Skip to content
This repository has been archived by the owner on Oct 4, 2023. It is now read-only.

Commit

Permalink
[C-1557] Add TikTok to CompleteProfileWithSocial on desktop (#2341)
Browse files Browse the repository at this point in the history
* Add tiktok button in signup flow

* Add tiktok button to complete profile

* Style buttons

* Add import tile

* Add verified helper

* Convert things to typescript

* Fix types

* Disable feature flag and fix handle key

* Undo mobile changes

* Undo mobile changes pt 2

* Address pr comments
  • Loading branch information
sliptype authored Dec 5, 2022
1 parent 228b20e commit 552497f
Show file tree
Hide file tree
Showing 34 changed files with 1,224 additions and 931 deletions.
55 changes: 54 additions & 1 deletion packages/common/src/services/oauth/formatSocialProfile.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { InstagramProfile, TwitterProfile } from 'store/account/types'
import {
InstagramProfile,
TikTokProfile,
TwitterProfile
} from 'store/account/types'

export const MAX_HANDLE_LENGTH = 16
export const MAX_DISPLAY_NAME_LENGTH = 32
Expand Down Expand Up @@ -117,3 +121,52 @@ export const formatInstagramProfile = async (
requiresUserReview
}
}

export const formatTikTokProfile = async (
tikTokProfile: TikTokProfile,
resizeImage: (
image: File,
maxWidth?: number,
square?: boolean,
key?: string
) => Promise<File>
) => {
const getProfilePicture = async () => {
if (tikTokProfile.avatar_large_url) {
const imageBlob = await fetch(tikTokProfile.avatar_large_url).then((r) =>
r.blob()
)
const artworkFile = new File([imageBlob], 'Artwork', {
type: 'image/jpeg'
})
const file = await resizeImage(artworkFile)
const url = URL.createObjectURL(file)
return { url, file }
}

return undefined
}

const profilePicture = await getProfilePicture()

// Truncate to MAX_HANDLE_LENGTH characters because we don't support longer handles.
// If the user is verifed, they won't be able to claim the status if
// the handle doesn't match, so just pass through.
let requiresUserReview = false
if (tikTokProfile.display_name.length > MAX_HANDLE_LENGTH) {
requiresUserReview = true
if (!tikTokProfile.is_verified) {
tikTokProfile.display_name = tikTokProfile.display_name.slice(
0,
MAX_HANDLE_LENGTH
)
}
}

return {
profile: tikTokProfile,
profileImage: profilePicture,
profileBanner: undefined,
requiresUserReview
}
}
6 changes: 4 additions & 2 deletions packages/common/src/services/remote-config/feature-flags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ export enum FeatureFlags {
READ_ARTIST_PICK_FROM_DISCOVERY = 'read_artist_pick_from_discovery',
SHARE_TO_STORY = 'share_to_story',
READ_SUBSCRIBERS_FROM_DISCOVERY_ENABLED = 'read_subscribers_from_discovery_enabled',
MOBILE_WALLET_CONNECT = 'mobile_wallet_connect'
MOBILE_WALLET_CONNECT = 'mobile_wallet_connect',
COMPLETE_PROFILE_WITH_TIKTOK = 'complete_profile_with_tiktok'
}

type FlagDefaults = Record<FeatureFlags, boolean>
Expand Down Expand Up @@ -80,5 +81,6 @@ export const flagDefaults: FlagDefaults = {
[FeatureFlags.READ_ARTIST_PICK_FROM_DISCOVERY]: false,
[FeatureFlags.SHARE_TO_STORY]: false,
[FeatureFlags.READ_SUBSCRIBERS_FROM_DISCOVERY_ENABLED]: false,
[FeatureFlags.MOBILE_WALLET_CONNECT]: false
[FeatureFlags.MOBILE_WALLET_CONNECT]: false,
[FeatureFlags.COMPLETE_PROFILE_WITH_TIKTOK]: false
}
9 changes: 9 additions & 0 deletions packages/common/src/store/account/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@ export type TwitterProfile = {
profile_banner_url?: string
}

export type TikTokProfile = {
open_id: string
display_name: string
avatar_url?: string
avatar_large_url?: string
profile_deep_link: string
is_verified: string
}

export type AccountImage = { url: string; file: any }

export type NativeAccountImage = {
Expand Down
5 changes: 5 additions & 0 deletions packages/web/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
"@sentry/integrations": "6.16.1",
"@solana/spl-token": "0.1.8",
"@solana/web3.js": "1.53.0",
"@types/react-twitter-auth": "0.0.4",
"@walletconnect/web3-provider": "1.4.1",
"amplitude-js": "8.10.0",
"antd": "4.20.6",
Expand Down
22 changes: 21 additions & 1 deletion packages/web/src/common/store/pages/signon/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import {
AccountImage,
InstagramProfile,
TwitterProfile,
NativeAccountImage
NativeAccountImage,
TikTokProfile
} from '@audius/common'

import { UiErrorCode } from 'store/errors/actions'
Expand Down Expand Up @@ -43,6 +44,8 @@ export const SET_TWITTER_PROFILE = 'SIGN_ON/SET_TWITTER_PROFILE'
export const SET_TWITTER_PROFILE_ERROR = 'SIGN_ON/SET_TWITTER_PROFILE_ERROR'
export const SET_INSTAGRAM_PROFILE = 'SIGN_ON/SET_INSTAGRAM_PROFILE'
export const SET_INSTAGRAM_PROFILE_ERROR = 'SIGN_ON/SET_INSTAGRAM_PROFILE_ERROR'
export const SET_TIKTOK_PROFILE = 'SIGN_ON/SET_TIKTOK_PROFILE'
export const SET_TIKTOK_PROFILE_ERROR = 'SIGN_ON/SET_TIKTOK_PROFILE_ERROR'

export const SET_STATUS = 'SIGN_ON/SET_STATUS'
export const CONFIGURE_META_MASK = 'SIGN_ON/CONFIGURE_META_MASK'
Expand Down Expand Up @@ -308,6 +311,23 @@ export function setInstagramProfileError(error: string) {
return { type: SET_INSTAGRAM_PROFILE_ERROR, error }
}

export function setTikTokProfile(
tikTokId: string,
profile: TikTokProfile,
profileImage?: AccountImage | NativeAccountImage | null
) {
return {
type: SET_TIKTOK_PROFILE,
tikTokId,
profile,
profileImage
}
}

export function setTikTokProfileError(error: string) {
return { type: SET_TIKTOK_PROFILE_ERROR, error }
}

/**
* Follows users in signup flow after user is created
* @param userIds array of userIds to follow
Expand Down
6 changes: 5 additions & 1 deletion packages/web/src/common/store/pages/signon/errorSagas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import { ERROR_PAGE } from 'utils/route'
import * as signOnActions from './actions'

const noRedirectSet = new Set([
// Twitter failures are not fatal
// Social failures are not fatal
signOnActions.SET_TWITTER_PROFILE_ERROR,
signOnActions.SET_INSTAGRAM_PROFILE_ERROR,
signOnActions.SET_TIKTOK_PROFILE_ERROR,
// Sign in errors are never fatal
signOnActions.SIGN_IN_FAILED
])
Expand Down Expand Up @@ -61,6 +63,8 @@ export function* watchSignOnError() {
yield takeEvery(
[
signOnActions.SET_TWITTER_PROFILE_ERROR,
signOnActions.SET_INSTAGRAM_PROFILE_ERROR,
signOnActions.SET_TIKTOK_PROFILE_ERROR,
signOnActions.SIGN_UP_FAILED,
signOnActions.SIGN_UP_TIMEOUT,
signOnActions.SIGN_IN_FAILED
Expand Down
21 changes: 21 additions & 0 deletions packages/web/src/common/store/pages/signon/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
SET_VALUE_FIELD,
SET_TWITTER_PROFILE,
SET_INSTAGRAM_PROFILE,
SET_TIKTOK_PROFILE,
FETCH_FOLLOW_ARTISTS_SUCCEEDED,
SET_FOLLOW_ARTIST_CATEGORY,
VALIDATE_EMAIL,
Expand Down Expand Up @@ -59,6 +60,8 @@ const initialState = {
twitterScreenName: '',
instagramId: '',
instagramScreenName: '',
tikTokId: '',
tikTokScreenName: '',
profileImage: null, // Object with file blob & url
coverPhoto: null, // Object with file blob & url
status: 'editing', // 'editing', 'loading', 'success', or 'failure'
Expand Down Expand Up @@ -224,6 +227,24 @@ const actionsMap = {
verified: action.profile.is_verified
}
},
[SET_TIKTOK_PROFILE](state, action) {
return {
...state,
tikTokProfile: action.tikTokProfile,
name: {
value: action.profile.display_name || '',
status: 'editing',
error: ''
},
handle: {
...state.handle,
value: action.profile.display_name
},
tikTokScreenName: action.profile.display_name,
profileImage: action.profileImage || null,
verified: action.profile.is_verified
}
},
[VALIDATE_EMAIL](state, action) {
return {
...state,
Expand Down
17 changes: 17 additions & 0 deletions packages/web/src/common/store/pages/signon/sagas.js
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ function* validateHandle(action) {
const handleInUse = !isEmpty(user)

if (IS_PRODUCTION_BUILD || IS_PRODUCTION) {
// TODO: add tiktok here
const [twitterUserQuery, instagramUser] = yield all([
call(audiusBackendInstance.twitterHandle, handle),
call(getInstagramUser, handle, remoteConfigInstance)
Expand Down Expand Up @@ -426,6 +427,22 @@ function* signUp() {
}
}

// if (
// !signOn.useMetaMask &&
// signOn.tikTokId &&
// handle.toLowerCase() === (signOn.tikTokId || '').toLowerCase()
// ) {
// const { error } = yield call(
// audiusBackendInstance.associateTikTokAccount,
// handle.toLowerCase(),
// userId,
// handle
// )
// if (error) {
// yield put(signOnActions.setTikTokProfileError(error))
// }
// }

yield put(
identify(handle, {
name,
Expand Down
4 changes: 2 additions & 2 deletions packages/web/src/components/instagram-auth/InstagramAuth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ const igUserFields = [
'edge_follow'
]

type InstagramAuthProps = {
export type InstagramAuthProps = {
dialogWidth?: number
dialogHeight?: number
setProfileUrl: string
getUserUrl: string
onClick: () => void
onClick?: () => void
onSuccess: (uuid: string, profile: any) => void
onFailure: (error: any) => void
style?: object
Expand Down
26 changes: 8 additions & 18 deletions packages/web/src/components/instagram-button/InstagramButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,17 @@ import cn from 'classnames'
import { ReactComponent as IconInstagram } from 'assets/img/iconInstagram.svg'
import { audiusBackendInstance } from 'services/audius-backend/audius-backend-instance'

import InstagramAuth from '../instagram-auth/InstagramAuth'
import InstagramAuth, {
InstagramAuthProps
} from '../instagram-auth/InstagramAuth'

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

type InstagramAuthButtonProps = {
onSuccess?: (uuid: string, profile: any) => void
onFailure?: (error: any) => void
style?: object
disabled?: boolean
/**
* Whether or not the success of this instagram auth
* depends on fetching metadata or not.
* Generally speaking, fetching metadata is not reliable,
* so if the purpose of this auth is just verification
* that the user has OAuthed, not to pull specific data,
* set this flag to false.
* Without metadata, instagram gives you very few fields:
* https://developers.facebook.com/docs/instagram-basic-display-api/reference/user
*/
requiresProfileMetadata?: boolean
} & InstagramButtonProps
type InstagramAuthButtonProps = Pick<
InstagramAuthProps,
'onSuccess' | 'onFailure' | 'style' | 'disabled' | 'requiresProfileMetadata'
> &
InstagramButtonProps

type InstagramButtonProps = {
text?: string
Expand Down
Empty file.
22 changes: 22 additions & 0 deletions packages/web/src/components/tiktok-button/TikTokButton.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
.button {
background-color: #fe2c55;
}

.button.includeHoverAnimations:hover:enabled {
background-color: #fe5676;
}

.button.includeHoverAnimations:active:enabled {
background-color: #e5294d;
}

.button .text {
font-size: var(--font-l);
font-weight: var(--font-bold);
color: var(--static-white);
color: 'black';
}

.button .icon path {
fill: var(--static-white);
}
33 changes: 33 additions & 0 deletions packages/web/src/components/tiktok-button/TikTokButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import {
Button,
ButtonSize,
ButtonType,
IconTikTokInverted
} from '@audius/stems'
import cn from 'classnames'

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

type TikTokButtonProps = {
text?: string
textClassName?: string
iconClassName?: string
onClick?: () => void
className?: string
}

export const TikTokButton = (props: TikTokButtonProps) => {
const { text, className, onClick, textClassName, iconClassName } = props
return (
<Button
type={ButtonType.PRIMARY_ALT}
leftIcon={<IconTikTokInverted className={styles.icon} />}
className={cn(styles.button, styles.includeHoverAnimations, className)}
textClassName={cn(styles.text, textClassName)}
iconClassName={cn(styles.icon, iconClassName)}
size={ButtonSize.MEDIUM}
text={text}
onClick={onClick ?? (() => {})}
/>
)
}
Loading

0 comments on commit 552497f

Please sign in to comment.