From 05736f399400fb56f9680c2705ff8fb0a1fcd869 Mon Sep 17 00:00:00 2001 From: KJ Shanks Date: Tue, 30 Jan 2024 11:21:30 -0800 Subject: [PATCH] Convert profile page store js files to ts --- .../common/src/store/pages/profile/actions.ts | 219 ++++++++++++++++-- .../pages/profile/lineups/tracks/reducer.ts | 17 +- .../common/src/store/pages/profile/reducer.ts | 174 ++++++++++---- .../common/src/store/pages/profile/types.ts | 4 +- 4 files changed, 334 insertions(+), 80 deletions(-) diff --git a/packages/common/src/store/pages/profile/actions.ts b/packages/common/src/store/pages/profile/actions.ts index 3572b2391f3..1757c16c9fe 100644 --- a/packages/common/src/store/pages/profile/actions.ts +++ b/packages/common/src/store/pages/profile/actions.ts @@ -1,6 +1,6 @@ import { Nullable } from 'utils' -import { ID, User, UserMetadata } from '../../../models' +import { ID, UID, UserMetadata } from '../../../models' import { CollectionSortMode, FollowType } from './types' @@ -28,6 +28,7 @@ export const DISMISS_PROFILE_METER = 'PROFILE/DISMISS_PROFILE_METER' export const FETCH_TOP_TAGS = 'PROFILE/FETCH_TOP_TAGS' export const FETCH_TOP_TAGS_SUCCEEDED = 'PROFILE/FETCH_TOP_TAGS_SUCCEEDED' export const FETCH_TOP_TAGS_FAILED = 'PROFILE/FETCH_TOP_TAGS_FAILED' + export const SET_NOTIFICATION_SUBSCRIPTION = 'PROFILE/SET_NOTIFICATION_SUBSCRIPTION' @@ -35,6 +36,158 @@ export const FETCH_COLLECTIONS = 'PROFILE/FETCH_COLLECTIONS' export const FETCH_COLLECTIONS_SUCCEEDED = 'PROFILE/FETCH_COLLECTIONS_SUCCEEDED' export const FETCH_COLLECTIONS_FAILED = 'PROFILE/FETCH_COLLECTIONS_FAILED' +export type FetchProfileAction = { + type: typeof FETCH_PROFILE + handle: string | null + userId: ID | null + forceUpdate: boolean + shouldSetLoading: boolean + deleteExistingEntry: boolean + fetchOnly?: boolean +} + +export type FetchProfileSucceededAction = { + type: typeof FETCH_PROFILE_SUCCEEDED + handle: string + userId: ID + fetchOnly: boolean +} + +export type FetchProfileFailedAction = { + type: typeof FETCH_PROFILE_FAILED + handle: string +} + +export type SetCurrentUserAction = { + type: typeof SET_CURRENT_USER + handle: string +} + +export type UpdateProfileAction = { + type: typeof UPDATE_PROFILE + metadata: UserMetadata +} + +export type UpdateProfileSucceededAction = { + type: typeof UPDATE_PROFILE_SUCCEEDED + userId: ID +} + +export type UpdateProfileFailedAction = { + type: typeof UPDATE_PROFILE_FAILED +} + +export type UpdateCollectionSortModeAction = { + type: typeof UPDATE_COLLECTION_SORT_MODE + mode: CollectionSortMode + handle: string +} + +export type SetProfileFieldAction = { + type: typeof SET_PROFILE_FIELD + field: string + value: string + handle: string +} + +export type UpdateCurrentUserFollowsAction = { + type: typeof UPDATE_CURRENT_USER_FOLLOWS + follow?: boolean + handle: string +} + +export type FetchFollowUsersAction = { + type: typeof FETCH_FOLLOW_USERS + followerGroup: FollowType + limit?: number + offset?: number + handle: string +} + +export type FetchFollowUsersSucceededAction = { + type: typeof FETCH_FOLLOW_USERS_SUCCEEDED + followerGroup: FollowType + userIds: { id: ID; uid?: UID }[] + limit: number + offset: number + handle: string +} + +export type FetchFollowUsersFailedAction = { + type: typeof FETCH_FOLLOW_USERS_FAILED + followerGroup: FollowType + limit: number + offset: number + handle: string +} + +export type DismissProfileMeterAction = { + type: typeof DISMISS_PROFILE_METER +} + +export type FetchTopTagsAction = { + type: typeof FETCH_TOP_TAGS + handle: string + userId: ID +} + +export type FetchTopTagsSucceededAction = { + type: typeof FETCH_TOP_TAGS_SUCCEEDED + handle: string + topTags: string[] +} + +export type FetchTopTagsFailedAction = { + type: typeof FETCH_TOP_TAGS_FAILED + handle: string +} + +export type SetNotificationSubscriptionAction = { + type: typeof SET_NOTIFICATION_SUBSCRIPTION + userId: ID + isSubscribed: boolean + update?: boolean + handle?: string +} + +export type FetchCollectionsAction = { + type: typeof FETCH_COLLECTIONS + handle: string +} + +export type FetchCollectionsSucceededAction = { + type: typeof FETCH_COLLECTIONS_SUCCEEDED + handle: string +} + +export type FetchCollectionsFailedAction = { + type: typeof FETCH_COLLECTIONS_FAILED + handle: string +} + +export type ProfilePageAction = + | FetchProfileAction + | FetchProfileSucceededAction + | FetchProfileFailedAction + | SetCurrentUserAction + | UpdateProfileAction + | UpdateProfileSucceededAction + | UpdateProfileFailedAction + | UpdateCollectionSortModeAction + | SetProfileFieldAction + | UpdateCurrentUserFollowsAction + | FetchFollowUsersAction + | FetchFollowUsersSucceededAction + | FetchFollowUsersFailedAction + | DismissProfileMeterAction + | FetchTopTagsAction + | FetchTopTagsSucceededAction + | FetchTopTagsFailedAction + | SetNotificationSubscriptionAction + | FetchCollectionsAction + | FetchCollectionsSucceededAction + | FetchCollectionsFailedAction + // Either handle or userId is required // TODO: Move this to redux toolkit export function fetchProfile( @@ -44,7 +197,7 @@ export function fetchProfile( shouldSetLoading: boolean, deleteExistingEntry: boolean, fetchOnly = false -) { +): FetchProfileAction { return { type: FETCH_PROFILE, handle, @@ -60,42 +213,51 @@ export function fetchProfileSucceeded( handle: string, userId: ID, fetchOnly: boolean -) { +): FetchProfileSucceededAction { return { type: FETCH_PROFILE_SUCCEEDED, handle, userId, fetchOnly } } -export function fetchProfileFailed(handle: string) { +export function fetchProfileFailed(handle: string): FetchProfileFailedAction { return { type: FETCH_PROFILE_FAILED, handle } } -export function setCurrentUser(handle: string) { +export function setCurrentUser(handle: string): SetCurrentUserAction { return { type: SET_CURRENT_USER, handle } } -export function updateProfile(metadata: UserMetadata) { +export function updateProfile(metadata: UserMetadata): UpdateProfileAction { return { type: UPDATE_PROFILE, metadata } } -export function updateProfileSucceeded(userId: ID) { +export function updateProfileSucceeded( + userId: ID +): UpdateProfileSucceededAction { return { type: UPDATE_PROFILE_SUCCEEDED, userId } } -export function updateProfileFailed() { +export function updateProfileFailed(): UpdateProfileFailedAction { return { type: UPDATE_PROFILE_FAILED } } export function updateCollectionSortMode( mode: CollectionSortMode, handle: string -) { +): UpdateCollectionSortModeAction { return { type: UPDATE_COLLECTION_SORT_MODE, mode, handle } } -export function setProfileField(field: string, value: string, handle: string) { +export function setProfileField( + field: string, + value: string, + handle: string +): SetProfileFieldAction { return { type: SET_PROFILE_FIELD, field, value, handle } } -export function updateCurrentUserFollows(follow = false, handle: string) { +export function updateCurrentUserFollows( + follow = false, + handle: string +): UpdateCurrentUserFollowsAction { return { type: UPDATE_CURRENT_USER_FOLLOWS, follow, handle } } @@ -104,17 +266,17 @@ export function fetchFollowUsers( limit = 15, offset = 0, handle: string -) { +): FetchFollowUsersAction { return { type: FETCH_FOLLOW_USERS, followerGroup, offset, limit, handle } } export function fetchFollowUsersSucceeded( - followerGroup: User[], - userIds: ID[], + followerGroup: FollowType, + userIds: { id: ID; uid?: UID }[], limit: number, offset: number, handle: string -) { +): FetchFollowUsersSucceededAction { return { type: FETCH_FOLLOW_USERS_SUCCEEDED, followerGroup, @@ -126,11 +288,11 @@ export function fetchFollowUsersSucceeded( } export function fetchFollowUsersFailed( - followerGroup: User[], + followerGroup: FollowType, limit: number, offset: number, handle: string -) { +): FetchFollowUsersFailedAction { return { type: FETCH_FOLLOW_USERS_FAILED, followerGroup, @@ -140,7 +302,7 @@ export function fetchFollowUsersFailed( } } -export function profileMeterDismissed() { +export function profileMeterDismissed(): DismissProfileMeterAction { return { type: DISMISS_PROFILE_METER } } @@ -149,7 +311,7 @@ export function setNotificationSubscription( isSubscribed: boolean, update = false, handle?: string -) { +): SetNotificationSubscriptionAction { return { type: SET_NOTIFICATION_SUBSCRIPTION, userId, @@ -159,28 +321,32 @@ export function setNotificationSubscription( } } -export function fetchCollections(handle: string) { +export function fetchCollections(handle: string): FetchCollectionsAction { return { type: FETCH_COLLECTIONS, handle } } -export function fetchCollectionsSucceded(handle: string) { +export function fetchCollectionsSucceded( + handle: string +): FetchCollectionsSucceededAction { return { type: FETCH_COLLECTIONS_SUCCEEDED, handle } } -export function fetchCollectionsFailed(handle: string) { +export function fetchCollectionsFailed( + handle: string +): FetchCollectionsFailedAction { return { type: FETCH_COLLECTIONS_FAILED, handle } } -export function fetchTopTags(handle: string, userId: ID) { +export function fetchTopTags(handle: string, userId: ID): FetchTopTagsAction { return { type: FETCH_TOP_TAGS, handle, @@ -188,7 +354,10 @@ export function fetchTopTags(handle: string, userId: ID) { } } -export function fetchTopTagsSucceeded(handle: string, topTags: string[]) { +export function fetchTopTagsSucceeded( + handle: string, + topTags: string[] +): FetchTopTagsSucceededAction { return { type: FETCH_TOP_TAGS_SUCCEEDED, handle, @@ -196,7 +365,7 @@ export function fetchTopTagsSucceeded(handle: string, topTags: string[]) { } } -export function fetchTopTagsFailed(handle: string) { +export function fetchTopTagsFailed(handle: string): FetchTopTagsFailedAction { return { type: FETCH_TOP_TAGS_FAILED, handle diff --git a/packages/common/src/store/pages/profile/lineups/tracks/reducer.ts b/packages/common/src/store/pages/profile/lineups/tracks/reducer.ts index ab0492ffdca..68c677c0c1b 100644 --- a/packages/common/src/store/pages/profile/lineups/tracks/reducer.ts +++ b/packages/common/src/store/pages/profile/lineups/tracks/reducer.ts @@ -1,5 +1,5 @@ -// @ts-nocheck -// TODO(nkang) - convert to TS +import { LineupState } from 'models/Lineup' +import { Track } from 'models/Track' import { RESET_SUCCEEDED, stripPrefix } from 'store/lineup/actions' import { initialLineupState } from 'store/lineup/reducer' import { PREFIX } from 'store/pages/profile/lineups/tracks/actions' @@ -9,15 +9,22 @@ export const initialState = { prefix: PREFIX } +type ResetSucceededAction = { + type: typeof RESET_SUCCEEDED +} + const actionsMap = { - [RESET_SUCCEEDED](state, action) { + [RESET_SUCCEEDED](_state: LineupState, _action: ResetSucceededAction) { const newState = initialState return newState } } -const tracks = (state = initialState, action) => { - const baseActionType = stripPrefix(PREFIX, action.type) +const tracks = (state = initialState, action: ResetSucceededAction) => { + const baseActionType = stripPrefix( + PREFIX, + action.type + ) as typeof RESET_SUCCEEDED const matchingReduceFunction = actionsMap[baseActionType] if (!matchingReduceFunction) return state return matchingReduceFunction(state, action) diff --git a/packages/common/src/store/pages/profile/reducer.ts b/packages/common/src/store/pages/profile/reducer.ts index 6c2474079f1..4d9ef825013 100644 --- a/packages/common/src/store/pages/profile/reducer.ts +++ b/packages/common/src/store/pages/profile/reducer.ts @@ -1,16 +1,12 @@ -// @ts-nocheck -// TODO(nkang) - convert to TS - -import { asLineup } from 'store/lineup/reducer' +import { LineupActions, asLineup } from 'store/lineup/reducer' import feedReducer, { initialState as initialFeedLineupState } from 'store/pages/profile/lineups/feed/reducer' import tracksReducer, { initialState as initialTracksLineupState } from 'store/pages/profile/lineups/tracks/reducer' -import { FollowType, CollectionSortMode } from 'store/pages/profile/types' -import { Status } from '../../../models' +import { Status, Track } from '../../../models' import { FETCH_PROFILE, @@ -32,10 +28,37 @@ import { FETCH_COLLECTIONS_FAILED, FETCH_TOP_TAGS, FETCH_TOP_TAGS_SUCCEEDED, - FETCH_TOP_TAGS_FAILED + FETCH_TOP_TAGS_FAILED, + FetchProfileAction, + FetchProfileSucceededAction, + SetCurrentUserAction, + FetchFollowUsersAction, + FetchFollowUsersSucceededAction, + FetchFollowUsersFailedAction, + SetProfileFieldAction, + FetchProfileFailedAction, + UpdateProfileAction, + UpdateProfileSucceededAction, + UpdateProfileFailedAction, + FetchCollectionsAction, + FetchCollectionsSucceededAction, + FetchCollectionsFailedAction, + UpdateCollectionSortModeAction, + DismissProfileMeterAction, + SetNotificationSubscriptionAction, + FetchTopTagsAction, + FetchTopTagsFailedAction, + FetchTopTagsSucceededAction, + ProfilePageAction } from './actions' import { PREFIX as feedPrefix } from './lineups/feed/actions' import { PREFIX as tracksPrefix } from './lineups/tracks/actions' +import { + FollowType, + CollectionSortMode, + ProfilePageState, + ProfileState +} from './types' const initialProfileState = { handle: null, @@ -62,33 +85,40 @@ const initialProfileState = { tracks: initialTracksLineupState } -const updateProfile = (state, action, data) => { +const updateProfile = ( + state: ProfilePageState, + action: ProfilePageAction, + data: Partial +) => { const { currentUser, entries } = state - const { handle } = action - const profileHandle = handle?.toLowerCase() ?? currentUser - const newEntry = entries[profileHandle] + const profileHandle = + ('handle' in action && action.handle?.toLowerCase()) || currentUser + const newEntry = profileHandle ? entries[profileHandle] : {} + + const newEntryData = profileHandle + ? { + [profileHandle]: { + ...newEntry, + ...data + } + } + : {} return { ...state, - entries: { - ...entries, - [profileHandle]: { - ...newEntry, - ...data - } - } + entries: { ...entries, ...newEntryData } } } const initialState = { currentUser: null, entries: {} } const actionsMap = { - [FETCH_PROFILE](state, action) { + [FETCH_PROFILE](state: ProfilePageState, action: FetchProfileAction) { const { fetchOnly, shouldSetLoading, handle, userId } = action if (fetchOnly) return state - const lowerHandle = handle.toLowerCase() + const lowerHandle = handle?.toLowerCase() - const newState = {} + const newState: Partial = {} if (shouldSetLoading) { newState.status = Status.LOADING @@ -104,7 +134,10 @@ const actionsMap = { currentUser: lowerHandle } }, - [FETCH_PROFILE_SUCCEEDED](state, action) { + [FETCH_PROFILE_SUCCEEDED]( + state: ProfilePageState, + action: FetchProfileSucceededAction + ) { const { currentUser } = state const { fetchOnly, userId, handle } = action const profileHandle = handle?.toLowerCase() ?? currentUser @@ -116,7 +149,13 @@ const actionsMap = { handle: profileHandle }) }, - [SET_CURRENT_USER](state, action) { + [FETCH_PROFILE_FAILED]( + state: ProfilePageState, + action: FetchProfileFailedAction + ) { + return updateProfile(state, action, { status: Status.ERROR }) + }, + [SET_CURRENT_USER](state: ProfilePageState, action: SetCurrentUserAction) { const { handle } = action const lowerHandle = handle.toLowerCase() @@ -125,7 +164,10 @@ const actionsMap = { currentUser: lowerHandle } }, - [FETCH_FOLLOW_USERS](state, action) { + [FETCH_FOLLOW_USERS]( + state: ProfilePageState, + action: FetchFollowUsersAction + ) { const { currentUser, entries } = state const { followerGroup, handle } = action const profileHandle = handle?.toLowerCase() ?? currentUser @@ -145,7 +187,10 @@ const actionsMap = { } } }, - [FETCH_FOLLOW_USERS_SUCCEEDED](state, action) { + [FETCH_FOLLOW_USERS_SUCCEEDED]( + state: ProfilePageState, + action: FetchFollowUsersSucceededAction + ) { const { currentUser, entries } = state const { userIds, followerGroup, handle } = action const profileHandle = handle?.toLowerCase() ?? currentUser @@ -169,7 +214,10 @@ const actionsMap = { } } }, - [FETCH_FOLLOW_USERS_FAILED](state, action) { + [FETCH_FOLLOW_USERS_FAILED]( + state: ProfilePageState, + action: FetchFollowUsersFailedAction + ) { const { currentUser, entries } = state const { followerGroup, handle } = action const profileHandle = handle?.toLowerCase() ?? currentUser @@ -188,66 +236,90 @@ const actionsMap = { } } }, - [SET_PROFILE_FIELD](state, action) { + [SET_PROFILE_FIELD](state: ProfilePageState, action: SetProfileFieldAction) { const { field, value } = action return updateProfile(state, action, { [field]: value }) }, - [FETCH_PROFILE_FAILED](state, action) { - return updateProfile(state, action, { status: Status.ERROR }) - }, - [UPDATE_PROFILE](state, action) { + [UPDATE_PROFILE](state: ProfilePageState, action: UpdateProfileAction) { return updateProfile(state, action, { updating: true, updateSuccess: false, updateError: false }) }, - [UPDATE_PROFILE_SUCCEEDED](state, action) { + [UPDATE_PROFILE_SUCCEEDED]( + state: ProfilePageState, + action: UpdateProfileSucceededAction + ) { return updateProfile(state, action, { updating: false, updateSuccess: true }) }, - [UPDATE_PROFILE_FAILED](state, action) { + [UPDATE_PROFILE_FAILED]( + state: ProfilePageState, + action: UpdateProfileFailedAction + ) { return updateProfile(state, action, { updating: false, updateError: true }) }, - [UPDATE_COLLECTION_SORT_MODE](state, action) { + [UPDATE_COLLECTION_SORT_MODE]( + state: ProfilePageState, + action: UpdateCollectionSortModeAction + ) { const { mode } = action return updateProfile(state, action, { collectionSortMode: mode }) }, - [DISMISS_PROFILE_METER](state, action) { + [DISMISS_PROFILE_METER]( + state: ProfilePageState, + action: DismissProfileMeterAction + ) { return updateProfile(state, action, { profileMeterDismissed: true }) }, - [SET_NOTIFICATION_SUBSCRIPTION](state, action) { + [SET_NOTIFICATION_SUBSCRIPTION]( + state: ProfilePageState, + action: SetNotificationSubscriptionAction + ) { const { isSubscribed } = action return updateProfile(state, action, { isNotificationSubscribed: isSubscribed }) }, - [FETCH_COLLECTIONS](state, action) { + [FETCH_COLLECTIONS](state: ProfilePageState, action: FetchCollectionsAction) { return updateProfile(state, action, { collectionStatus: Status.LOADING }) }, - [FETCH_COLLECTIONS_SUCCEEDED](state, action) { + [FETCH_COLLECTIONS_SUCCEEDED]( + state: ProfilePageState, + action: FetchCollectionsSucceededAction + ) { return updateProfile(state, action, { collectionStatus: Status.SUCCESS }) }, - [FETCH_COLLECTIONS_FAILED](state, action) { + [FETCH_COLLECTIONS_FAILED]( + state: ProfilePageState, + action: FetchCollectionsFailedAction + ) { return updateProfile(state, action, { collectionStatus: Status.ERROR }) }, - [FETCH_TOP_TAGS](state, action) { + [FETCH_TOP_TAGS](state: ProfilePageState, action: FetchTopTagsAction) { return updateProfile(state, action, { topTagsStatus: Status.LOADING }) }, - [FETCH_TOP_TAGS_SUCCEEDED](state, action) { + [FETCH_TOP_TAGS_SUCCEEDED]( + state: ProfilePageState, + action: FetchTopTagsSucceededAction + ) { const { topTags } = action return updateProfile(state, action, { topTagsStatus: Status.SUCCESS, topTags }) }, - [FETCH_TOP_TAGS_FAILED](state, action) { + [FETCH_TOP_TAGS_FAILED]( + state: ProfilePageState, + action: FetchTopTagsFailedAction + ) { return updateProfile(state, action, { topTagsStatus: Status.ERROR }) } } @@ -255,21 +327,27 @@ const actionsMap = { const feedLineupReducer = asLineup(feedPrefix, feedReducer) const tracksLineupReducer = asLineup(tracksPrefix, tracksReducer) -const reducer = (state = initialState, action) => { +const reducer = ( + state = initialState, + action: ProfilePageAction | LineupActions +) => { const { currentUser, entries } = state - const { handle } = action - const profileHandle = handle?.toLowerCase() ?? currentUser + const profileHandle = + ('handle' in action && action.handle?.toLowerCase()) ?? currentUser if (!profileHandle) return state let newEntry = entries[profileHandle] ?? initialProfileState - const feed = feedLineupReducer(newEntry.feed, action) + const feed = feedLineupReducer(newEntry.feed, action as LineupActions) if (feed !== newEntry.feed) { newEntry = { ...newEntry, feed } } - const tracks = tracksLineupReducer(newEntry.tracks, action) + const tracks = tracksLineupReducer( + newEntry.tracks, + action as LineupActions + ) if (tracks !== newEntry.tracks) { newEntry = { ...newEntry, tracks } } @@ -281,7 +359,7 @@ const reducer = (state = initialState, action) => { const matchingReduceFunction = actionsMap[action.type] if (!matchingReduceFunction) return newState - return matchingReduceFunction(newState, action) + return matchingReduceFunction(newState, action as ProfilePageAction) } export default reducer diff --git a/packages/common/src/store/pages/profile/types.ts b/packages/common/src/store/pages/profile/types.ts index d5ca5379185..9a516e8f496 100644 --- a/packages/common/src/store/pages/profile/types.ts +++ b/packages/common/src/store/pages/profile/types.ts @@ -18,7 +18,7 @@ export enum TracksSortMode { } export type ProfilePageFollow = { - userIds: Array<{ id: ID; uid: UID }> + userIds: { id: ID; uid?: UID }[] status: Status } @@ -30,7 +30,7 @@ export type ProfileState = { updateSuccess: boolean updateError: boolean collectionIds: number[] - collectionStatus: Status.IDLE + collectionStatus: Status topTagsStatus: Status topTags: string[] collectionSortMode: CollectionSortMode