From 2b555f181348f866c0ebfc25812ded3b16e81811 Mon Sep 17 00:00:00 2001 From: Dylan Jeffers Date: Wed, 1 May 2024 23:51:11 -0700 Subject: [PATCH] [C-4333] Migrate follow-users to new sign-up flow --- .../common/src/store/pages/feed/actions.ts | 29 +------ .../common/src/store/pages/feed/reducer.ts | 11 --- .../common/src/store/pages/feed/selectors.ts | 12 --- .../web/src/common/store/pages/feed/sagas.ts | 24 +----- .../follow-artist-card}/FollowArtistCard.tsx | 2 +- .../selectArtistsPreviewContext.tsx | 0 .../src/pages/feed-page/FeedPageProvider.jsx | 11 +-- .../{EmptyFeed.jsx => EmptyFeed.tsx} | 52 +++--------- .../feed-page/components/FollowUsers.jsx | 80 ------------------ .../components/FollowUsers.module.css | 18 +--- .../feed-page/components/FollowUsers.tsx | 82 +++++++++++++++++++ .../components/desktop/FeedPageContent.tsx | 16 +--- packages/web/src/pages/feed-page/types.ts | 8 +- .../sign-up-page/pages/SelectArtistsPage.tsx | 10 +-- 14 files changed, 109 insertions(+), 246 deletions(-) rename packages/web/src/{pages/sign-up-page/components => components/follow-artist-card}/FollowArtistCard.tsx (98%) rename packages/web/src/{pages/sign-up-page/utils => components/follow-artist-card}/selectArtistsPreviewContext.tsx (100%) rename packages/web/src/pages/feed-page/components/{EmptyFeed.jsx => EmptyFeed.tsx} (54%) delete mode 100644 packages/web/src/pages/feed-page/components/FollowUsers.jsx create mode 100644 packages/web/src/pages/feed-page/components/FollowUsers.tsx diff --git a/packages/common/src/store/pages/feed/actions.ts b/packages/common/src/store/pages/feed/actions.ts index 81ac0f12926..7e3edd9408b 100644 --- a/packages/common/src/store/pages/feed/actions.ts +++ b/packages/common/src/store/pages/feed/actions.ts @@ -1,53 +1,26 @@ import { FeedFilter } from '~/models/FeedFilter' import { ID } from '~/models/Identifiers' -export const FETCH_SUGGESTED_FOLLOW_USERS = 'FEED/FETCH_SUGGESTED_FOLLOW_USERS' export const FOLLOW_USERS = 'FEED/FOLLOW_USERS' -export const SET_SUGGESTED_FOLLOWS = 'FEED/SET_SUGGESTED_FOLLOWS' export const SET_FEED_FILTER = 'FEED/SET_FEED_FILTER' -export type FetchSuggestedFollowUsersAction = { - type: typeof FETCH_SUGGESTED_FOLLOW_USERS -} - export type FollowUsersAction = { type: typeof FOLLOW_USERS userIds: ID[] } -export type SetSuggestedFollowsAction = { - type: typeof SET_SUGGESTED_FOLLOWS - userIds: ID[] -} - export type SetFeedFilterAction = { type: typeof SET_FEED_FILTER filter: FeedFilter } -export type FeedPageAction = - | FetchSuggestedFollowUsersAction - | FollowUsersAction - | SetSuggestedFollowsAction - | SetFeedFilterAction - -export const fetchSuggestedFollowUsers = - (): FetchSuggestedFollowUsersAction => ({ - type: FETCH_SUGGESTED_FOLLOW_USERS - }) +export type FeedPageAction = FollowUsersAction | SetFeedFilterAction export const followUsers = (userIds: ID[]): FollowUsersAction => ({ type: FOLLOW_USERS, userIds }) -export const setSuggestedFollows = ( - userIds: ID[] -): SetSuggestedFollowsAction => ({ - type: SET_SUGGESTED_FOLLOWS, - userIds -}) - export const setFeedFilter = (filter: FeedFilter): SetFeedFilterAction => ({ type: SET_FEED_FILTER, filter diff --git a/packages/common/src/store/pages/feed/reducer.ts b/packages/common/src/store/pages/feed/reducer.ts index 343d966ca80..0f870e4f210 100644 --- a/packages/common/src/store/pages/feed/reducer.ts +++ b/packages/common/src/store/pages/feed/reducer.ts @@ -1,8 +1,6 @@ import { LineupActions, asLineup } from '~/store/lineup/reducer' import { - SET_SUGGESTED_FOLLOWS, SET_FEED_FILTER, - SetSuggestedFollowsAction, SetFeedFilterAction, FeedPageAction } from '~/store/pages/feed/actions' @@ -22,15 +20,6 @@ const initialState = { } const actionsMap = { - [SET_SUGGESTED_FOLLOWS]( - state: FeedPageState, - action: SetSuggestedFollowsAction - ) { - return { - ...state, - suggestedFollows: action.userIds - } - }, [SET_FEED_FILTER](state: FeedPageState, action: SetFeedFilterAction) { return { ...state, diff --git a/packages/common/src/store/pages/feed/selectors.ts b/packages/common/src/store/pages/feed/selectors.ts index a7af94dcb88..4229cd8ca35 100644 --- a/packages/common/src/store/pages/feed/selectors.ts +++ b/packages/common/src/store/pages/feed/selectors.ts @@ -1,6 +1,5 @@ import { getUsers } from '~/store/cache/users/selectors' import { CommonState } from '~/store/commonStore' -import { createShallowSelector } from '~/utils/selectorHelpers' export const getSuggestedFollows = (state: CommonState) => state.pages.feed.suggestedFollows @@ -11,14 +10,3 @@ export const getFeedFilter = (state: CommonState) => state.pages.feed.feedFilter export const getSuggestedFollowUsers = (state: CommonState) => getUsers(state, { ids: getSuggestedFollows(state) }) - -export const makeGetSuggestedFollows = () => { - return createShallowSelector( - [getSuggestedFollowUsers, getSuggestedFollows], - (users, followIds) => { - return followIds - .map((id) => users[id]) - .filter((user) => !!user && !user.is_deactivated) - } - ) -} diff --git a/packages/web/src/common/store/pages/feed/sagas.ts b/packages/web/src/common/store/pages/feed/sagas.ts index 30c90f2849c..6743cf74b2b 100644 --- a/packages/web/src/common/store/pages/feed/sagas.ts +++ b/packages/web/src/common/store/pages/feed/sagas.ts @@ -7,21 +7,8 @@ import { import { getErrorMessage } from '@audius/common/utils' import { call, put, take, fork, takeEvery } from 'redux-saga/effects' -import { fetchUsers } from 'common/store/cache/users/sagas' import feedSagas from 'common/store/pages/feed/lineup/sagas' -import { fetchSuggestedFollowUserIds } from 'common/store/pages/signon/sagas' -import { waitForRead, waitForWrite } from 'utils/sagaHelpers' - -function* fetchSuggestedFollowUsers() { - yield call(waitForRead) - try { - const userIds: ID[] = yield call(fetchSuggestedFollowUserIds) - yield put(discoverActions.setSuggestedFollows(userIds)) - yield call(fetchUsers, userIds) - } catch (error) { - console.error(getErrorMessage(error)) - } -} +import { waitForWrite } from 'utils/sagaHelpers' function* waitForFollow(userIds: ID[]) { const usersConfirmed = Array.from(Array(userIds.length)).map(() => false) @@ -55,17 +42,10 @@ function* followUsers(action: ReturnType) { } } -function* watchFetchSuggestedFollowUsers() { - yield takeEvery( - discoverActions.FETCH_SUGGESTED_FOLLOW_USERS, - fetchSuggestedFollowUsers - ) -} - function* watchFollowUsers() { yield takeEvery(discoverActions.FOLLOW_USERS, followUsers) } export default function sagas() { - return [...feedSagas(), watchFetchSuggestedFollowUsers, watchFollowUsers] + return [...feedSagas(), watchFollowUsers] } diff --git a/packages/web/src/pages/sign-up-page/components/FollowArtistCard.tsx b/packages/web/src/components/follow-artist-card/FollowArtistCard.tsx similarity index 98% rename from packages/web/src/pages/sign-up-page/components/FollowArtistCard.tsx rename to packages/web/src/components/follow-artist-card/FollowArtistCard.tsx index 31f1f0d59a3..26e75513c20 100644 --- a/packages/web/src/pages/sign-up-page/components/FollowArtistCard.tsx +++ b/packages/web/src/components/follow-artist-card/FollowArtistCard.tsx @@ -28,7 +28,7 @@ import Skeleton from 'components/skeleton/Skeleton' import { useCoverPhoto } from 'hooks/useCoverPhoto' import { useMedia } from 'hooks/useMedia' -import { SelectArtistsPreviewContext } from '../utils/selectArtistsPreviewContext' +import { SelectArtistsPreviewContext } from './selectArtistsPreviewContext' type FollowArtistTileProps = { user: UserMetadata diff --git a/packages/web/src/pages/sign-up-page/utils/selectArtistsPreviewContext.tsx b/packages/web/src/components/follow-artist-card/selectArtistsPreviewContext.tsx similarity index 100% rename from packages/web/src/pages/sign-up-page/utils/selectArtistsPreviewContext.tsx rename to packages/web/src/components/follow-artist-card/selectArtistsPreviewContext.tsx diff --git a/packages/web/src/pages/feed-page/FeedPageProvider.jsx b/packages/web/src/pages/feed-page/FeedPageProvider.jsx index b56e0cf56f1..a56f8d7122d 100644 --- a/packages/web/src/pages/feed-page/FeedPageProvider.jsx +++ b/packages/web/src/pages/feed-page/FeedPageProvider.jsx @@ -24,8 +24,7 @@ import { useIsMobile } from 'hooks/useIsMobile' import { getPathname, TRENDING_PAGE } from 'utils/route' const { makeGetCurrent } = queueSelectors const { getPlaying, getBuffering } = playerSelectors -const { getDiscoverFeedLineup, makeGetSuggestedFollows, getFeedFilter } = - feedPageSelectors +const { getDiscoverFeedLineup, getFeedFilter } = feedPageSelectors const { makeGetLineupMetadatas } = lineupSelectors const getHasAccount = accountSelectors.getHasAccount @@ -89,9 +88,6 @@ class FeedPageProvider extends PureComponent { feedIsMain: this.props.feedIsMain, feed: this.props.feed, - fetchSuggestedFollowUsers: this.props.fetchSuggestedFollowUsers, - followUsers: this.props.followUsers, - suggestedFollows: this.props.suggestedFollows, refreshFeedInView: this.props.refreshFeedInView, hasAccount: this.props.hasAccount, goToSignUp: this.goToSignUp, @@ -118,13 +114,11 @@ class FeedPageProvider extends PureComponent { const makeMapStateToProps = () => { const getCurrentQueueItem = makeGetCurrent() - const getSuggestedFollows = makeGetSuggestedFollows() const getFeedLineup = makeGetLineupMetadatas(getDiscoverFeedLineup) const mapStateToProps = (state) => ({ hasAccount: getHasAccount(state), feed: getFeedLineup(state), - suggestedFollows: getSuggestedFollows(state), currentQueueItem: getCurrentQueueItem(state), playing: getPlaying(state), buffering: getBuffering(state), @@ -137,11 +131,8 @@ const mapDispatchToProps = (dispatch) => ({ dispatch, openSignOn: (signIn) => dispatch(openSignOn(signIn)), resetFeedLineup: () => dispatch(feedActions.reset()), - fetchSuggestedFollowUsers: () => - dispatch(discoverPageAction.fetchSuggestedFollowUsers()), goToRoute: (route) => dispatch(pushRoute(route)), replaceRoute: (route) => dispatch(replaceRoute(route)), - followUsers: (userIds) => dispatch(discoverPageAction.followUsers(userIds)), setFeedFilter: (filter) => dispatch(discoverPageAction.setFeedFilter(filter)), // Feed Lineup Actions diff --git a/packages/web/src/pages/feed-page/components/EmptyFeed.jsx b/packages/web/src/pages/feed-page/components/EmptyFeed.tsx similarity index 54% rename from packages/web/src/pages/feed-page/components/EmptyFeed.jsx rename to packages/web/src/pages/feed-page/components/EmptyFeed.tsx index 82523777071..67e59cc9f87 100644 --- a/packages/web/src/pages/feed-page/components/EmptyFeed.jsx +++ b/packages/web/src/pages/feed-page/components/EmptyFeed.tsx @@ -1,20 +1,20 @@ -import { memo } from 'react' - +import { accountSelectors } from '@audius/common/store' import { Button } from '@audius/harmony' import cn from 'classnames' -import PropTypes from 'prop-types' +import { Link } from 'react-router-dom' + +import { useSelector } from 'utils/reducer' +import { SIGN_UP_PAGE } from 'utils/route' import styles from './EmptyFeed.module.css' import FollowArtists from './FollowUsers' -const messages = { - noFollowers: `Oops! There's nothing here.` -} +const EmptyFeed = () => { + const hasAccount = useSelector(accountSelectors.getHasAccount) -const EmptyFeed = (props) => { return (
- {props.hasAccount ? null : ( + {hasAccount ? null : (
{`You'll Need An Account Before You Can Use Your Feed!`} @@ -23,18 +23,8 @@ const EmptyFeed = (props) => { )}
- {props.hasAccount ? ( - - {messages.noFollowers}{' '} - - - } - fetchFollowUsers={props.fetchFollowUsers} - followUsers={props.followUsers} - users={props.suggestedFollows} - /> + {hasAccount ? ( + ) : ( <>
@@ -53,8 +43,8 @@ const EmptyFeed = (props) => {
and much more!
- )} @@ -64,20 +54,4 @@ const EmptyFeed = (props) => { ) } -EmptyFeed.propTypes = { - hasAccount: PropTypes.bool, - onClick: PropTypes.func, - fetchFollowUsers: PropTypes.func, - followUsers: PropTypes.func, - suggestedFollows: PropTypes.arrayOf( - PropTypes.shape({ - user_id: PropTypes.number, - name: PropTypes.string, - handle: PropTypes.string, - is_verified: PropTypes.bool, - follower_count: PropTypes.number - }) - ) -} - -export default memo(EmptyFeed) +export default EmptyFeed diff --git a/packages/web/src/pages/feed-page/components/FollowUsers.jsx b/packages/web/src/pages/feed-page/components/FollowUsers.jsx deleted file mode 100644 index 50705ecc632..00000000000 --- a/packages/web/src/pages/feed-page/components/FollowUsers.jsx +++ /dev/null @@ -1,80 +0,0 @@ -import { useState, useEffect } from 'react' - -import { Button, IconUserFollow as IconFollow } from '@audius/harmony' -import cn from 'classnames' -import PropTypes from 'prop-types' - -import UserCard from 'components/card-legacy/UserCard' - -import styles from './FollowUsers.module.css' - -const messages = { - cta: `Let’s fix that by following some of these artists!` -} - -const FollowUsers = (props) => { - const { fetchFollowUsers } = props - - useEffect(() => { - fetchFollowUsers() - }, [fetchFollowUsers]) - - const [followUsers, setFollowUser] = useState([]) - const disabled = followUsers.length === 0 - - const onUserClick = (userId) => () => { - if (followUsers.includes(userId)) { - setFollowUser(followUsers.filter((u) => u !== userId)) - } else { - setFollowUser(followUsers.concat(userId)) - } - } - - const onFollowUsers = () => { - if (followUsers.length > 0) { - props.followUsers(followUsers) - } - } - - return ( -
-
-
{props.header}
-
{messages.cta}
-
-
- {props.users.map((user, idx) => ( - - ))} -
-
- -
-
- ) -} - -FollowUsers.propTypes = { - header: PropTypes.oneOfType([PropTypes.string, PropTypes.element]), - followUsers: PropTypes.func, - users: PropTypes.arrayOf(PropTypes.object) -} - -export default FollowUsers diff --git a/packages/web/src/pages/feed-page/components/FollowUsers.module.css b/packages/web/src/pages/feed-page/components/FollowUsers.module.css index edd184e3e72..d0b3c9f3c93 100644 --- a/packages/web/src/pages/feed-page/components/FollowUsers.module.css +++ b/packages/web/src/pages/feed-page/components/FollowUsers.module.css @@ -4,26 +4,12 @@ font-size: var(--harmony-font-m); font-weight: var(--harmony-font-medium); line-height: 26px; + text-align: center; margin-bottom: 24px; } -.cardsContainer { - margin: 0px -8px 8px; - display: inline-flex; - justify-content: center; - width: 100%; - flex-wrap: wrap; - margin-bottom: 8px; -} - -.userCard { - margin: 0px 7px 16px; - max-width: 168px !important; - flex: 1 0 168px; - width: auto !important; -} - .buttonContainer { + margin-top: var(--harmony-spacing-m); width: 100%; display: inline-flex; justify-content: center; diff --git a/packages/web/src/pages/feed-page/components/FollowUsers.tsx b/packages/web/src/pages/feed-page/components/FollowUsers.tsx new file mode 100644 index 00000000000..f67aaeccd4d --- /dev/null +++ b/packages/web/src/pages/feed-page/components/FollowUsers.tsx @@ -0,0 +1,82 @@ +import { useCallback } from 'react' + +import { useGetFeaturedArtists } from '@audius/common/api' +import { feedPageActions } from '@audius/common/store' +import { Button, Flex, IconUserFollow as IconFollow } from '@audius/harmony' +import { Form, Formik } from 'formik' +import { useDispatch } from 'react-redux' + +import { FollowArtistCard } from 'components/follow-artist-card/FollowArtistCard' +import { SelectArtistsPreviewContextProvider } from 'components/follow-artist-card/selectArtistsPreviewContext' + +import styles from './FollowUsers.module.css' + +const messages = { + cta: `Let’s fix that by following some of these artists!`, + noFollowers: `Oops! There's nothing here.` +} + +type FollowUsersValues = { + selectedArtists: string[] +} + +const initialValues: FollowUsersValues = { + selectedArtists: [] +} + +const FollowUsers = () => { + const dispatch = useDispatch() + + const { data: featuredArtists } = useGetFeaturedArtists(undefined) + + const handleSubmit = useCallback( + (values: FollowUsersValues) => { + const { selectedArtists } = values + const followUsers = selectedArtists.map((id) => parseInt(id)) + dispatch(feedPageActions.followUsers(followUsers)) + }, + [dispatch] + ) + + return ( + + + {({ values }) => ( +
+
+
+ {messages.noFollowers}{' '} + +
+
{messages.cta}
+
+ + {featuredArtists?.map((artist) => ( + + ))} + +
+ +
+ + )} +
+
+ ) +} + +export default FollowUsers diff --git a/packages/web/src/pages/feed-page/components/desktop/FeedPageContent.tsx b/packages/web/src/pages/feed-page/components/desktop/FeedPageContent.tsx index 710545945a1..b694837c76c 100644 --- a/packages/web/src/pages/feed-page/components/desktop/FeedPageContent.tsx +++ b/packages/web/src/pages/feed-page/components/desktop/FeedPageContent.tsx @@ -27,12 +27,6 @@ const FeedPageContent = ({ feedDescription, feedIsMain, feed, - fetchSuggestedFollowUsers, - followUsers, - suggestedFollows, - hasAccount, - goToTrending, - goToSignUp, setFeedInView, loadMoreFeed, playFeedTrack, @@ -97,15 +91,7 @@ const FeedPageContent = ({ header={header} > - } + emptyElement={} endOfLineup={} key='feed' showFeedTipTile={!isUSDCEnabled} diff --git a/packages/web/src/pages/feed-page/types.ts b/packages/web/src/pages/feed-page/types.ts index 6d34054cacd..f094baa6c0b 100644 --- a/packages/web/src/pages/feed-page/types.ts +++ b/packages/web/src/pages/feed-page/types.ts @@ -1,4 +1,4 @@ -import { FeedFilter, ID, UID, Lineup, User } from '@audius/common/models' +import { FeedFilter, ID, UID, Lineup } from '@audius/common/models' export interface FeedPageContentProps { feedTitle: string @@ -6,13 +6,7 @@ export interface FeedPageContentProps { feedIsMain: boolean feed: Lineup - fetchSuggestedFollowUsers: () => void - followUsers: (userIDs: ID[]) => void - suggestedFollows: User[] refreshFeedInView: (overwrite: boolean, limit?: number) => void - hasAccount: boolean - goToSignUp: () => void - goToTrending: () => void setFeedInView: (inView: boolean) => void loadMoreFeed: (offset: number, limit: number, overwrite: boolean) => void playFeedTrack: (uid: UID) => void diff --git a/packages/web/src/pages/sign-up-page/pages/SelectArtistsPage.tsx b/packages/web/src/pages/sign-up-page/pages/SelectArtistsPage.tsx index d33fe03dc72..f2643376acd 100644 --- a/packages/web/src/pages/sign-up-page/pages/SelectArtistsPage.tsx +++ b/packages/web/src/pages/sign-up-page/pages/SelectArtistsPage.tsx @@ -21,6 +21,11 @@ import { completeFollowArtists } from 'common/store/pages/signon/actions' import { getGenres } from 'common/store/pages/signon/selectors' +import { + FollowArtistCard, + FollowArtistTileSkeleton +} from 'components/follow-artist-card/FollowArtistCard' +import { SelectArtistsPreviewContextProvider } from 'components/follow-artist-card/selectArtistsPreviewContext' import { useMedia } from 'hooks/useMedia' import { useNavigateToPage } from 'hooks/useNavigateToPage' import { env } from 'services/env' @@ -28,10 +33,6 @@ import { useSelector } from 'utils/reducer' import { SIGN_UP_APP_CTA_PAGE, SIGN_UP_COMPLETED_REDIRECT } from 'utils/route' import { AccountHeader } from '../components/AccountHeader' -import { - FollowArtistCard, - FollowArtistTileSkeleton -} from '../components/FollowArtistCard' import { PreviewArtistHint } from '../components/PreviewArtistHint' import { Heading, @@ -39,7 +40,6 @@ import { PageFooter, ScrollView } from '../components/layout' -import { SelectArtistsPreviewContextProvider } from '../utils/selectArtistsPreviewContext' const AnimatedFlex = animated(Flex)