From 2a8fcba3faf4b1c3a5f93b05be4940038eb015f9 Mon Sep 17 00:00:00 2001 From: Saliou Diallo Date: Wed, 5 Jun 2024 22:23:45 -0400 Subject: [PATCH 01/12] Update clients to use DN socials --- .../src/hooks/useTwitterButtonStatus.ts | 16 ++---- .../messages/sign-on/socialMediaMessages.ts | 4 +- packages/common/src/models/User.ts | 21 +++++--- packages/common/src/schemas/metadata.ts | 5 ++ .../services/audius-backend/AudiusBackend.ts | 52 ------------------- .../common/src/store/cache/users/actions.ts | 5 -- .../src/components/share-drawer/utils.ts | 32 ++++++++---- .../twitter-button/TwitterButton.tsx | 12 ++--- .../edit-profile-screen/EditProfileScreen.tsx | 20 ++++--- .../ProfileHeader/ProfileSocials.tsx | 17 +----- .../components/SocialMediaSignUpButtons.tsx | 7 +-- .../screens/PickHandleScreen.tsx | 5 +- .../utils/socialMediaMessages.ts | 4 +- .../src/common/store/cache/tracks/sagas.ts | 15 +++--- .../web/src/common/store/cache/users/sagas.ts | 38 +------------- .../web/src/common/store/profile/sagas.js | 6 +-- .../ai-attribution-modal/SearchBarResult.jsx | 8 --- .../components/TwitterShareButton.tsx | 16 ++---- .../notification/Notification/utils.ts | 8 --- .../web/src/components/share-modal/utils.ts | 29 +++++++---- .../TwitterShareButton.tsx | 16 ++---- .../profile-page/ProfilePageProvider.tsx | 12 ++--- .../components/desktop/ProfilePage.tsx | 6 +-- .../components/mobile/EditProfile.tsx | 6 +-- .../components/mobile/ProfilePage.tsx | 6 +-- .../sign-up-page/components/HandleField.tsx | 4 +- .../components/SignupFlowInstagramAuth.tsx | 3 +- .../components/SignupFlowTikTokAuth.tsx | 3 +- .../components/SignupFlowTwitterAuth.tsx | 3 +- .../components/SocialMediaLoginOptions.tsx | 3 +- .../hooks/useSocialMediaLoader.ts | 4 +- .../sign-up-page/pages/PickHandlePage.tsx | 10 ++-- 32 files changed, 133 insertions(+), 263 deletions(-) diff --git a/packages/common/src/hooks/useTwitterButtonStatus.ts b/packages/common/src/hooks/useTwitterButtonStatus.ts index e63f9d0c240..3896ff7de8b 100644 --- a/packages/common/src/hooks/useTwitterButtonStatus.ts +++ b/packages/common/src/hooks/useTwitterButtonStatus.ts @@ -14,24 +14,16 @@ export const useTwitterButtonStatus = ( useState('idle') const userName = user?.name - const twitterHandle = user ? user.twitter_handle : null + const twitterHandle = user?.twitter_handle const additionalUserName = additionalUser?.name - const additionalTwitterHandle = additionalUser - ? additionalUser.twitter_handle - : null - - // Initially twitter handle is undefined; after fetch it's - // set to either null or a value in `fetchUserSocials` sagas - const twitterHandleFetched = - twitterHandle !== undefined && - (additionalUser ? additionalTwitterHandle !== undefined : true) + const additionalTwitterHandle = additionalUser?.twitter_handle ?? null useEffect(() => { - if (shareTwitterStatus === 'loading' && twitterHandleFetched) { + if (shareTwitterStatus === 'loading') { setShareTwitterStatus('success') } - }, [setShareTwitterStatus, shareTwitterStatus, twitterHandleFetched]) + }, [setShareTwitterStatus, shareTwitterStatus]) const setLoading = useCallback(() => setShareTwitterStatus('loading'), []) const setIdle = useCallback(() => setShareTwitterStatus('idle'), []) diff --git a/packages/common/src/messages/sign-on/socialMediaMessages.ts b/packages/common/src/messages/sign-on/socialMediaMessages.ts index 10b2f2c45fd..51b0265990c 100644 --- a/packages/common/src/messages/sign-on/socialMediaMessages.ts +++ b/packages/common/src/messages/sign-on/socialMediaMessages.ts @@ -1,7 +1,9 @@ +import { SocialPlatform } from '~/models' + export const socialMediaMessages = { verificationError: 'Something went wrong. Please try again or verify with another account.', - socialMediaLoginSucess: (platform: 'twitter' | 'instagram' | 'tiktok') => { + socialMediaLoginSucess: (platform: SocialPlatform) => { const platformName = { twitter: 'Twitter', instagram: 'Instagram', diff --git a/packages/common/src/models/User.ts b/packages/common/src/models/User.ts index 672b02545c2..97d29b97bed 100644 --- a/packages/common/src/models/User.ts +++ b/packages/common/src/models/User.ts @@ -15,6 +15,8 @@ import { Grant } from './Grant' import { Timestamped } from './Timestamped' import { UserEvent } from './UserEvent' +export type SocialPlatform = 'twitter' | 'instagram' | 'tiktok' + export type UserMetadata = { album_count: number allow_ai_attribution?: boolean @@ -39,6 +41,14 @@ export type UserMetadata = { has_collectibles: boolean is_deactivated: boolean is_verified: boolean + twitter_handle: Nullable + instagram_handle: Nullable + tiktok_handle: Nullable + verified_with_twitter: boolean + verified_with_instagram: boolean + verified_with_tiktok: boolean + website: Nullable + donation: Nullable location: Nullable metadata_multihash: Nullable name: string @@ -57,15 +67,10 @@ export type UserMetadata = { // Only present on the "current" account track_save_count?: number user_id: number - twitter_handle?: string - instagram_handle?: string - tiktok_handle?: string - website?: string wallet?: string - donation?: string - twitterVerified?: boolean - instagramVerified?: boolean - tikTokVerified?: boolean + verifiedWithTwitter?: boolean + verifiedWithInstagram?: boolean + verifiedWithTiktok?: boolean balance?: Nullable total_balance?: Nullable associated_wallets?: Nullable diff --git a/packages/common/src/schemas/metadata.ts b/packages/common/src/schemas/metadata.ts index 4af49933997..ae509f6b1fc 100644 --- a/packages/common/src/schemas/metadata.ts +++ b/packages/common/src/schemas/metadata.ts @@ -134,6 +134,11 @@ const userMetadataSchema = { bio: null, location: null, is_verified: false, + twitter_handle: null, + instagram_handle: null, + tiktok_handle: null, + website: null, + donation: null, creator_node_endpoint: null, updated_at: null, associated_wallets: null, diff --git a/packages/common/src/services/audius-backend/AudiusBackend.ts b/packages/common/src/services/audius-backend/AudiusBackend.ts index d7a8b992294..94dac8bcf16 100644 --- a/packages/common/src/services/audius-backend/AudiusBackend.ts +++ b/packages/common/src/services/audius-backend/AudiusBackend.ts @@ -742,19 +742,6 @@ export const audiusBackend = ({ const account = audiusLibs.Account.getCurrentUser() if (!account) return null - try { - const body = await getSocialHandles(account.handle) - account.twitter_handle = body.twitterHandle || null - account.instagram_handle = body.instagramHandle || null - account.tiktok_handle = body.tikTokHandle || null - account.website = body.website || null - account.donation = body.donation || null - account.twitterVerified = body.twitterVerified || false - account.instagramVerified = body.instagramVerified || false - account.tikTokVerified = body.tikTokVerified || false - } catch (e) { - console.error(e) - } try { const userBank = await audiusLibs.solanaWeb3Manager.deriveUserBank() account.userBank = userBank.toString() @@ -966,19 +953,6 @@ export const audiusBackend = ({ } } - async function getSocialHandles(handle: string) { - try { - const res = await fetch( - `${identityServiceUrl}/social_handles?handle=${handle}` - ) - const json = await res.json() - return json - } catch (e) { - console.error(e) - return {} - } - } - /** * Retrieves the user's eth associated wallets from IPFS using the user's metadata CID and creator node endpoints * @param user The user metadata which contains the CID for the metadata multihash @@ -1055,31 +1029,6 @@ export const audiusBackend = ({ newMetadata.cover_photo_sizes = resp.id } - if ( - typeof newMetadata.twitter_handle === 'string' || - typeof newMetadata.instagram_handle === 'string' || - typeof newMetadata.tiktok_handle === 'string' || - typeof newMetadata.website === 'string' || - typeof newMetadata.donation === 'string' - ) { - const { data, signature } = await signData() - await fetch(`${identityServiceUrl}/social_handles`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - [AuthHeaders.Message]: data, - [AuthHeaders.Signature]: signature - }, - body: JSON.stringify({ - twitterHandle: newMetadata.twitter_handle, - instagramHandle: newMetadata.instagram_handle, - tikTokHandle: newMetadata.tiktok_handle, - website: newMetadata.website, - donation: newMetadata.donation - }) - }) - } - newMetadata = schemas.newUserMetadata(newMetadata, true) const userId = newMetadata.user_id const { blockHash, blockNumber } = await audiusLibs.User.updateMetadataV2( @@ -3029,7 +2978,6 @@ export const audiusBackend = ({ getBrowserPushSubscription, getCollectionImages, getCreators, - getSocialHandles, getEmailNotificationSettings, getFolloweeFollows, getImageUrl, diff --git a/packages/common/src/store/cache/users/actions.ts b/packages/common/src/store/cache/users/actions.ts index 669ffab579a..dcad6623f21 100644 --- a/packages/common/src/store/cache/users/actions.ts +++ b/packages/common/src/store/cache/users/actions.ts @@ -4,7 +4,6 @@ export const REMOVE_BY_HANDLE = 'CACHE/USERS/REMOVE_BY_HANDLE' export const FETCH_PROFILE_PICTURE = 'CACHE/USERS/FETCH_PROFILE_PICTURE' export const FETCH_COVER_PHOTO = 'CACHE/USERS/FETCH_COVER_PHOTO' -export const FETCH_USER_SOCIALS = 'CACHE/USERS/FETCH_USER_SOCIALS' export const FETCH_USERS = 'CACHE/USERS/FETCH' export const removeByHandle = (handle: string) => ({ @@ -23,10 +22,6 @@ export function fetchCoverPhoto(userId: ID, size: WidthSizes | SquareSizes) { return { type: FETCH_COVER_PHOTO, userId, size } } -export function fetchUserSocials(handle: string) { - return { type: FETCH_USER_SOCIALS, handle } -} - export function fetchUsers({ userIds, requiredFields, diff --git a/packages/mobile/src/components/share-drawer/utils.ts b/packages/mobile/src/components/share-drawer/utils.ts index 7c7f6fef34e..bf1ca37fd71 100644 --- a/packages/mobile/src/components/share-drawer/utils.ts +++ b/packages/mobile/src/components/share-drawer/utils.ts @@ -1,7 +1,7 @@ import type { ShareContent } from '@audius/common/store' +import type { Nullable } from '@audius/common/utils' import { makeTwitterShareUrl } from '@audius/common/utils' -import { audiusBackendInstance } from 'app/services/audius-backend-instance' import { getCollectionRoute, getTrackRoute, @@ -35,8 +35,13 @@ export const getContentUrl = (content: ShareContent) => { } } -const getShareHandle = async (handle: string) => { - const { twitterHandle } = await audiusBackendInstance.getSocialHandles(handle) +const getTwitterShareHandle = ({ + handle, + twitterHandle +}: { + handle: string + twitterHandle: Nullable +}) => { return twitterHandle ? `@${twitterHandle}` : handle } @@ -45,34 +50,39 @@ export const getTwitterShareText = async (content: ShareContent) => { case 'track': { const { track: { title }, - artist: { handle } + artist: { handle, twitter_handle: twitterHandle } } = content - return messages.trackShareText(title, await getShareHandle(handle)) + return messages.trackShareText( + title, + getTwitterShareHandle({ handle, twitterHandle }) + ) } case 'profile': { const { - profile: { handle } + profile: { handle, twitter_handle: twitterHandle } } = content - return messages.profileShareText(await getShareHandle(handle)) + return messages.profileShareText( + getTwitterShareHandle({ handle, twitterHandle }) + ) } case 'album': { const { album: { playlist_name }, - artist: { handle } + artist: { handle, twitter_handle: twitterHandle } } = content return messages.albumShareText( playlist_name, - await getShareHandle(handle) + getTwitterShareHandle({ handle, twitterHandle }) ) } case 'playlist': { const { playlist: { playlist_name }, - creator: { handle } + creator: { handle, twitter_handle: twitterHandle } } = content return messages.playlistShareText( playlist_name, - await getShareHandle(handle) + getTwitterShareHandle({ handle, twitterHandle }) ) } case 'audioNftPlaylist': { diff --git a/packages/mobile/src/components/twitter-button/TwitterButton.tsx b/packages/mobile/src/components/twitter-button/TwitterButton.tsx index 449092931c3..086cd8fc2f6 100644 --- a/packages/mobile/src/components/twitter-button/TwitterButton.tsx +++ b/packages/mobile/src/components/twitter-button/TwitterButton.tsx @@ -1,10 +1,10 @@ import { useCallback } from 'react' import { useTwitterButtonStatus } from '@audius/common/hooks' -import { cacheUsersActions, cacheUsersSelectors } from '@audius/common/store' +import { cacheUsersSelectors } from '@audius/common/store' import { makeTwitterShareUrl } from '@audius/common/utils' import type { Nullable } from '@audius/common/utils' -import { useDispatch, useSelector } from 'react-redux' +import { useSelector } from 'react-redux' import { IconTwitter } from '@audius/harmony-native' import type { ButtonProps } from 'app/components/core' @@ -14,7 +14,6 @@ import { makeStyles } from 'app/styles' import { spacing } from 'app/styles/spacing' import type { AllEvents } from 'app/types/analytics' const { getUser } = cacheUsersSelectors -const { fetchUserSocials } = cacheUsersActions const messages = { share: 'Share to Twitter' @@ -53,7 +52,6 @@ export const TwitterButton = (props: TwitterButtonProps) => { const { size } = other const styles = useStyles() const openLink = useOnOpenLink() - const dispatch = useDispatch() const user = useSelector((state) => getUser(state, { handle: 'handle' in other ? other.handle : undefined }) @@ -80,13 +78,9 @@ export const TwitterButton = (props: TwitterButtonProps) => { track(make(other.analytics)) } if (other.type === 'dynamic') { - dispatch(fetchUserSocials(other.handle)) - if (other.additionalHandle) { - dispatch(fetchUserSocials(other.additionalHandle)) - } setLoading() } - }, [other, dispatch, setLoading]) + }, [other, setLoading]) if (other.type === 'dynamic' && shareTwitterStatus === 'success') { const handle = twitterHandle ? `@${twitterHandle}` : userName diff --git a/packages/mobile/src/screens/edit-profile-screen/EditProfileScreen.tsx b/packages/mobile/src/screens/edit-profile-screen/EditProfileScreen.tsx index 2f518e63e66..1ae202846ed 100644 --- a/packages/mobile/src/screens/edit-profile-screen/EditProfileScreen.tsx +++ b/packages/mobile/src/screens/edit-profile-screen/EditProfileScreen.tsx @@ -64,9 +64,9 @@ const useStyles = makeStyles(({ palette, spacing }) => ({ })) type EditProfileFormProps = FormikProps & { - isTwitterVerified?: boolean - isInstagramVerified?: boolean - isTikTokVerified?: boolean + isTwitterVerified: boolean + isInstagramVerified: boolean + isTikTokVerified: boolean } const EditProfileForm = (props: EditProfileFormProps) => { @@ -134,8 +134,12 @@ const EditProfileForm = (props: EditProfileFormProps) => { export const EditProfileScreen = () => { const profile = useSelector(getAccountUser)! - const { user_id, twitterVerified, instagramVerified, tikTokVerified } = - profile + const { + user_id, + verified_with_twitter: verifiedWithTwitter, + verified_with_instagram: verifiedWithInstagram, + verified_with_tiktok: verifiedWithTiktok + } = profile const dispatch = useDispatch() @@ -208,9 +212,9 @@ export const EditProfileScreen = () => { return ( ) }} diff --git a/packages/mobile/src/screens/profile-screen/ProfileHeader/ProfileSocials.tsx b/packages/mobile/src/screens/profile-screen/ProfileHeader/ProfileSocials.tsx index c7b2000def4..bd2101224fa 100644 --- a/packages/mobile/src/screens/profile-screen/ProfileHeader/ProfileSocials.tsx +++ b/packages/mobile/src/screens/profile-screen/ProfileHeader/ProfileSocials.tsx @@ -1,9 +1,7 @@ -import { Fragment, useEffect, useLayoutEffect, useMemo, useRef } from 'react' +import { Fragment, useLayoutEffect, useMemo, useRef } from 'react' import { useSelectTierInfo } from '@audius/common/hooks' -import { cacheUsersActions } from '@audius/common/store' import { View, Animated } from 'react-native' -import { useDispatch } from 'react-redux' import { Divider } from 'app/components/core' import { makeStyles } from 'app/styles' @@ -18,8 +16,6 @@ import { TwitterSocialLink } from './SocialLink' -const { fetchUserSocials } = cacheUsersActions - const useStyles = makeStyles(({ spacing }) => ({ root: { flexDirection: 'row', @@ -43,23 +39,14 @@ const useStyles = makeStyles(({ spacing }) => ({ })) export const ProfileSocials = () => { - const { handle, user_id, twitter_handle, instagram_handle, tiktok_handle } = + const { user_id, twitter_handle, instagram_handle, tiktok_handle } = useSelectProfile([ - 'handle', 'user_id', 'twitter_handle', 'instagram_handle', 'tiktok_handle' ]) - const dispatch = useDispatch() - - useEffect(() => { - if (twitter_handle === undefined) { - dispatch(fetchUserSocials(handle)) - } - }, [twitter_handle, dispatch, handle]) - const socialLinks = useMemo(() => { const links = [ { diff --git a/packages/mobile/src/screens/sign-on-screen/components/SocialMediaSignUpButtons.tsx b/packages/mobile/src/screens/sign-on-screen/components/SocialMediaSignUpButtons.tsx index af0af41580b..788f77c688f 100644 --- a/packages/mobile/src/screens/sign-on-screen/components/SocialMediaSignUpButtons.tsx +++ b/packages/mobile/src/screens/sign-on-screen/components/SocialMediaSignUpButtons.tsx @@ -1,5 +1,6 @@ import { useRemoteVar } from '@audius/common/hooks' import { socialMediaMessages } from '@audius/common/messages' +import type { SocialPlatform } from '@audius/common/models' import { ErrorLevel } from '@audius/common/models' import { BooleanKeys } from '@audius/common/services' @@ -15,7 +16,7 @@ type SocialMediaLoginOptionsProps = { onCompleteSocialMediaLogin: (info: { requiresReview: boolean handle: string - platform: 'twitter' | 'instagram' | 'tiktok' + platform: SocialPlatform }) => void onError: (e: unknown) => void onStart: () => void @@ -33,7 +34,7 @@ export const SocialMediaSignUpButtons = ({ }: SocialMediaLoginOptionsProps) => { const { toast } = useToast() const handleFailure = - (platform: 'twitter' | 'instagram' | 'tiktok') => + (platform: SocialPlatform) => (e: unknown, additionalInfo?: Record) => { onError(e) reportToSentry({ @@ -52,7 +53,7 @@ export const SocialMediaSignUpButtons = ({ }: { requiresReview: boolean handle: string - platform: 'twitter' | 'instagram' | 'tiktok' + platform: SocialPlatform }) => { toast({ content: socialMediaMessages.socialMediaLoginSucess(platform), diff --git a/packages/mobile/src/screens/sign-on-screen/screens/PickHandleScreen.tsx b/packages/mobile/src/screens/sign-on-screen/screens/PickHandleScreen.tsx index ffa0048046c..185e1e719fe 100644 --- a/packages/mobile/src/screens/sign-on-screen/screens/PickHandleScreen.tsx +++ b/packages/mobile/src/screens/sign-on-screen/screens/PickHandleScreen.tsx @@ -2,6 +2,7 @@ import { useCallback, useMemo } from 'react' import { useAudiusQueryContext } from '@audius/common/audius-query' import { pickHandlePageMessages } from '@audius/common/messages' +import type { SocialPlatform } from '@audius/common/models' import { pickHandleSchema } from '@audius/common/schemas' import { getIsSocialConnected } from '@audius/web/src/common/store/pages/signon/selectors' import { @@ -44,7 +45,7 @@ type SocialMediaSectionProps = { onCompleteSocialMediaLogin: (info: { requiresReview: boolean handle: string - platform: 'twitter' | 'instagram' | 'tiktok' + platform: SocialPlatform }) => void onStart: () => void onError: () => void @@ -131,7 +132,7 @@ export const PickHandleScreen = () => { }: { requiresReview: boolean handle: string - platform: 'twitter' | 'instagram' | 'tiktok' + platform: SocialPlatform }) => { handleCompleteSocialMediaLogin() dispatch(setValueField('handle', handle)) diff --git a/packages/mobile/src/screens/sign-on-screen/utils/socialMediaMessages.ts b/packages/mobile/src/screens/sign-on-screen/utils/socialMediaMessages.ts index 10b2f2c45fd..0665981c03f 100644 --- a/packages/mobile/src/screens/sign-on-screen/utils/socialMediaMessages.ts +++ b/packages/mobile/src/screens/sign-on-screen/utils/socialMediaMessages.ts @@ -1,7 +1,9 @@ +import type { SocialPlatform } from '@audius/common/models' + export const socialMediaMessages = { verificationError: 'Something went wrong. Please try again or verify with another account.', - socialMediaLoginSucess: (platform: 'twitter' | 'instagram' | 'tiktok') => { + socialMediaLoginSucess: (platform: SocialPlatform) => { const platformName = { twitter: 'Twitter', instagram: 'Instagram', diff --git a/packages/web/src/common/store/cache/tracks/sagas.ts b/packages/web/src/common/store/cache/tracks/sagas.ts index 9f1483e496d..e48bb8a9988 100644 --- a/packages/web/src/common/store/cache/tracks/sagas.ts +++ b/packages/web/src/common/store/cache/tracks/sagas.ts @@ -245,18 +245,19 @@ function* watchEditTrack() { function* deleteTrackAsync( action: ReturnType ) { - const audiusBackendInstance = yield* getContext('audiusBackendInstance') yield* waitForWrite() - const userId = yield* select(getUserId) - if (!userId) { + const user = yield* select(getAccountUser) + if (!user) { yield* put(signOnActions.openSignOn(false)) return } - const handle = yield* select(getUserHandle) + const userId = user.user_id + + const track = yield* select(getTrack, { id: action.trackId }) + if (!track) return // Before deleting, check if the track is set as the artist pick & delete if so - const socials = yield* call(audiusBackendInstance.getSocialHandles, handle!) - if (socials.pinnedTrackId === action.trackId) { + if (user.artist_pick_track_id === action.trackId) { yield* put( cacheActions.update(Kind.USERS, [ { @@ -271,8 +272,6 @@ function* deleteTrackAsync( yield* fork(updateProfileAsync, { metadata: user }) } - const track = yield* select(getTrack, { id: action.trackId }) - if (!track) return yield* put( cacheActions.update(Kind.TRACKS, [ { id: track.track_id, metadata: { _marked_deleted: true } } diff --git a/packages/web/src/common/store/cache/users/sagas.ts b/packages/web/src/common/store/cache/users/sagas.ts index 3e0c4f26ced..3a380865b9b 100644 --- a/packages/web/src/common/store/cache/users/sagas.ts +++ b/packages/web/src/common/store/cache/users/sagas.ts @@ -17,7 +17,7 @@ import { reformatUser, getSDK } from '@audius/common/store' -import { waitForAccount, waitForValue } from '@audius/common/utils' +import { waitForAccount } from '@audius/common/utils' import { mergeWith } from 'lodash' import { call, put, select, takeEvery } from 'typed-redux-saga' @@ -352,41 +352,6 @@ function* watchFetchCoverPhoto() { ) } -export function* fetchUserSocials({ - handle -}: ReturnType) { - const audiusBackendInstance = yield* getContext('audiusBackendInstance') - let user = yield* select(getUser, { handle }) - if (!user) { - yield* call(fetchUserByHandle, handle, new Set()) - } - user = yield* call(waitForValue, getUser, { handle }) - if (!user) return - const socials = yield* call( - audiusBackendInstance.getSocialHandles, - user.handle - ) - - yield* put( - cacheActions.update(Kind.USERS, [ - { - id: user.user_id, - metadata: { - twitter_handle: socials.twitterHandle || null, - instagram_handle: socials.instagramHandle || null, - tiktok_handle: socials.tikTokHandle || null, - website: socials.website || null, - donation: socials.donation || null - } - } - ]) - ) -} - -function* watchFetchUserSocials() { - yield* takeEvery(userActions.FETCH_USER_SOCIALS, fetchUserSocials) -} - function* watchFetchUsers() { yield* takeEvery( userActions.FETCH_USERS, @@ -403,7 +368,6 @@ const sagas = () => { watchFetchProfilePicture, watchFetchCoverPhoto, watchSyncLocalStorageUser, - watchFetchUserSocials, watchFetchUsers ] } diff --git a/packages/web/src/common/store/profile/sagas.js b/packages/web/src/common/store/profile/sagas.js index b9599d75e30..733054dd91e 100644 --- a/packages/web/src/common/store/profile/sagas.js +++ b/packages/web/src/common/store/profile/sagas.js @@ -40,8 +40,7 @@ import { import { fetchUsers, fetchUserByHandle, - fetchUserCollections, - fetchUserSocials + fetchUserCollections } from 'common/store/cache/users/sagas' import feedSagas from 'common/store/pages/profile/lineups/feed/sagas.js' import tracksSagas from 'common/store/pages/profile/lineups/tracks/sagas.js' @@ -366,8 +365,7 @@ function* fetchProfileAsync(action) { ) if (!isNativeMobile) { - // Fetch user socials and collections after fetching the user itself - yield fork(fetchUserSocials, action) + // Fetch user collections after fetching the user itself yield fork(fetchUserCollections, user.user_id) yield fork(fetchSupportersAndSupporting, user.user_id) } diff --git a/packages/web/src/components/ai-attribution-modal/SearchBarResult.jsx b/packages/web/src/components/ai-attribution-modal/SearchBarResult.jsx index 5bc3e62b252..6813e446ad1 100644 --- a/packages/web/src/components/ai-attribution-modal/SearchBarResult.jsx +++ b/packages/web/src/components/ai-attribution-modal/SearchBarResult.jsx @@ -2,11 +2,9 @@ import { useState, useEffect, memo, useCallback } from 'react' import { imageBlank as placeholderArt } from '@audius/common/assets' import { Kind } from '@audius/common/models' -import { cacheUsersActions } from '@audius/common/store' import { Tag } from '@audius/harmony' import cn from 'classnames' import PropTypes from 'prop-types' -import { useDispatch } from 'react-redux' import DynamicImage from 'components/dynamic-image/DynamicImage' import { TwitterShareButton } from 'components/notification/Notification/components/TwitterShareButton' @@ -75,12 +73,6 @@ const SearchBarResult = memo((props) => { handle } = props const isUser = kind === Kind.USERS - const { fetchUserSocials } = cacheUsersActions - const dispatch = useDispatch() - - useEffect(() => { - dispatch(fetchUserSocials(handle)) - }, [dispatch, fetchUserSocials, handle]) const handleTwitterShare = useCallback((handle) => { const shareText = messages.tweet(handle) diff --git a/packages/web/src/components/notification/Notification/components/TwitterShareButton.tsx b/packages/web/src/components/notification/Notification/components/TwitterShareButton.tsx index 837b379d6fe..9d575472bda 100644 --- a/packages/web/src/components/notification/Notification/components/TwitterShareButton.tsx +++ b/packages/web/src/components/notification/Notification/components/TwitterShareButton.tsx @@ -1,21 +1,16 @@ import { MouseEventHandler, useCallback } from 'react' import { useTwitterButtonStatus } from '@audius/common/hooks' -import { - cacheUsersActions, - cacheUsersSelectors, - CommonState -} from '@audius/common/store' +import { cacheUsersSelectors, CommonState } from '@audius/common/store' import { Nullable } from '@audius/common/utils' import { IconTwitter as IconTwitterBird } from '@audius/harmony' import cn from 'classnames' -import { useDispatch, useSelector } from 'react-redux' +import { useSelector } from 'react-redux' import { useRecord, TrackEvent } from 'common/store/analytics/actions' import { openTwitterLink } from 'utils/tweet' import styles from './TwitterShareButton.module.css' -const { fetchUserSocials } = cacheUsersActions const { getUser } = cacheUsersSelectors const messages = { @@ -50,7 +45,6 @@ type TwitterShareButtonProps = { export const TwitterShareButton = (props: TwitterShareButtonProps) => { const { url = null, className, hideText, ...other } = props const record = useRecord() - const dispatch = useDispatch() const user = useSelector((state: CommonState) => getUser(state, { handle: 'handle' in other ? other.handle : undefined }) @@ -82,14 +76,10 @@ export const TwitterShareButton = (props: TwitterShareButtonProps) => { } } if (other.type === 'dynamic') { - dispatch(fetchUserSocials(other.handle)) - if (other.additionalHandle) { - dispatch(fetchUserSocials(other.additionalHandle)) - } setLoading() } }, - [url, other, dispatch, record, setLoading] + [url, other, record, setLoading] ) if ( diff --git a/packages/web/src/components/notification/Notification/utils.ts b/packages/web/src/components/notification/Notification/utils.ts index 5cfad5c31e4..3e10a962e87 100644 --- a/packages/web/src/components/notification/Notification/utils.ts +++ b/packages/web/src/components/notification/Notification/utils.ts @@ -1,6 +1,5 @@ import { Entity, EntityType } from '@audius/common/store' -import { audiusBackendInstance } from 'services/audius-backend/audius-backend-instance' import { UserListEntityType } from 'store/application/ui/userListModal/types' import { fullCollectionPage, fullTrackPage, collectionPage } from 'utils/route' @@ -28,13 +27,6 @@ export const getRankSuffix = (rank: number) => { return 'th' } -export const getTwitterHandleByUserHandle = async (userHandle: string) => { - const { twitterHandle } = await audiusBackendInstance.getSocialHandles( - userHandle - ) - return twitterHandle || '' -} - export const USER_LENGTH_LIMIT = 9 export const entityToUserListEntity = { diff --git a/packages/web/src/components/share-modal/utils.ts b/packages/web/src/components/share-modal/utils.ts index 1f5af852a6f..275f2ae3d5b 100644 --- a/packages/web/src/components/share-modal/utils.ts +++ b/packages/web/src/components/share-modal/utils.ts @@ -1,7 +1,7 @@ import { ShareToTwitter } from '@audius/common/models' import { ShareContent } from '@audius/common/store' +import { Nullable } from '@audius/common/utils' -import { getTwitterHandleByUserHandle } from 'components/notification/Notification/utils' import { fullCollectionPage, fullProfilePage, @@ -13,8 +13,13 @@ import { messages } from './messages' type ShareToTwitterEvent = Omit -const getShareHandle = async (handle: string) => { - const twitterHandle = await getTwitterHandleByUserHandle(handle) +const getTwitterShareHandle = ({ + handle, + twitterHandle +}: { + handle: string + twitterHandle: Nullable +}) => { return twitterHandle ? `@${twitterHandle}` : handle } @@ -39,11 +44,11 @@ export const getTwitterShareText = async ( case 'track': { const { track: { title, permalink, track_id }, - artist: { handle } + artist: { handle, twitter_handle: twitterHandle } } = content twitterText = messageConfig.trackShareText( title, - await getShareHandle(handle) + getTwitterShareHandle({ handle, twitterHandle }) ) link = fullTrackPage(permalink) analyticsEvent = { kind: 'track', id: track_id, url: link } @@ -51,9 +56,11 @@ export const getTwitterShareText = async ( } case 'profile': { const { - profile: { handle, user_id } + profile: { handle, user_id, twitter_handle: twitterHandle } } = content - twitterText = messageConfig.profileShareText(await getShareHandle(handle)) + twitterText = messageConfig.profileShareText( + getTwitterShareHandle({ handle, twitterHandle }) + ) link = fullProfilePage(handle) analyticsEvent = { kind: 'profile', id: user_id, url: link } break @@ -61,11 +68,11 @@ export const getTwitterShareText = async ( case 'album': { const { album: { playlist_name, playlist_id, permalink }, - artist: { handle } + artist: { handle, twitter_handle: twitterHandle } } = content twitterText = messageConfig.albumShareText( playlist_name, - await getShareHandle(handle) + getTwitterShareHandle({ handle, twitterHandle }) ) link = fullCollectionPage( handle, @@ -80,11 +87,11 @@ export const getTwitterShareText = async ( case 'playlist': { const { playlist: { playlist_name, playlist_id, permalink, is_album }, - creator: { handle } + creator: { handle, twitter_handle: twitterHandle } } = content twitterText = messageConfig.playlistShareText( playlist_name, - await getShareHandle(handle) + getTwitterShareHandle({ handle, twitterHandle }) ) link = fullCollectionPage( handle, diff --git a/packages/web/src/components/twitter-share-button/TwitterShareButton.tsx b/packages/web/src/components/twitter-share-button/TwitterShareButton.tsx index 411f31ef422..85c011a0192 100644 --- a/packages/web/src/components/twitter-share-button/TwitterShareButton.tsx +++ b/packages/web/src/components/twitter-share-button/TwitterShareButton.tsx @@ -1,23 +1,18 @@ import { MouseEventHandler, useCallback } from 'react' import { useTwitterButtonStatus } from '@audius/common/hooks' -import { - cacheUsersActions, - cacheUsersSelectors, - CommonState -} from '@audius/common/store' +import { cacheUsersSelectors, CommonState } from '@audius/common/store' import { Nullable } from '@audius/common/utils' import { Button, ButtonProps, IconTwitter as IconTwitterBird } from '@audius/harmony' -import { useDispatch, useSelector } from 'react-redux' +import { useSelector } from 'react-redux' import { useRecord, TrackEvent } from 'common/store/analytics/actions' import { openTwitterLink } from 'utils/tweet' -const { fetchUserSocials } = cacheUsersActions const { getUser } = cacheUsersSelectors const messages = { @@ -51,7 +46,6 @@ type TwitterShareButtonProps = { export const TwitterShareButton = (props: TwitterShareButtonProps) => { const { url = null, fullWidth, size, hideText, ...other } = props const record = useRecord() - const dispatch = useDispatch() const user = useSelector((state: CommonState) => getUser(state, { handle: 'handle' in other ? other.handle : undefined }) @@ -83,14 +77,10 @@ export const TwitterShareButton = (props: TwitterShareButtonProps) => { } } if (other.type === 'dynamic') { - dispatch(fetchUserSocials(other.handle)) - if (other.additionalHandle) { - dispatch(fetchUserSocials(other.additionalHandle)) - } setLoading() } }, - [url, other, dispatch, record, setLoading] + [url, other, record, setLoading] ) if ( diff --git a/packages/web/src/pages/profile-page/ProfilePageProvider.tsx b/packages/web/src/pages/profile-page/ProfilePageProvider.tsx index 1a38c65530f..d6736161800 100644 --- a/packages/web/src/pages/profile-page/ProfilePageProvider.tsx +++ b/packages/web/src/pages/profile-page/ProfilePageProvider.tsx @@ -791,9 +791,9 @@ class ProfilePage extends PureComponent { const userId = profile ? profile.user_id : null const handle = profile ? `@${profile.handle}` : '' const verified = profile ? profile.is_verified : false - const twitterVerified = profile ? profile.twitterVerified : false - const instagramVerified = profile ? profile.instagramVerified : false - const tikTokVerified = profile ? profile.tikTokVerified : false + const twitterVerified = !!profile?.verified_with_twitter + const instagramVerified = !!profile?.verified_with_instagram + const tikTokVerified = !!profile?.verified_with_tiktok const created = profile ? moment(profile.created_at).format('YYYY') : moment().format('YYYY') @@ -812,21 +812,21 @@ class ProfilePage extends PureComponent { const twitterHandle = profile ? updatedTwitterHandle !== null ? updatedTwitterHandle - : profile.twitterVerified && !verifiedHandleWhitelist.has(handle) + : twitterVerified && !verifiedHandleWhitelist.has(handle) ? profile.handle : profile.twitter_handle || '' : '' const instagramHandle = profile ? updatedInstagramHandle !== null ? updatedInstagramHandle - : profile.instagramVerified + : instagramVerified ? profile.handle : profile.instagram_handle || '' : '' const tikTokHandle = profile ? updatedTikTokHandle !== null ? updatedTikTokHandle - : profile.tikTokVerified + : tikTokVerified ? profile.handle : profile.tiktok_handle || '' : '' diff --git a/packages/web/src/pages/profile-page/components/desktop/ProfilePage.tsx b/packages/web/src/pages/profile-page/components/desktop/ProfilePage.tsx index 2cd1d705c3d..3a762734c55 100644 --- a/packages/web/src/pages/profile-page/components/desktop/ProfilePage.tsx +++ b/packages/web/src/pages/profile-page/components/desktop/ProfilePage.tsx @@ -71,9 +71,9 @@ export type ProfilePageProps = { twitterHandle: string instagramHandle: string tikTokHandle: string - twitterVerified?: boolean - instagramVerified?: boolean - tikTokVerified?: boolean + twitterVerified: boolean + instagramVerified: boolean + tikTokVerified: boolean website: string donation: string coverPhotoSizes: CoverPhotoSizes | null diff --git a/packages/web/src/pages/profile-page/components/mobile/EditProfile.tsx b/packages/web/src/pages/profile-page/components/mobile/EditProfile.tsx index 9353e6247b5..84970d33120 100644 --- a/packages/web/src/pages/profile-page/components/mobile/EditProfile.tsx +++ b/packages/web/src/pages/profile-page/components/mobile/EditProfile.tsx @@ -19,9 +19,9 @@ type EditProfileProps = { twitterHandle: string instagramHandle: string tikTokHandle: string - twitterVerified?: boolean - instagramVerified?: boolean - tikTokVerified?: boolean + twitterVerified: boolean + instagramVerified: boolean + tikTokVerified: boolean website: string donation: string diff --git a/packages/web/src/pages/profile-page/components/mobile/ProfilePage.tsx b/packages/web/src/pages/profile-page/components/mobile/ProfilePage.tsx index 9952d9d03d2..70f13990dde 100644 --- a/packages/web/src/pages/profile-page/components/mobile/ProfilePage.tsx +++ b/packages/web/src/pages/profile-page/components/mobile/ProfilePage.tsx @@ -65,9 +65,9 @@ export type ProfilePageProps = { twitterHandle: string instagramHandle: string tikTokHandle: string - twitterVerified?: boolean - instagramVerified?: boolean - tikTokVerified?: boolean + twitterVerified: boolean + instagramVerified: boolean + tikTokVerified: boolean website: string donation: string coverPhotoSizes: CoverPhotoSizes | null diff --git a/packages/web/src/pages/sign-up-page/components/HandleField.tsx b/packages/web/src/pages/sign-up-page/components/HandleField.tsx index 3dc2d540f7e..1ba33ec1200 100644 --- a/packages/web/src/pages/sign-up-page/components/HandleField.tsx +++ b/packages/web/src/pages/sign-up-page/components/HandleField.tsx @@ -5,6 +5,7 @@ import { socialMediaMessages, pickHandlePageMessages as messages } from '@audius/common/messages' +import { SocialPlatform } from '@audius/common/models' import { pickHandleErrorMessages } from '@audius/common/schemas' import { MAX_HANDLE_LENGTH } from '@audius/common/services' import { TextLink, IconCheck } from '@audius/harmony' @@ -19,7 +20,6 @@ import { ToastContext } from 'components/toast/ToastContext' import { SignupFlowInstagramAuth } from './SignupFlowInstagramAuth' import { SignupFlowTikTokAuth } from './SignupFlowTikTokAuth' import { SignupFlowTwitterAuth } from './SignupFlowTwitterAuth' -import { SocialPlatform } from './SocialMediaLoginOptions' const handleAuthMap = { [pickHandleErrorMessages.twitterReservedError]: SignupFlowTwitterAuth, @@ -31,7 +31,7 @@ type HandleFieldProps = Partial & { onCompleteSocialMediaLogin?: (info: { requiresReview: boolean handle: string - platform: 'twitter' | 'instagram' | 'tiktok' + platform: SocialPlatform }) => void onStartSocialMediaLogin?: (platform: SocialPlatform) => void onErrorSocialMediaLogin?: (error: Error, platform: SocialPlatform) => void diff --git a/packages/web/src/pages/sign-up-page/components/SignupFlowInstagramAuth.tsx b/packages/web/src/pages/sign-up-page/components/SignupFlowInstagramAuth.tsx index f02438c852d..6e8309fa35f 100644 --- a/packages/web/src/pages/sign-up-page/components/SignupFlowInstagramAuth.tsx +++ b/packages/web/src/pages/sign-up-page/components/SignupFlowInstagramAuth.tsx @@ -1,13 +1,12 @@ import { PropsWithChildren } from 'react' +import { SocialPlatform } from '@audius/common/models' import { InstagramProfile } from '@audius/common/store' import InstagramAuth from 'components/instagram-auth/InstagramAuth' import { useSetProfileFromInstagram } from '../hooks/socialMediaLogin' -import { SocialPlatform } from './SocialMediaLoginOptions' - type SignupFlowInstagramAuthProps = PropsWithChildren<{ className?: string onFailure: (e: Error, platform: SocialPlatform) => void diff --git a/packages/web/src/pages/sign-up-page/components/SignupFlowTikTokAuth.tsx b/packages/web/src/pages/sign-up-page/components/SignupFlowTikTokAuth.tsx index 83d48f98ef0..76a09e4fedb 100644 --- a/packages/web/src/pages/sign-up-page/components/SignupFlowTikTokAuth.tsx +++ b/packages/web/src/pages/sign-up-page/components/SignupFlowTikTokAuth.tsx @@ -1,13 +1,12 @@ import { ReactElement } from 'react' +import { SocialPlatform } from '@audius/common/models' import { TikTokProfile } from '@audius/common/store' import { TikTokAuth } from 'components/tiktok-auth/TikTokAuthButton' import { useSetProfileFromTikTok } from '../hooks/socialMediaLogin' -import { SocialPlatform } from './SocialMediaLoginOptions' - type SignupFlowTikTokAuthProps = { onStart: (platform: SocialPlatform) => void onFailure: (e: Error, platform: SocialPlatform) => void diff --git a/packages/web/src/pages/sign-up-page/components/SignupFlowTwitterAuth.tsx b/packages/web/src/pages/sign-up-page/components/SignupFlowTwitterAuth.tsx index cd60179f816..81143ee2d31 100644 --- a/packages/web/src/pages/sign-up-page/components/SignupFlowTwitterAuth.tsx +++ b/packages/web/src/pages/sign-up-page/components/SignupFlowTwitterAuth.tsx @@ -1,13 +1,12 @@ import { PropsWithChildren } from 'react' +import { SocialPlatform } from '@audius/common/models' import { TwitterProfile } from '@audius/common/store' import TwitterAuth from 'components/twitter-auth/TwitterAuth' import { useSetProfileFromTwitter } from '../hooks/socialMediaLogin' -import { SocialPlatform } from './SocialMediaLoginOptions' - type SignupFlowTwitterAuthProps = PropsWithChildren<{ className?: string onFailure: (e: Error, platform: SocialPlatform) => void diff --git a/packages/web/src/pages/sign-up-page/components/SocialMediaLoginOptions.tsx b/packages/web/src/pages/sign-up-page/components/SocialMediaLoginOptions.tsx index 15c9f82427a..7b447222662 100644 --- a/packages/web/src/pages/sign-up-page/components/SocialMediaLoginOptions.tsx +++ b/packages/web/src/pages/sign-up-page/components/SocialMediaLoginOptions.tsx @@ -1,6 +1,7 @@ import { useContext } from 'react' import { socialMediaMessages } from '@audius/common/messages' +import { SocialPlatform } from '@audius/common/models' import { BooleanKeys } from '@audius/common/services' import { Box, Flex, SocialButton } from '@audius/harmony' @@ -11,8 +12,6 @@ import { SignupFlowInstagramAuth } from './SignupFlowInstagramAuth' import { SignupFlowTikTokAuth } from './SignupFlowTikTokAuth' import { SignupFlowTwitterAuth } from './SignupFlowTwitterAuth' -export type SocialPlatform = 'twitter' | 'instagram' | 'tiktok' - type SocialMediaLoginOptionsProps = { onCompleteSocialMediaLogin: (info: { requiresReview: boolean diff --git a/packages/web/src/pages/sign-up-page/hooks/useSocialMediaLoader.ts b/packages/web/src/pages/sign-up-page/hooks/useSocialMediaLoader.ts index 63b5f425316..811fa293531 100644 --- a/packages/web/src/pages/sign-up-page/hooks/useSocialMediaLoader.ts +++ b/packages/web/src/pages/sign-up-page/hooks/useSocialMediaLoader.ts @@ -1,13 +1,11 @@ import { useCallback, useEffect, useState } from 'react' -import { Name } from '@audius/common/models' +import { Name, SocialPlatform } from '@audius/common/models' import { useDispatch } from 'react-redux' import { AnyAction } from 'redux' import { make } from 'common/store/analytics/actions' -import { SocialPlatform } from '../components/SocialMediaLoginOptions' - export const useSocialMediaLoader = ({ linkedSocialOnThisPagePreviously, resetAction, diff --git a/packages/web/src/pages/sign-up-page/pages/PickHandlePage.tsx b/packages/web/src/pages/sign-up-page/pages/PickHandlePage.tsx index 381116e3dfc..bc692d9b33c 100644 --- a/packages/web/src/pages/sign-up-page/pages/PickHandlePage.tsx +++ b/packages/web/src/pages/sign-up-page/pages/PickHandlePage.tsx @@ -5,6 +5,7 @@ import { pickHandlePageMessages, socialMediaMessages } from '@audius/common/messages' +import { SocialPlatform } from '@audius/common/models' import { pickHandleSchema } from '@audius/common/schemas' import { Divider, Flex, IconVerified, Paper, Text } from '@audius/harmony' import { Form, Formik } from 'formik' @@ -33,10 +34,7 @@ import { import { HandleField } from '../components/HandleField' import { OutOfText } from '../components/OutOfText' import { SocialMediaLoading } from '../components/SocialMediaLoading' -import { - SocialMediaLoginOptions, - SocialPlatform -} from '../components/SocialMediaLoginOptions' +import { SocialMediaLoginOptions } from '../components/SocialMediaLoginOptions' import { Heading, Page, PageFooter } from '../components/layout' import { useSocialMediaLoader } from '../hooks/useSocialMediaLoader' @@ -48,7 +46,7 @@ type SocialMediaSectionProps = { onCompleteSocialMediaLogin: (info: { requiresReview: boolean handle: string - platform: 'twitter' | 'instagram' | 'tiktok' + platform: SocialPlatform }) => void onStart: (platform: SocialPlatform) => void onError: (error: Error, platform: SocialPlatform) => void @@ -139,7 +137,7 @@ export const PickHandlePage = () => { }: { requiresReview: boolean handle: string - platform: 'twitter' | 'instagram' | 'tiktok' + platform: SocialPlatform }) => { dispatch(setValueField('handle', handle)) if (!requiresReview) { From 294fdb6e52c2259e9b651d522c22872073bb22c2 Mon Sep 17 00:00:00 2001 From: Saliou Diallo Date: Thu, 6 Jun 2024 10:56:01 -0400 Subject: [PATCH 02/12] Update user types in libs --- packages/libs/src/api/Users.ts | 5 +++ .../schemaValidator/schemas/userSchema.json | 32 +++++++++++++++++++ packages/libs/src/utils/types.ts | 16 +++++----- 3 files changed, 45 insertions(+), 8 deletions(-) diff --git a/packages/libs/src/api/Users.ts b/packages/libs/src/api/Users.ts index 84057f19f1a..e0aa14edda9 100644 --- a/packages/libs/src/api/Users.ts +++ b/packages/libs/src/api/Users.ts @@ -10,6 +10,11 @@ import { Base, BaseConstructorArgs, Services } from './base' // null or non-null values const USER_PROPS = [ 'is_verified', + 'twitter_handle', + 'instagram_handle', + 'tiktok_handle', + 'website', + 'donation', 'is_deactivated', 'name', 'handle', diff --git a/packages/libs/src/services/schemaValidator/schemas/userSchema.json b/packages/libs/src/services/schemaValidator/schemas/userSchema.json index 5954c85ed46..01380267764 100644 --- a/packages/libs/src/services/schemaValidator/schemas/userSchema.json +++ b/packages/libs/src/services/schemaValidator/schemas/userSchema.json @@ -26,6 +26,38 @@ "type": ["string", "null"], "default": null }, + "twitter_handle": { + "type": ["string", "null"], + "default": null + }, + "instagram_handle": { + "type": ["string", "null"], + "default": null + }, + "tiktok_handle": { + "type": ["string", "null"], + "default": null + }, + "verified_with_twitter": { + "type": "boolean", + "default": false + }, + "verified_with_instagram": { + "type": "boolean", + "default": false + }, + "verified_with_tiktok": { + "type": "boolean", + "default": false + }, + "website": { + "type": ["string", "null"], + "default": null + }, + "donation": { + "type": ["string", "null"], + "default": null + }, "bio": { "type": ["string", "null"], "default": null diff --git a/packages/libs/src/utils/types.ts b/packages/libs/src/utils/types.ts index 7819fa584e0..ba11f3608d7 100644 --- a/packages/libs/src/utils/types.ts +++ b/packages/libs/src/utils/types.ts @@ -45,6 +45,14 @@ export type UserMetadata = { handle_lc: string is_deactivated: boolean is_verified: boolean + twitter_handle: Nullable + instagram_handle: Nullable + tiktok_handle: Nullable + verified_with_twitter: boolean + verified_with_instagram: boolean + verified_with_tiktok: boolean + website: Nullable + donation: Nullable is_storage_v2: boolean location: Nullable // this should be removed @@ -64,15 +72,7 @@ export type UserMetadata = { // Only present on the "current" account track_save_count?: number - twitter_handle?: string - instagram_handle?: string - tiktok_handle?: string - website?: string wallet?: string - donation?: string - twitterVerified?: boolean - instagramVerified?: boolean - tikTokVerified?: boolean } export type User = UserMetadata From ad8a2de920ca2c66a24df542dd1effae36d3e727 Mon Sep 17 00:00:00 2001 From: Saliou Diallo Date: Thu, 6 Jun 2024 14:01:21 -0400 Subject: [PATCH 03/12] Write to both identity and dn for socials update. Use identity as fallback when getting socials. --- .../services/audius-backend/AudiusBackend.ts | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/packages/common/src/services/audius-backend/AudiusBackend.ts b/packages/common/src/services/audius-backend/AudiusBackend.ts index 94dac8bcf16..3fba5a30f2c 100644 --- a/packages/common/src/services/audius-backend/AudiusBackend.ts +++ b/packages/common/src/services/audius-backend/AudiusBackend.ts @@ -742,6 +742,27 @@ export const audiusBackend = ({ const account = audiusLibs.Account.getCurrentUser() if (!account) return null + // This is saying that if there is any social info coming back from DN, + // then we should not attempt to fetch socials from identity. + // It is possible that identity has more up-to-date socials than DN, + // but we can live with that until we do the final social backfill from identity to DN. + const hasSocialsFromDn = account.twitter_handle || account.instagram_handle || account.tiktok_handle || account.website || account.donation || account.verified_with_twitter || account.verified_with_instagram || account.verified_with_tiktok + if (!hasSocialsFromDn) { + try { + const body = await getSocialHandles(account.handle) + account.twitter_handle = body.twitterHandle || null + account.instagram_handle = body.instagramHandle || null + account.tiktok_handle = body.tikTokHandle || null + account.website = body.website || null + account.donation = body.donation || null + account.verified_with_twitter = body.twitterVerified || false + account.verified_with_instagram= body.instagramVerified || false + account.verified_with_tiktok = body.tikTokVerified || false + } catch (e) { + console.error(e) + } + } + try { const userBank = await audiusLibs.solanaWeb3Manager.deriveUserBank() account.userBank = userBank.toString() @@ -953,6 +974,19 @@ export const audiusBackend = ({ } } + async function getSocialHandles(handle: string) { + try { + const res = await fetch( + `${identityServiceUrl}/social_handles?handle=${handle}` + ) + const json = await res.json() + return json + } catch (e) { + console.error(e) + return {} + } + } + /** * Retrieves the user's eth associated wallets from IPFS using the user's metadata CID and creator node endpoints * @param user The user metadata which contains the CID for the metadata multihash @@ -1029,6 +1063,39 @@ export const audiusBackend = ({ newMetadata.cover_photo_sizes = resp.id } + // Leave this here for now, but this should be removed once we believe + // that old clients have caught up and are updating socials via entity manager to DN. + try { + if ( + typeof newMetadata.twitter_handle === 'string' || + typeof newMetadata.instagram_handle === 'string' || + typeof newMetadata.tiktok_handle === 'string' || + typeof newMetadata.website === 'string' || + typeof newMetadata.donation === 'string' + ) { + const { data, signature } = await signData() + await fetch(`${identityServiceUrl}/social_handles`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + [AuthHeaders.Message]: data, + [AuthHeaders.Signature]: signature + }, + body: JSON.stringify({ + twitterHandle: newMetadata.twitter_handle, + instagramHandle: newMetadata.instagram_handle, + tikTokHandle: newMetadata.tiktok_handle, + website: newMetadata.website, + donation: newMetadata.donation + }) + }) + } + } catch (e) { + console.error( + `Could not update socials in identity, but they should still be updated in DN with code below. Error: ${e}` + ) + } + newMetadata = schemas.newUserMetadata(newMetadata, true) const userId = newMetadata.user_id const { blockHash, blockNumber } = await audiusLibs.User.updateMetadataV2( @@ -2978,6 +3045,7 @@ export const audiusBackend = ({ getBrowserPushSubscription, getCollectionImages, getCreators, + getSocialHandles, getEmailNotificationSettings, getFolloweeFollows, getImageUrl, From f53e194cb43d1bf01debee05579ca21694307e73 Mon Sep 17 00:00:00 2001 From: Saliou Diallo Date: Thu, 6 Jun 2024 14:24:53 -0400 Subject: [PATCH 04/12] Use identity twitter handle as fallback in share modal and drawer --- .../mobile/src/components/share-drawer/utils.ts | 15 ++++++++++----- .../components/notification/Notification/utils.ts | 8 ++++++++ packages/web/src/components/share-modal/utils.ts | 15 ++++++++++----- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/packages/mobile/src/components/share-drawer/utils.ts b/packages/mobile/src/components/share-drawer/utils.ts index bf1ca37fd71..4efb2a6e5c2 100644 --- a/packages/mobile/src/components/share-drawer/utils.ts +++ b/packages/mobile/src/components/share-drawer/utils.ts @@ -2,6 +2,7 @@ import type { ShareContent } from '@audius/common/store' import type { Nullable } from '@audius/common/utils' import { makeTwitterShareUrl } from '@audius/common/utils' +import { audiusBackendInstance } from 'app/services/audius-backend-instance' import { getCollectionRoute, getTrackRoute, @@ -35,13 +36,17 @@ export const getContentUrl = (content: ShareContent) => { } } -const getTwitterShareHandle = ({ +const getTwitterShareHandle = async ({ handle, twitterHandle }: { handle: string twitterHandle: Nullable }) => { + if (!twitterHandle) { + const socials = await audiusBackendInstance.getSocialHandles(handle) + return socials.twitterHandle ? `@${socials.twitterHandle}` : handle + } return twitterHandle ? `@${twitterHandle}` : handle } @@ -54,7 +59,7 @@ export const getTwitterShareText = async (content: ShareContent) => { } = content return messages.trackShareText( title, - getTwitterShareHandle({ handle, twitterHandle }) + await getTwitterShareHandle({ handle, twitterHandle }) ) } case 'profile': { @@ -62,7 +67,7 @@ export const getTwitterShareText = async (content: ShareContent) => { profile: { handle, twitter_handle: twitterHandle } } = content return messages.profileShareText( - getTwitterShareHandle({ handle, twitterHandle }) + await getTwitterShareHandle({ handle, twitterHandle }) ) } case 'album': { @@ -72,7 +77,7 @@ export const getTwitterShareText = async (content: ShareContent) => { } = content return messages.albumShareText( playlist_name, - getTwitterShareHandle({ handle, twitterHandle }) + await getTwitterShareHandle({ handle, twitterHandle }) ) } case 'playlist': { @@ -82,7 +87,7 @@ export const getTwitterShareText = async (content: ShareContent) => { } = content return messages.playlistShareText( playlist_name, - getTwitterShareHandle({ handle, twitterHandle }) + await getTwitterShareHandle({ handle, twitterHandle }) ) } case 'audioNftPlaylist': { diff --git a/packages/web/src/components/notification/Notification/utils.ts b/packages/web/src/components/notification/Notification/utils.ts index 3e10a962e87..5cfad5c31e4 100644 --- a/packages/web/src/components/notification/Notification/utils.ts +++ b/packages/web/src/components/notification/Notification/utils.ts @@ -1,5 +1,6 @@ import { Entity, EntityType } from '@audius/common/store' +import { audiusBackendInstance } from 'services/audius-backend/audius-backend-instance' import { UserListEntityType } from 'store/application/ui/userListModal/types' import { fullCollectionPage, fullTrackPage, collectionPage } from 'utils/route' @@ -27,6 +28,13 @@ export const getRankSuffix = (rank: number) => { return 'th' } +export const getTwitterHandleByUserHandle = async (userHandle: string) => { + const { twitterHandle } = await audiusBackendInstance.getSocialHandles( + userHandle + ) + return twitterHandle || '' +} + export const USER_LENGTH_LIMIT = 9 export const entityToUserListEntity = { diff --git a/packages/web/src/components/share-modal/utils.ts b/packages/web/src/components/share-modal/utils.ts index 275f2ae3d5b..02b79127e02 100644 --- a/packages/web/src/components/share-modal/utils.ts +++ b/packages/web/src/components/share-modal/utils.ts @@ -1,6 +1,7 @@ import { ShareToTwitter } from '@audius/common/models' import { ShareContent } from '@audius/common/store' import { Nullable } from '@audius/common/utils' +import { getTwitterHandleByUserHandle } from 'components/notification/Notification/utils' import { fullCollectionPage, @@ -13,13 +14,17 @@ import { messages } from './messages' type ShareToTwitterEvent = Omit -const getTwitterShareHandle = ({ +const getTwitterShareHandle = async ({ handle, twitterHandle }: { handle: string twitterHandle: Nullable }) => { + if (!twitterHandle) { + const theTwitterHandle = await getTwitterHandleByUserHandle(handle) + return theTwitterHandle ? `@${theTwitterHandle}` : handle + } return twitterHandle ? `@${twitterHandle}` : handle } @@ -48,7 +53,7 @@ export const getTwitterShareText = async ( } = content twitterText = messageConfig.trackShareText( title, - getTwitterShareHandle({ handle, twitterHandle }) + await getTwitterShareHandle({ handle, twitterHandle }) ) link = fullTrackPage(permalink) analyticsEvent = { kind: 'track', id: track_id, url: link } @@ -59,7 +64,7 @@ export const getTwitterShareText = async ( profile: { handle, user_id, twitter_handle: twitterHandle } } = content twitterText = messageConfig.profileShareText( - getTwitterShareHandle({ handle, twitterHandle }) + await getTwitterShareHandle({ handle, twitterHandle }) ) link = fullProfilePage(handle) analyticsEvent = { kind: 'profile', id: user_id, url: link } @@ -72,7 +77,7 @@ export const getTwitterShareText = async ( } = content twitterText = messageConfig.albumShareText( playlist_name, - getTwitterShareHandle({ handle, twitterHandle }) + await getTwitterShareHandle({ handle, twitterHandle }) ) link = fullCollectionPage( handle, @@ -91,7 +96,7 @@ export const getTwitterShareText = async ( } = content twitterText = messageConfig.playlistShareText( playlist_name, - getTwitterShareHandle({ handle, twitterHandle }) + await getTwitterShareHandle({ handle, twitterHandle }) ) link = fullCollectionPage( handle, From 50e6512c04d5c1a145115c2d6a4078b9ea2e1523 Mon Sep 17 00:00:00 2001 From: Saliou Diallo Date: Thu, 6 Jun 2024 14:51:29 -0400 Subject: [PATCH 05/12] Re-add fetchUserSocials for fallback --- .../src/hooks/useTwitterButtonStatus.ts | 12 ++++-- .../common/src/store/cache/users/actions.ts | 5 +++ .../twitter-button/TwitterButton.tsx | 12 ++++-- .../ProfileHeader/ProfileSocials.tsx | 15 +++++++- .../web/src/common/store/cache/users/sagas.ts | 38 ++++++++++++++++++- .../web/src/common/store/profile/sagas.js | 4 +- .../ai-attribution-modal/SearchBarResult.jsx | 8 ++++ .../components/TwitterShareButton.tsx | 16 ++++++-- .../web/src/components/share-modal/utils.ts | 2 +- .../TwitterShareButton.tsx | 16 ++++++-- 10 files changed, 111 insertions(+), 17 deletions(-) diff --git a/packages/common/src/hooks/useTwitterButtonStatus.ts b/packages/common/src/hooks/useTwitterButtonStatus.ts index 3896ff7de8b..c257fdf7bb7 100644 --- a/packages/common/src/hooks/useTwitterButtonStatus.ts +++ b/packages/common/src/hooks/useTwitterButtonStatus.ts @@ -17,13 +17,19 @@ export const useTwitterButtonStatus = ( const twitterHandle = user?.twitter_handle const additionalUserName = additionalUser?.name - const additionalTwitterHandle = additionalUser?.twitter_handle ?? null + const additionalTwitterHandle = additionalUser?.twitter_handle + + // Initially twitter handle is undefined; after fetch it's + // set to either null or a value in `fetchUserSocials` sagas + const twitterHandleFetched = + twitterHandle !== undefined && + (additionalUser ? additionalTwitterHandle !== undefined : true) useEffect(() => { - if (shareTwitterStatus === 'loading') { + if (shareTwitterStatus === 'loading' && twitterHandleFetched) { setShareTwitterStatus('success') } - }, [setShareTwitterStatus, shareTwitterStatus]) + }, [setShareTwitterStatus, shareTwitterStatus, twitterHandleFetched]) const setLoading = useCallback(() => setShareTwitterStatus('loading'), []) const setIdle = useCallback(() => setShareTwitterStatus('idle'), []) diff --git a/packages/common/src/store/cache/users/actions.ts b/packages/common/src/store/cache/users/actions.ts index dcad6623f21..669ffab579a 100644 --- a/packages/common/src/store/cache/users/actions.ts +++ b/packages/common/src/store/cache/users/actions.ts @@ -4,6 +4,7 @@ export const REMOVE_BY_HANDLE = 'CACHE/USERS/REMOVE_BY_HANDLE' export const FETCH_PROFILE_PICTURE = 'CACHE/USERS/FETCH_PROFILE_PICTURE' export const FETCH_COVER_PHOTO = 'CACHE/USERS/FETCH_COVER_PHOTO' +export const FETCH_USER_SOCIALS = 'CACHE/USERS/FETCH_USER_SOCIALS' export const FETCH_USERS = 'CACHE/USERS/FETCH' export const removeByHandle = (handle: string) => ({ @@ -22,6 +23,10 @@ export function fetchCoverPhoto(userId: ID, size: WidthSizes | SquareSizes) { return { type: FETCH_COVER_PHOTO, userId, size } } +export function fetchUserSocials(handle: string) { + return { type: FETCH_USER_SOCIALS, handle } +} + export function fetchUsers({ userIds, requiredFields, diff --git a/packages/mobile/src/components/twitter-button/TwitterButton.tsx b/packages/mobile/src/components/twitter-button/TwitterButton.tsx index 086cd8fc2f6..449092931c3 100644 --- a/packages/mobile/src/components/twitter-button/TwitterButton.tsx +++ b/packages/mobile/src/components/twitter-button/TwitterButton.tsx @@ -1,10 +1,10 @@ import { useCallback } from 'react' import { useTwitterButtonStatus } from '@audius/common/hooks' -import { cacheUsersSelectors } from '@audius/common/store' +import { cacheUsersActions, cacheUsersSelectors } from '@audius/common/store' import { makeTwitterShareUrl } from '@audius/common/utils' import type { Nullable } from '@audius/common/utils' -import { useSelector } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import { IconTwitter } from '@audius/harmony-native' import type { ButtonProps } from 'app/components/core' @@ -14,6 +14,7 @@ import { makeStyles } from 'app/styles' import { spacing } from 'app/styles/spacing' import type { AllEvents } from 'app/types/analytics' const { getUser } = cacheUsersSelectors +const { fetchUserSocials } = cacheUsersActions const messages = { share: 'Share to Twitter' @@ -52,6 +53,7 @@ export const TwitterButton = (props: TwitterButtonProps) => { const { size } = other const styles = useStyles() const openLink = useOnOpenLink() + const dispatch = useDispatch() const user = useSelector((state) => getUser(state, { handle: 'handle' in other ? other.handle : undefined }) @@ -78,9 +80,13 @@ export const TwitterButton = (props: TwitterButtonProps) => { track(make(other.analytics)) } if (other.type === 'dynamic') { + dispatch(fetchUserSocials(other.handle)) + if (other.additionalHandle) { + dispatch(fetchUserSocials(other.additionalHandle)) + } setLoading() } - }, [other, setLoading]) + }, [other, dispatch, setLoading]) if (other.type === 'dynamic' && shareTwitterStatus === 'success') { const handle = twitterHandle ? `@${twitterHandle}` : userName diff --git a/packages/mobile/src/screens/profile-screen/ProfileHeader/ProfileSocials.tsx b/packages/mobile/src/screens/profile-screen/ProfileHeader/ProfileSocials.tsx index bd2101224fa..0bc63ac8bdf 100644 --- a/packages/mobile/src/screens/profile-screen/ProfileHeader/ProfileSocials.tsx +++ b/packages/mobile/src/screens/profile-screen/ProfileHeader/ProfileSocials.tsx @@ -1,7 +1,9 @@ -import { Fragment, useLayoutEffect, useMemo, useRef } from 'react' +import { Fragment, useEffect, useLayoutEffect, useMemo, useRef } from 'react' import { useSelectTierInfo } from '@audius/common/hooks' +import { cacheUsersActions } from '@audius/common/store' import { View, Animated } from 'react-native' +import { useDispatch } from 'react-redux' import { Divider } from 'app/components/core' import { makeStyles } from 'app/styles' @@ -16,6 +18,8 @@ import { TwitterSocialLink } from './SocialLink' +const { fetchUserSocials } = cacheUsersActions + const useStyles = makeStyles(({ spacing }) => ({ root: { flexDirection: 'row', @@ -39,14 +43,21 @@ const useStyles = makeStyles(({ spacing }) => ({ })) export const ProfileSocials = () => { - const { user_id, twitter_handle, instagram_handle, tiktok_handle } = + const { handle, user_id, twitter_handle, instagram_handle, tiktok_handle } = useSelectProfile([ + 'handle', 'user_id', 'twitter_handle', 'instagram_handle', 'tiktok_handle' ]) + const dispatch = useDispatch() + + useEffect(() => { + dispatch(fetchUserSocials(handle)) + }, [dispatch, handle]) + const socialLinks = useMemo(() => { const links = [ { diff --git a/packages/web/src/common/store/cache/users/sagas.ts b/packages/web/src/common/store/cache/users/sagas.ts index 3a380865b9b..3e0c4f26ced 100644 --- a/packages/web/src/common/store/cache/users/sagas.ts +++ b/packages/web/src/common/store/cache/users/sagas.ts @@ -17,7 +17,7 @@ import { reformatUser, getSDK } from '@audius/common/store' -import { waitForAccount } from '@audius/common/utils' +import { waitForAccount, waitForValue } from '@audius/common/utils' import { mergeWith } from 'lodash' import { call, put, select, takeEvery } from 'typed-redux-saga' @@ -352,6 +352,41 @@ function* watchFetchCoverPhoto() { ) } +export function* fetchUserSocials({ + handle +}: ReturnType) { + const audiusBackendInstance = yield* getContext('audiusBackendInstance') + let user = yield* select(getUser, { handle }) + if (!user) { + yield* call(fetchUserByHandle, handle, new Set()) + } + user = yield* call(waitForValue, getUser, { handle }) + if (!user) return + const socials = yield* call( + audiusBackendInstance.getSocialHandles, + user.handle + ) + + yield* put( + cacheActions.update(Kind.USERS, [ + { + id: user.user_id, + metadata: { + twitter_handle: socials.twitterHandle || null, + instagram_handle: socials.instagramHandle || null, + tiktok_handle: socials.tikTokHandle || null, + website: socials.website || null, + donation: socials.donation || null + } + } + ]) + ) +} + +function* watchFetchUserSocials() { + yield* takeEvery(userActions.FETCH_USER_SOCIALS, fetchUserSocials) +} + function* watchFetchUsers() { yield* takeEvery( userActions.FETCH_USERS, @@ -368,6 +403,7 @@ const sagas = () => { watchFetchProfilePicture, watchFetchCoverPhoto, watchSyncLocalStorageUser, + watchFetchUserSocials, watchFetchUsers ] } diff --git a/packages/web/src/common/store/profile/sagas.js b/packages/web/src/common/store/profile/sagas.js index 733054dd91e..3165d116b24 100644 --- a/packages/web/src/common/store/profile/sagas.js +++ b/packages/web/src/common/store/profile/sagas.js @@ -40,7 +40,8 @@ import { import { fetchUsers, fetchUserByHandle, - fetchUserCollections + fetchUserCollections, + fetchUserSocials } from 'common/store/cache/users/sagas' import feedSagas from 'common/store/pages/profile/lineups/feed/sagas.js' import tracksSagas from 'common/store/pages/profile/lineups/tracks/sagas.js' @@ -366,6 +367,7 @@ function* fetchProfileAsync(action) { if (!isNativeMobile) { // Fetch user collections after fetching the user itself + yield fork(fetchUserSocials, action) yield fork(fetchUserCollections, user.user_id) yield fork(fetchSupportersAndSupporting, user.user_id) } diff --git a/packages/web/src/components/ai-attribution-modal/SearchBarResult.jsx b/packages/web/src/components/ai-attribution-modal/SearchBarResult.jsx index 6813e446ad1..5bc3e62b252 100644 --- a/packages/web/src/components/ai-attribution-modal/SearchBarResult.jsx +++ b/packages/web/src/components/ai-attribution-modal/SearchBarResult.jsx @@ -2,9 +2,11 @@ import { useState, useEffect, memo, useCallback } from 'react' import { imageBlank as placeholderArt } from '@audius/common/assets' import { Kind } from '@audius/common/models' +import { cacheUsersActions } from '@audius/common/store' import { Tag } from '@audius/harmony' import cn from 'classnames' import PropTypes from 'prop-types' +import { useDispatch } from 'react-redux' import DynamicImage from 'components/dynamic-image/DynamicImage' import { TwitterShareButton } from 'components/notification/Notification/components/TwitterShareButton' @@ -73,6 +75,12 @@ const SearchBarResult = memo((props) => { handle } = props const isUser = kind === Kind.USERS + const { fetchUserSocials } = cacheUsersActions + const dispatch = useDispatch() + + useEffect(() => { + dispatch(fetchUserSocials(handle)) + }, [dispatch, fetchUserSocials, handle]) const handleTwitterShare = useCallback((handle) => { const shareText = messages.tweet(handle) diff --git a/packages/web/src/components/notification/Notification/components/TwitterShareButton.tsx b/packages/web/src/components/notification/Notification/components/TwitterShareButton.tsx index 9d575472bda..837b379d6fe 100644 --- a/packages/web/src/components/notification/Notification/components/TwitterShareButton.tsx +++ b/packages/web/src/components/notification/Notification/components/TwitterShareButton.tsx @@ -1,16 +1,21 @@ import { MouseEventHandler, useCallback } from 'react' import { useTwitterButtonStatus } from '@audius/common/hooks' -import { cacheUsersSelectors, CommonState } from '@audius/common/store' +import { + cacheUsersActions, + cacheUsersSelectors, + CommonState +} from '@audius/common/store' import { Nullable } from '@audius/common/utils' import { IconTwitter as IconTwitterBird } from '@audius/harmony' import cn from 'classnames' -import { useSelector } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import { useRecord, TrackEvent } from 'common/store/analytics/actions' import { openTwitterLink } from 'utils/tweet' import styles from './TwitterShareButton.module.css' +const { fetchUserSocials } = cacheUsersActions const { getUser } = cacheUsersSelectors const messages = { @@ -45,6 +50,7 @@ type TwitterShareButtonProps = { export const TwitterShareButton = (props: TwitterShareButtonProps) => { const { url = null, className, hideText, ...other } = props const record = useRecord() + const dispatch = useDispatch() const user = useSelector((state: CommonState) => getUser(state, { handle: 'handle' in other ? other.handle : undefined }) @@ -76,10 +82,14 @@ export const TwitterShareButton = (props: TwitterShareButtonProps) => { } } if (other.type === 'dynamic') { + dispatch(fetchUserSocials(other.handle)) + if (other.additionalHandle) { + dispatch(fetchUserSocials(other.additionalHandle)) + } setLoading() } }, - [url, other, record, setLoading] + [url, other, dispatch, record, setLoading] ) if ( diff --git a/packages/web/src/components/share-modal/utils.ts b/packages/web/src/components/share-modal/utils.ts index 02b79127e02..ce8e9eaea2b 100644 --- a/packages/web/src/components/share-modal/utils.ts +++ b/packages/web/src/components/share-modal/utils.ts @@ -1,8 +1,8 @@ import { ShareToTwitter } from '@audius/common/models' import { ShareContent } from '@audius/common/store' import { Nullable } from '@audius/common/utils' -import { getTwitterHandleByUserHandle } from 'components/notification/Notification/utils' +import { getTwitterHandleByUserHandle } from 'components/notification/Notification/utils' import { fullCollectionPage, fullProfilePage, diff --git a/packages/web/src/components/twitter-share-button/TwitterShareButton.tsx b/packages/web/src/components/twitter-share-button/TwitterShareButton.tsx index 85c011a0192..411f31ef422 100644 --- a/packages/web/src/components/twitter-share-button/TwitterShareButton.tsx +++ b/packages/web/src/components/twitter-share-button/TwitterShareButton.tsx @@ -1,18 +1,23 @@ import { MouseEventHandler, useCallback } from 'react' import { useTwitterButtonStatus } from '@audius/common/hooks' -import { cacheUsersSelectors, CommonState } from '@audius/common/store' +import { + cacheUsersActions, + cacheUsersSelectors, + CommonState +} from '@audius/common/store' import { Nullable } from '@audius/common/utils' import { Button, ButtonProps, IconTwitter as IconTwitterBird } from '@audius/harmony' -import { useSelector } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import { useRecord, TrackEvent } from 'common/store/analytics/actions' import { openTwitterLink } from 'utils/tweet' +const { fetchUserSocials } = cacheUsersActions const { getUser } = cacheUsersSelectors const messages = { @@ -46,6 +51,7 @@ type TwitterShareButtonProps = { export const TwitterShareButton = (props: TwitterShareButtonProps) => { const { url = null, fullWidth, size, hideText, ...other } = props const record = useRecord() + const dispatch = useDispatch() const user = useSelector((state: CommonState) => getUser(state, { handle: 'handle' in other ? other.handle : undefined }) @@ -77,10 +83,14 @@ export const TwitterShareButton = (props: TwitterShareButtonProps) => { } } if (other.type === 'dynamic') { + dispatch(fetchUserSocials(other.handle)) + if (other.additionalHandle) { + dispatch(fetchUserSocials(other.additionalHandle)) + } setLoading() } }, - [url, other, record, setLoading] + [url, other, dispatch, record, setLoading] ) if ( From 77b0f21d3ae22f86fa1abef34fc06ed2d4bd4b07 Mon Sep 17 00:00:00 2001 From: Saliou Diallo Date: Thu, 6 Jun 2024 14:51:37 -0400 Subject: [PATCH 06/12] Lint --- .../src/services/audius-backend/AudiusBackend.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/common/src/services/audius-backend/AudiusBackend.ts b/packages/common/src/services/audius-backend/AudiusBackend.ts index 3fba5a30f2c..8586a2cb375 100644 --- a/packages/common/src/services/audius-backend/AudiusBackend.ts +++ b/packages/common/src/services/audius-backend/AudiusBackend.ts @@ -746,7 +746,15 @@ export const audiusBackend = ({ // then we should not attempt to fetch socials from identity. // It is possible that identity has more up-to-date socials than DN, // but we can live with that until we do the final social backfill from identity to DN. - const hasSocialsFromDn = account.twitter_handle || account.instagram_handle || account.tiktok_handle || account.website || account.donation || account.verified_with_twitter || account.verified_with_instagram || account.verified_with_tiktok + const hasSocialsFromDn = + account.twitter_handle || + account.instagram_handle || + account.tiktok_handle || + account.website || + account.donation || + account.verified_with_twitter || + account.verified_with_instagram || + account.verified_with_tiktok if (!hasSocialsFromDn) { try { const body = await getSocialHandles(account.handle) @@ -756,7 +764,7 @@ export const audiusBackend = ({ account.website = body.website || null account.donation = body.donation || null account.verified_with_twitter = body.twitterVerified || false - account.verified_with_instagram= body.instagramVerified || false + account.verified_with_instagram = body.instagramVerified || false account.verified_with_tiktok = body.tikTokVerified || false } catch (e) { console.error(e) From f4ebd09bbe2f0eb266e6189d055cf8ce0937e76f Mon Sep 17 00:00:00 2001 From: Saliou Diallo Date: Thu, 6 Jun 2024 14:58:26 -0400 Subject: [PATCH 07/12] Fix response adapter --- packages/common/src/models/User.ts | 3 --- packages/common/src/services/audius-api-client/types.ts | 8 ++++++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/common/src/models/User.ts b/packages/common/src/models/User.ts index 97d29b97bed..13e4e8ae8d0 100644 --- a/packages/common/src/models/User.ts +++ b/packages/common/src/models/User.ts @@ -68,9 +68,6 @@ export type UserMetadata = { track_save_count?: number user_id: number wallet?: string - verifiedWithTwitter?: boolean - verifiedWithInstagram?: boolean - verifiedWithTiktok?: boolean balance?: Nullable total_balance?: Nullable associated_wallets?: Nullable diff --git a/packages/common/src/services/audius-api-client/types.ts b/packages/common/src/services/audius-api-client/types.ts index e972d620a3a..51ed338a9bb 100644 --- a/packages/common/src/services/audius-api-client/types.ts +++ b/packages/common/src/services/audius-api-client/types.ts @@ -36,6 +36,14 @@ export type APIUser = { handle: string id: OpaqueID is_verified: boolean + twitter_handle: Nullable + instagram_handle: Nullable + tiktok_handle: Nullable + verified_with_twitter: boolean + verified_with_instagram: boolean + verified_with_tiktok: boolean + website: Nullable + donation: Nullable is_deactivated: boolean location: Nullable name: string From cdfd9f1a15fb2660589fd86a2344467dcd95b10c Mon Sep 17 00:00:00 2001 From: Saliou Diallo Date: Thu, 6 Jun 2024 15:27:55 -0400 Subject: [PATCH 08/12] Fix user adapter --- packages/common/src/adapters/user.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/common/src/adapters/user.ts b/packages/common/src/adapters/user.ts index 79949d4e14c..929286bce95 100644 --- a/packages/common/src/adapters/user.ts +++ b/packages/common/src/adapters/user.ts @@ -59,6 +59,11 @@ export const userMetadataFromSDK = ( // Required Nullable fields bio: user.bio ?? null, + twitter_handle: user.twitter_handle ?? null, + instagram_handle: user.instagram_handle ?? null, + tiktok_handle: user.tiktok_handle ?? null, + website: user.website ?? null, + donation: user.donation ?? null, cover_photo_sizes: user.cover_photo_sizes ?? null, creator_node_endpoint: user.creator_node_endpoint ?? null, location: user.location ?? null, From df0e0a696075055ce9bccdbb99746690aa80cb99 Mon Sep 17 00:00:00 2001 From: Saliou Diallo Date: Thu, 6 Jun 2024 15:28:27 -0400 Subject: [PATCH 09/12] Fix mobile social links --- .../ProfileHeader/SocialLink.tsx | 22 ++----------------- .../ProfileHeader/SocialsAndSites.tsx | 3 ++- 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/packages/mobile/src/screens/profile-screen/ProfileHeader/SocialLink.tsx b/packages/mobile/src/screens/profile-screen/ProfileHeader/SocialLink.tsx index 7b4a915400e..a3951aea05d 100644 --- a/packages/mobile/src/screens/profile-screen/ProfileHeader/SocialLink.tsx +++ b/packages/mobile/src/screens/profile-screen/ProfileHeader/SocialLink.tsx @@ -1,7 +1,7 @@ import { useCallback, useState } from 'react' import type { StyleProp, ViewStyle } from 'react-native' -import { View } from 'react-native' +import type { Nullable } from '~/utils' import type { IconButtonProps } from '@audius/harmony-native' import { @@ -12,7 +12,6 @@ import { } from '@audius/harmony-native' import type { LinkProps } from 'app/components/core' import { Link, UserGeneratedText } from 'app/components/core' -import Skeleton from 'app/components/skeleton' import { make } from 'app/services/analytics' import { makeStyles } from 'app/styles' import { EventNames } from 'app/types/analytics' @@ -40,7 +39,7 @@ const useStyles = makeStyles(({ spacing }) => ({ export type SocialLinkProps = LinkProps & Pick & { style?: StyleProp - text?: string + text: Nullable showText?: boolean hyperlink?: boolean } @@ -58,23 +57,6 @@ export const SocialLink = (props: SocialLinkProps) => { setIsActive(false) }, []) - // undefined equates to "LOADING" from backend - if (text === undefined) { - if (showText) { - return ( - - - - - ) - } - return ( - - ) - } - if (text === null || text === '') return null const iconButtonElement = diff --git a/packages/mobile/src/screens/profile-screen/ProfileHeader/SocialsAndSites.tsx b/packages/mobile/src/screens/profile-screen/ProfileHeader/SocialsAndSites.tsx index c2bf625e9bb..8d4f29cd890 100644 --- a/packages/mobile/src/screens/profile-screen/ProfileHeader/SocialsAndSites.tsx +++ b/packages/mobile/src/screens/profile-screen/ProfileHeader/SocialsAndSites.tsx @@ -1,4 +1,5 @@ import { View } from 'react-native' +import type { Nullable } from '~/utils' import { IconDonate, IconLink } from '@audius/harmony-native' import { makeStyles } from 'app/styles' @@ -29,7 +30,7 @@ const useStyles = makeStyles(({ spacing, palette, typography }) => ({ })) // adds https to urls that don't include http protocol -const prependProtocol = (url?: string) => +const prependProtocol = (url: Nullable) => !url?.match(/^https?:\/\//i) ? `https://${url}` : url export const SocialsAndSites = () => { From 75ebb6ae4a020030f4aa74010974412ca8934c6d Mon Sep 17 00:00:00 2001 From: Saliou Diallo Date: Thu, 6 Jun 2024 15:32:13 -0400 Subject: [PATCH 10/12] Update comments --- packages/web/src/common/store/profile/sagas.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web/src/common/store/profile/sagas.js b/packages/web/src/common/store/profile/sagas.js index 3165d116b24..b9599d75e30 100644 --- a/packages/web/src/common/store/profile/sagas.js +++ b/packages/web/src/common/store/profile/sagas.js @@ -366,7 +366,7 @@ function* fetchProfileAsync(action) { ) if (!isNativeMobile) { - // Fetch user collections after fetching the user itself + // Fetch user socials and collections after fetching the user itself yield fork(fetchUserSocials, action) yield fork(fetchUserCollections, user.user_id) yield fork(fetchSupportersAndSupporting, user.user_id) From c7d28ff97e6117ac545663c85e78f0e250034f21 Mon Sep 17 00:00:00 2001 From: Saliou Diallo Date: Thu, 6 Jun 2024 15:35:41 -0400 Subject: [PATCH 11/12] Update imports --- .../src/screens/profile-screen/ProfileHeader/SocialLink.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mobile/src/screens/profile-screen/ProfileHeader/SocialLink.tsx b/packages/mobile/src/screens/profile-screen/ProfileHeader/SocialLink.tsx index a3951aea05d..c670a7bbb92 100644 --- a/packages/mobile/src/screens/profile-screen/ProfileHeader/SocialLink.tsx +++ b/packages/mobile/src/screens/profile-screen/ProfileHeader/SocialLink.tsx @@ -1,7 +1,7 @@ import { useCallback, useState } from 'react' +import type { Nullable } from '@audius/common/utils' import type { StyleProp, ViewStyle } from 'react-native' -import type { Nullable } from '~/utils' import type { IconButtonProps } from '@audius/harmony-native' import { From aa19362165990e4ec13c26a6a20af7aa77daf45a Mon Sep 17 00:00:00 2001 From: Saliou Diallo Date: Thu, 6 Jun 2024 23:10:50 -0400 Subject: [PATCH 12/12] Undo get twitter share handle changes --- .../src/components/share-drawer/utils.ts | 35 ++++++------------- .../web/src/components/share-modal/utils.ts | 30 ++++++---------- 2 files changed, 20 insertions(+), 45 deletions(-) diff --git a/packages/mobile/src/components/share-drawer/utils.ts b/packages/mobile/src/components/share-drawer/utils.ts index 4efb2a6e5c2..ee03475d811 100644 --- a/packages/mobile/src/components/share-drawer/utils.ts +++ b/packages/mobile/src/components/share-drawer/utils.ts @@ -1,5 +1,4 @@ import type { ShareContent } from '@audius/common/store' -import type { Nullable } from '@audius/common/utils' import { makeTwitterShareUrl } from '@audius/common/utils' import { audiusBackendInstance } from 'app/services/audius-backend-instance' @@ -36,17 +35,8 @@ export const getContentUrl = (content: ShareContent) => { } } -const getTwitterShareHandle = async ({ - handle, - twitterHandle -}: { - handle: string - twitterHandle: Nullable -}) => { - if (!twitterHandle) { - const socials = await audiusBackendInstance.getSocialHandles(handle) - return socials.twitterHandle ? `@${socials.twitterHandle}` : handle - } +const getTwitterShareHandle = async (handle: string) => { + const { twitterHandle } = await audiusBackendInstance.getSocialHandles(handle) return twitterHandle ? `@${twitterHandle}` : handle } @@ -55,39 +45,34 @@ export const getTwitterShareText = async (content: ShareContent) => { case 'track': { const { track: { title }, - artist: { handle, twitter_handle: twitterHandle } + artist: { handle } } = content - return messages.trackShareText( - title, - await getTwitterShareHandle({ handle, twitterHandle }) - ) + return messages.trackShareText(title, await getTwitterShareHandle(handle)) } case 'profile': { const { - profile: { handle, twitter_handle: twitterHandle } + profile: { handle } } = content - return messages.profileShareText( - await getTwitterShareHandle({ handle, twitterHandle }) - ) + return messages.profileShareText(await getTwitterShareHandle(handle)) } case 'album': { const { album: { playlist_name }, - artist: { handle, twitter_handle: twitterHandle } + artist: { handle } } = content return messages.albumShareText( playlist_name, - await getTwitterShareHandle({ handle, twitterHandle }) + await getTwitterShareHandle(handle) ) } case 'playlist': { const { playlist: { playlist_name }, - creator: { handle, twitter_handle: twitterHandle } + creator: { handle } } = content return messages.playlistShareText( playlist_name, - await getTwitterShareHandle({ handle, twitterHandle }) + await getTwitterShareHandle(handle) ) } case 'audioNftPlaylist': { diff --git a/packages/web/src/components/share-modal/utils.ts b/packages/web/src/components/share-modal/utils.ts index ce8e9eaea2b..ce5160af997 100644 --- a/packages/web/src/components/share-modal/utils.ts +++ b/packages/web/src/components/share-modal/utils.ts @@ -1,6 +1,5 @@ import { ShareToTwitter } from '@audius/common/models' import { ShareContent } from '@audius/common/store' -import { Nullable } from '@audius/common/utils' import { getTwitterHandleByUserHandle } from 'components/notification/Notification/utils' import { @@ -14,17 +13,8 @@ import { messages } from './messages' type ShareToTwitterEvent = Omit -const getTwitterShareHandle = async ({ - handle, - twitterHandle -}: { - handle: string - twitterHandle: Nullable -}) => { - if (!twitterHandle) { - const theTwitterHandle = await getTwitterHandleByUserHandle(handle) - return theTwitterHandle ? `@${theTwitterHandle}` : handle - } +const getTwitterShareHandle = async (handle: string) => { + const twitterHandle = await getTwitterHandleByUserHandle(handle) return twitterHandle ? `@${twitterHandle}` : handle } @@ -49,11 +39,11 @@ export const getTwitterShareText = async ( case 'track': { const { track: { title, permalink, track_id }, - artist: { handle, twitter_handle: twitterHandle } + artist: { handle } } = content twitterText = messageConfig.trackShareText( title, - await getTwitterShareHandle({ handle, twitterHandle }) + await getTwitterShareHandle(handle) ) link = fullTrackPage(permalink) analyticsEvent = { kind: 'track', id: track_id, url: link } @@ -61,10 +51,10 @@ export const getTwitterShareText = async ( } case 'profile': { const { - profile: { handle, user_id, twitter_handle: twitterHandle } + profile: { handle, user_id } } = content twitterText = messageConfig.profileShareText( - await getTwitterShareHandle({ handle, twitterHandle }) + await getTwitterShareHandle(handle) ) link = fullProfilePage(handle) analyticsEvent = { kind: 'profile', id: user_id, url: link } @@ -73,11 +63,11 @@ export const getTwitterShareText = async ( case 'album': { const { album: { playlist_name, playlist_id, permalink }, - artist: { handle, twitter_handle: twitterHandle } + artist: { handle } } = content twitterText = messageConfig.albumShareText( playlist_name, - await getTwitterShareHandle({ handle, twitterHandle }) + await getTwitterShareHandle(handle) ) link = fullCollectionPage( handle, @@ -92,11 +82,11 @@ export const getTwitterShareText = async ( case 'playlist': { const { playlist: { playlist_name, playlist_id, permalink, is_album }, - creator: { handle, twitter_handle: twitterHandle } + creator: { handle } } = content twitterText = messageConfig.playlistShareText( playlist_name, - await getTwitterShareHandle({ handle, twitterHandle }) + await getTwitterShareHandle(handle) ) link = fullCollectionPage( handle,