Skip to content

Commit

Permalink
[C-3595 C-3574] Fix Upload share-banner share options (#7136)
Browse files Browse the repository at this point in the history
  • Loading branch information
dylanjeffers authored Jan 10, 2024
1 parent 31e589c commit 264bbe9
Show file tree
Hide file tree
Showing 8 changed files with 167 additions and 38 deletions.
4 changes: 2 additions & 2 deletions packages/common/src/store/ui/share-modal/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ type ShareAudioNftPlaylistContent = {
user: User
}

export type ShareModalContent =
export type ShareContent =
| ShareTrackContent
| ShareProfileContent
| ShareAlbumContent
Expand All @@ -48,7 +48,7 @@ export type ShareModalContent =

export type ShareModalState = {
source: Nullable<ShareSource>
content: Nullable<ShareModalContent>
content: Nullable<ShareContent>
}

type RequestOpenPayload = { source: ShareSource } & (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ type ShareToStoryStickerProps = {
| 'track_id'
| '_cover_art_sizes'
>
user?: Pick<User, 'creator_node_endpoint'>
artist: Pick<User, 'user_id' | 'name' | 'is_verified'>
style?: StyleProp<ViewStyle>
/** Called once the image loads successfully */
Expand Down Expand Up @@ -81,7 +80,6 @@ const useStyles = makeStyles(({ palette, spacing }) => ({

export const ShareToStorySticker = ({
track,
user,
artist,
style,
onLoad,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useCallback, useMemo, useRef, useState } from 'react'
import EventEmitter from 'events'
import path from 'path'

import type { Color, Nullable, ShareModalContent } from '@audius/common'
import type { Color, Nullable, ShareContent } from '@audius/common'
import {
encodeHashId,
ErrorLevel,
Expand Down Expand Up @@ -120,7 +120,7 @@ export const useShareToStory = ({
content,
viewShotRef
}: {
content: Nullable<ShareModalContent>
content: Nullable<ShareContent>
viewShotRef: React.RefObject<ViewShot>
}) => {
const { toast } = useToast()
Expand Down
8 changes: 4 additions & 4 deletions packages/mobile/src/components/share-drawer/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ShareModalContent } from '@audius/common'
import type { ShareContent } from '@audius/common'
import { makeTwitterShareUrl } from '@audius/common'

import { audiusBackendInstance } from 'app/services/audius-backend-instance'
Expand All @@ -10,7 +10,7 @@ import {

import { messages } from './messages'

export const getContentUrl = (content: ShareModalContent) => {
export const getContentUrl = (content: ShareContent) => {
switch (content.type) {
case 'track': {
const { track } = content
Expand Down Expand Up @@ -40,7 +40,7 @@ const getShareHandle = async (handle: string) => {
return twitterHandle ? `@${twitterHandle}` : handle
}

export const getTwitterShareText = async (content: ShareModalContent) => {
export const getTwitterShareText = async (content: ShareContent) => {
switch (content.type) {
case 'track': {
const {
Expand Down Expand Up @@ -81,7 +81,7 @@ export const getTwitterShareText = async (content: ShareModalContent) => {
}
}

export const getTwitterShareUrl = async (content: ShareModalContent) => {
export const getTwitterShareUrl = async (content: ShareContent) => {
const url = getContentUrl(content)
const shareText = await getTwitterShareText(content)
return makeTwitterShareUrl(url ?? null, shareText)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
left: 0;
position: absolute;
top: 0;
transition: width 0.3s ease-in-out;
}

.labels {
Expand Down
29 changes: 21 additions & 8 deletions packages/web/src/components/share-modal/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ShareToTwitter, ShareModalContent } from '@audius/common'
import { ShareToTwitter, ShareContent } from '@audius/common'

import { getTwitterHandleByUserHandle } from 'components/notification/Notification/utils'
import {
Expand All @@ -17,9 +17,19 @@ const getShareHandle = async (handle: string) => {
return twitterHandle ? `@${twitterHandle}` : handle
}

export type ShareMessageConfig = Pick<
typeof messages,
| 'profileShareText'
| 'trackShareText'
| 'playlistShareText'
| 'albumShareText'
| 'audioNftPlaylistShareText'
>

export const getTwitterShareText = async (
content: ShareModalContent,
isPlaylistOwner = false
content: ShareContent,
isPlaylistOwner = false,
messageConfig: ShareMessageConfig = messages
) => {
let twitterText = ''
let link = ''
Expand All @@ -30,7 +40,10 @@ export const getTwitterShareText = async (
track: { title, permalink, track_id },
artist: { handle }
} = content
twitterText = messages.trackShareText(title, await getShareHandle(handle))
twitterText = messageConfig.trackShareText(
title,
await getShareHandle(handle)
)
link = fullTrackPage(permalink)
analyticsEvent = { kind: 'track', id: track_id, url: link }
break
Expand All @@ -39,7 +52,7 @@ export const getTwitterShareText = async (
const {
profile: { handle, user_id }
} = content
twitterText = messages.profileShareText(await getShareHandle(handle))
twitterText = messageConfig.profileShareText(await getShareHandle(handle))
link = fullProfilePage(handle)
analyticsEvent = { kind: 'profile', id: user_id, url: link }
break
Expand All @@ -49,7 +62,7 @@ export const getTwitterShareText = async (
album: { playlist_name, playlist_id, permalink },
artist: { handle }
} = content
twitterText = messages.albumShareText(
twitterText = messageConfig.albumShareText(
playlist_name,
await getShareHandle(handle)
)
Expand All @@ -68,7 +81,7 @@ export const getTwitterShareText = async (
playlist: { playlist_name, playlist_id, permalink, is_album },
creator: { handle }
} = content
twitterText = messages.playlistShareText(
twitterText = messageConfig.playlistShareText(
playlist_name,
await getShareHandle(handle)
)
Expand All @@ -86,7 +99,7 @@ export const getTwitterShareText = async (
const {
user: { handle, name, user_id }
} = content
twitterText = messages.audioNftPlaylistShareText(
twitterText = messageConfig.audioNftPlaylistShareText(
isPlaylistOwner ? 'my' : name
)
link = fullAudioNftPlaylistPage(handle)
Expand Down
154 changes: 136 additions & 18 deletions packages/web/src/pages/upload-page/components/ShareBanner.tsx
Original file line number Diff line number Diff line change
@@ -1,57 +1,175 @@
import { useCallback, useContext } from 'react'

import { Name, ShareSource, User, usersSocialActions } from '@audius/common'
import {
Collection,
Name,
ShareContent,
ShareSource,
Track,
UploadType,
User,
accountSelectors,
tracksSocialActions,
usersSocialActions
} from '@audius/common'
import { Button, ButtonType, IconLink, IconTwitterBird } from '@audius/stems'
import { useDispatch } from 'react-redux'

import backgroundPlaceholder from 'assets/img/1-Concert-3-1.jpg'
import { make, useRecord } from 'common/store/analytics/actions'
import { getTwitterShareText } from 'components/share-modal/utils'
import {
ShareMessageConfig,
getTwitterShareText
} from 'components/share-modal/utils'
import { ToastContext } from 'components/toast/ToastContext'
import { Text } from 'components/typography'
import { copyLinkToClipboard } from 'utils/clipboardUtil'
import { SHARE_TOAST_TIMEOUT_MILLIS } from 'utils/constants'
import { useSelector } from 'utils/reducer'
import { collectionPage } from 'utils/route'
import { openTwitterLink } from 'utils/tweet'

import styles from './ShareBanner.module.css'

const { shareUser } = usersSocialActions
const { shareTrack } = tracksSocialActions

const { getAccountUser } = accountSelectors

const uploadTypeMap = {
[UploadType.INDIVIDUAL_TRACK]: 'new track',
[UploadType.INDIVIDUAL_TRACKS]: 'profile',
[UploadType.PLAYLIST]: 'new playlist',
[UploadType.ALBUM]: 'new album'
}

const messages = {
uploadComplete: 'Your Upload is Complete!',
shareText: 'Share your profile with your fans',
copyProfileToast: 'Copied Link to Profile',
shareText: (uploadType: UploadType) =>
`Share your ${uploadTypeMap[uploadType]} with your fans`,
twitterButtonText: 'Twitter',
copyLinkButtonText: 'Copy Link'
copyLinkButtonText: 'Copy Link',
copyLinkToast: (uploadType: UploadType) =>
`Copied Link to your ${uploadTypeMap[uploadType]}`
}

const twitterSharMessages: ShareMessageConfig = {
profileShareText: () => 'Check out my new tracks on @audius #Audius',
trackShareText: (title: string) =>
`Check out my new track ${title} on @audius #Audius`,
albumShareText: (albumName: string) =>
`Check out my new album, ${albumName} on @audius #Audius`,
playlistShareText: (playlistName: string) =>
`Check out my new playlist, ${playlistName} on @audius #Audius`,
audioNftPlaylistShareText: () => ''
}

type ShareBannerProps = {
user: User
uploadType: UploadType
}

export const ShareBanner = (props: ShareBannerProps) => {
const { user } = props
const { uploadType } = props
const accountUser = useSelector(getAccountUser) as User
const upload = useSelector((state) => state.upload)
const dispatch = useDispatch()
const { toast } = useContext(ToastContext)
const record = useRecord()

const handleTwitterShare = useCallback(async () => {
const { twitterText, link, analyticsEvent } = await getTwitterShareText({
type: 'profile',
profile: user
})
let twitterShareContent: ShareContent

switch (uploadType) {
case UploadType.INDIVIDUAL_TRACK: {
const track = upload.tracks?.[0]
if (!track) return

twitterShareContent = {
type: 'track',
track: track.metadata as unknown as Track,
artist: accountUser
}
break
}

case UploadType.ALBUM: {
const album = upload.metadata as Collection
if (!album) return

twitterShareContent = {
type: 'album',
album,
artist: accountUser
}
break
}

case UploadType.PLAYLIST: {
const playlist = upload.metadata as Collection
if (!playlist) return

twitterShareContent = {
type: 'playlist',
playlist,
creator: accountUser
}
break
}

case UploadType.INDIVIDUAL_TRACKS:
default: {
twitterShareContent = {
type: 'profile',
profile: accountUser
}
break
}
}

const { twitterText, link, analyticsEvent } = await getTwitterShareText(
twitterShareContent,
true,
twitterSharMessages
)
openTwitterLink(link, twitterText)
record(
make(Name.SHARE_TO_TWITTER, {
source: ShareSource.UPLOAD,
...analyticsEvent
})
)
}, [record, user])
}, [uploadType, record, upload.tracks, upload.metadata, accountUser])

const handleCopyLink = useCallback(() => {
switch (uploadType) {
case UploadType.INDIVIDUAL_TRACK: {
const trackId = upload.tracks?.[0].metadata.track_id
if (!trackId) return
dispatch(shareTrack(trackId, ShareSource.UPLOAD))
break
}
case UploadType.INDIVIDUAL_TRACKS: {
dispatch(shareUser(accountUser.user_id, ShareSource.UPLOAD))
break
}
// We don't have access to the playlist_id so we manually copy to clipboard
case UploadType.ALBUM:
case UploadType.PLAYLIST: {
const collectionLink = collectionPage(
accountUser.handle,
upload.metadata?.playlist_name,
upload.completionId,
null,
uploadType === UploadType.ALBUM
)

copyLinkToClipboard(collectionLink)
break
}
}

const handleCopyTrackLink = useCallback(() => {
dispatch(shareUser(user.user_id, ShareSource.UPLOAD))
toast(messages.copyProfileToast, SHARE_TOAST_TIMEOUT_MILLIS)
}, [dispatch, toast, user.user_id])
toast(messages.copyLinkToast(uploadType), SHARE_TOAST_TIMEOUT_MILLIS)
}, [uploadType, toast, upload, dispatch, accountUser])

return (
<div
Expand All @@ -64,7 +182,7 @@ export const ShareBanner = (props: ShareBannerProps) => {
{messages.uploadComplete}
</Text>
<Text variant='heading' size='medium' color='darkmodeStaticWhite'>
{messages.shareText}
{messages.shareText(uploadType)}
</Text>
<div className={styles.buttonContainer}>
<Button
Expand All @@ -81,7 +199,7 @@ export const ShareBanner = (props: ShareBannerProps) => {
<Button
fullWidth
leftIcon={<IconLink />}
onClick={handleCopyTrackLink}
onClick={handleCopyLink}
text={
<Text variant='title' size='large' color='secondary'>
{messages.copyLinkButtonText}
Expand Down
3 changes: 1 addition & 2 deletions packages/web/src/pages/upload-page/pages/FinishPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@ type FinishPageProps = {
export const FinishPage = (props: FinishPageProps) => {
const { formState, onContinue } = props
const { tracks, uploadType } = formState
const accountUser = useSelector(getAccountUser)
const upload = useSelector((state: CommonState) => state.upload)
const user = useSelector(getAccountUser)
const fullUploadPercent = useSelector(getCombinedUploadPercentage)
Expand Down Expand Up @@ -192,7 +191,7 @@ export const FinishPage = (props: FinishPageProps) => {

return (
<div className={styles.page}>
{uploadComplete ? <ShareBanner user={accountUser!} /> : null}
{uploadComplete ? <ShareBanner uploadType={uploadType} /> : null}
<Tile className={styles.uploadProgress} elevation='mid'>
<div className={styles.uploadHeader}>
<div className={styles.headerInfo}>
Expand Down

0 comments on commit 264bbe9

Please sign in to comment.