diff options
| author | Ashm Walia <40498934+ashmgarv@users.noreply.github.com> | 2020-12-04 08:50:24 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-12-04 11:50:24 -0500 |
| commit | 0fd892ad288f2e1eaaa4fdf5e1fd6f15dbd45860 (patch) | |
| tree | d7d53d94c6c4026ac9b325508ebce4706d412ac4 /src/store | |
| parent | f620102190629e0b6f180d3ce056d850b1db5aaa (diff) | |
[TMA - 398 AND TMA-430] Replace Providers with Redux Store (#125)
* First
* WIP
* Thunk
* Some more comments
* sc
* recent searches and follounfollow
* Edit profile dummy
* Block / unblock and some cleanup
* Replace auth provider
* Sc
* Delete AP after rebase
* Discover users
* Cleanup
* More cleanup
* Replace profile provider
* Fixed build failure
* Fixed a bug reported
* Prevent app crash when backend server is down
Diffstat (limited to 'src/store')
| -rw-r--r-- | src/store/actions/index.ts | 7 | ||||
| -rw-r--r-- | src/store/actions/socials.ts | 38 | ||||
| -rw-r--r-- | src/store/actions/taggUsers.ts | 24 | ||||
| -rw-r--r-- | src/store/actions/user.ts | 52 | ||||
| -rw-r--r-- | src/store/actions/userBlock.ts | 48 | ||||
| -rw-r--r-- | src/store/actions/userFollow.ts | 57 | ||||
| -rw-r--r-- | src/store/actions/userMoments.ts | 22 | ||||
| -rw-r--r-- | src/store/actions/userX.ts | 131 | ||||
| -rw-r--r-- | src/store/configureStore.ts | 20 | ||||
| -rw-r--r-- | src/store/initialStates.ts | 95 | ||||
| -rw-r--r-- | src/store/reducers/index.ts | 7 | ||||
| -rw-r--r-- | src/store/reducers/taggUsersReducer.ts | 16 | ||||
| -rw-r--r-- | src/store/reducers/userBlockReducer.ts | 25 | ||||
| -rw-r--r-- | src/store/reducers/userFollowReducer.ts | 27 | ||||
| -rw-r--r-- | src/store/reducers/userMomentsReducer.ts | 15 | ||||
| -rw-r--r-- | src/store/reducers/userReducer.ts | 36 | ||||
| -rw-r--r-- | src/store/reducers/userSocialsReducer.ts | 21 | ||||
| -rw-r--r-- | src/store/reducers/userXReducer.ts | 77 | ||||
| -rw-r--r-- | src/store/rootReducer.ts | 30 |
19 files changed, 748 insertions, 0 deletions
diff --git a/src/store/actions/index.ts b/src/store/actions/index.ts new file mode 100644 index 00000000..04fa9767 --- /dev/null +++ b/src/store/actions/index.ts @@ -0,0 +1,7 @@ +export * from './user'; +export * from './userFollow'; +export * from './userMoments'; +export * from './socials'; +export * from './taggUsers'; +export * from './userBlock'; +export * from './userX'; diff --git a/src/store/actions/socials.ts b/src/store/actions/socials.ts new file mode 100644 index 00000000..f79b4ad1 --- /dev/null +++ b/src/store/actions/socials.ts @@ -0,0 +1,38 @@ +import {RootState} from '../rootReducer'; +import {loadSocialPosts} from '../../services'; +import {Action, ThunkAction} from '@reduxjs/toolkit'; +import {userSocialsFetched, individualSocialfetched} from '../reducers'; +import {loadAllSocialsForUser} from '../../utils'; + +export const loadIndividualSocial = ( + userId: string, + socialType: string, +): ThunkAction<Promise<void>, RootState, unknown, Action<string>> => async ( + dispatch, +) => { + try { + const social = await loadSocialPosts(userId, socialType); + dispatch({ + type: individualSocialfetched.type, + payload: {socialType, social}, + }); + } catch (error) { + console.log(error); + } +}; + +export const loadAllSocials = ( + userId: string, +): ThunkAction<Promise<void>, RootState, unknown, Action<string>> => async ( + dispatch, +) => { + try { + const socials = await loadAllSocialsForUser(userId); + dispatch({ + type: userSocialsFetched.type, + payload: socials, + }); + } catch (error) { + console.log(error); + } +}; diff --git a/src/store/actions/taggUsers.ts b/src/store/actions/taggUsers.ts new file mode 100644 index 00000000..7f841c51 --- /dev/null +++ b/src/store/actions/taggUsers.ts @@ -0,0 +1,24 @@ +import {RootState} from '../rootReducer'; +import {loadRecentlySearchedUsers, getAllTaggUsers} from '../../services'; +import {Action, ThunkAction} from '@reduxjs/toolkit'; +import {taggUsersFetched} from '../reducers'; +import {getTokenOrLogout} from '../../utils'; + +export const loadRecentlySearched = (): ThunkAction< + Promise<void>, + RootState, + unknown, + Action<string> +> => async (dispatch) => { + try { + const token = await getTokenOrLogout(dispatch); + const recentSearches = await loadRecentlySearchedUsers(); + const taggUsers = await getAllTaggUsers(token); + dispatch({ + type: taggUsersFetched.type, + payload: {recentSearches, taggUsers}, + }); + } catch (error) { + console.log(error); + } +}; diff --git a/src/store/actions/user.ts b/src/store/actions/user.ts new file mode 100644 index 00000000..09ec8abf --- /dev/null +++ b/src/store/actions/user.ts @@ -0,0 +1,52 @@ +import {RootState} from '../rootReducer'; +import {UserType} from '../../types/types'; +import {loadProfileInfo, loadAvatar, loadCover} from '../../services'; +import {Action, ThunkAction} from '@reduxjs/toolkit'; +import {userLoggedIn, userDetailsFetched} from '../reducers'; +import {getTokenOrLogout} from '../../utils'; + +/** + * Entry point to our store. + * Thunk allows us to make async API calls and hence is responsible to fetch data from server. + */ + +/** + * Lets understand Thunk. + * https://bloggie.io/@_ChristineOo/understanding-typings-of-redux-thunk-action + * https://github.com/reduxjs/redux-thunk + */ + +export const loadUserData = ( + user: UserType, +): ThunkAction<Promise<void>, RootState, unknown, Action<string>> => async ( + dispatch, +) => { + try { + await dispatch({type: userLoggedIn.type, payload: user}); + const token = await getTokenOrLogout(dispatch); + const [profile, avatar, cover] = await Promise.all([ + loadProfileInfo(token, user.userId), + loadAvatar(token, user.userId), + loadCover(token, user.userId), + ]); + dispatch({ + type: userDetailsFetched.type, + payload: {profile, cover, avatar}, + }); + } catch (error) { + console.log(error); + } +}; + +export const logout = (): ThunkAction< + Promise<void>, + RootState, + unknown, + Action<string> +> => async (dispatch) => { + try { + dispatch({type: userLoggedIn.type, payload: {userId: '', username: ''}}); + } catch (error) { + console.log(error); + } +}; diff --git a/src/store/actions/userBlock.ts b/src/store/actions/userBlock.ts new file mode 100644 index 00000000..f903e99e --- /dev/null +++ b/src/store/actions/userBlock.ts @@ -0,0 +1,48 @@ +import {RootState} from '../rootReducer'; +import {ProfilePreviewType, UserType} from '../../types/types'; +import {blockOrUnblockUser, loadBlockedUsers} from '../../services'; +import {Action, ThunkAction} from '@reduxjs/toolkit'; +import {userBlockFetched, updateBlockedList, userLoggedIn} from '../reducers'; +import {getTokenOrLogout} from '../../utils'; + +export const loadBlockedList = ( + userId: string, +): ThunkAction<Promise<void>, RootState, unknown, Action<string>> => async ( + dispatch, +) => { + try { + const token = await getTokenOrLogout(dispatch); + const blocked = await loadBlockedUsers(userId, token); + dispatch({ + type: userBlockFetched.type, + payload: blocked, + }); + } catch (error) { + console.log(error); + } +}; + +export const blockUnblockUser = ( + blocker: UserType, + blocked: ProfilePreviewType, + isBlocked: boolean, +): ThunkAction<Promise<void>, RootState, unknown, Action<string>> => async ( + dispatch, +) => { + const token = await getTokenOrLogout(dispatch); + const success = blockOrUnblockUser( + blocker.userId, + blocked.id, + token, + isBlocked, + ); + if (success) { + dispatch({ + type: updateBlockedList.type, + payload: { + isBlocked, + data: blocked, + }, + }); + } +}; diff --git a/src/store/actions/userFollow.ts b/src/store/actions/userFollow.ts new file mode 100644 index 00000000..e23bbfc0 --- /dev/null +++ b/src/store/actions/userFollow.ts @@ -0,0 +1,57 @@ +import {getTokenOrLogout} from './../../utils'; +import {RootState} from '../rootReducer'; +import {ProfilePreviewType, UserType} from '../../types/types'; +import { + followOrUnfollowUser, + loadFollowers, + loadFollowing, +} from '../../services'; +import {Action, ThunkAction} from '@reduxjs/toolkit'; +import {userFollowFetched, updateFollowing, userLoggedIn} from '../reducers'; + +export const loadFollowData = ( + userId: string, +): ThunkAction<Promise<void>, RootState, unknown, Action<string>> => async ( + dispatch, +) => { + try { + const token = await getTokenOrLogout(dispatch); + const followers = await loadFollowers(userId, token); + const following = await loadFollowing(userId, token); + dispatch({ + type: userFollowFetched.type, + payload: {followers, following}, + }); + } catch (error) { + console.log(error); + } +}; + +export const followUnfollowUser = ( + follower: UserType, + followed: ProfilePreviewType, + isFollowed: boolean, +): ThunkAction<Promise<void>, RootState, unknown, Action<string>> => async ( + dispatch, +) => { + try { + const token = await getTokenOrLogout(dispatch); + const success = await followOrUnfollowUser( + follower.userId, + followed.id, + token, + isFollowed, + ); + if (success) { + dispatch({ + type: updateFollowing.type, + payload: { + isFollowed, + data: followed, + }, + }); + } + } catch (error) { + console.log(error); + } +}; diff --git a/src/store/actions/userMoments.ts b/src/store/actions/userMoments.ts new file mode 100644 index 00000000..dce8da8a --- /dev/null +++ b/src/store/actions/userMoments.ts @@ -0,0 +1,22 @@ +import {RootState} from '../rootReducer'; +import {loadMoments} from '../../services'; +import {Action, ThunkAction} from '@reduxjs/toolkit'; +import {userMomentsFetched} from '../reducers'; +import {getTokenOrLogout} from '../../utils'; + +export const loadUserMoments = ( + userId: string, +): ThunkAction<Promise<void>, RootState, unknown, Action<string>> => async ( + dispatch, +) => { + try { + const token = await getTokenOrLogout(dispatch); + const moments = await loadMoments(userId, token); + dispatch({ + type: userMomentsFetched.type, + payload: moments, + }); + } catch (error) { + console.log(error); + } +}; diff --git a/src/store/actions/userX.ts b/src/store/actions/userX.ts new file mode 100644 index 00000000..5468f762 --- /dev/null +++ b/src/store/actions/userX.ts @@ -0,0 +1,131 @@ +import {userXInStore} from './../../utils/'; +import {getTokenOrLogout, loadAllSocialsForUser} from './../../utils'; +import {UserType, ScreenType, ProfilePreviewType} from '../../types/types'; +import {RootState} from '../rootReducer'; +import {Action, ThunkAction} from '@reduxjs/toolkit'; +import { + userXRequested, + userXAvatarFetched, + userXFollowersFetched, + userXFollowingFetched, + userXCoverFetched, + userXMomentsFetched, + userXProfileFetched, + userXSocialsFetched, + userXUserFetched, + resetScreen, +} from '../reducers'; +import { + loadProfileInfo, + loadAvatar, + loadCover, + loadFollowers, + loadFollowing, + loadMoments, +} from '../../services'; + +export const loadUserX = ( + user: UserType, + screenType: ScreenType, +): ThunkAction<Promise<void>, RootState, unknown, Action<string>> => async ( + dispatch, +) => { + try { + const {userId} = user; + await dispatch({type: userXRequested.type, payload: {screenType, userId}}); + await dispatch({ + type: userXUserFetched.type, + payload: {screenType, userId, user}, + }); + const token = await getTokenOrLogout(dispatch); + loadProfileInfo(token, userId).then((data) => + dispatch({ + type: userXProfileFetched.type, + payload: {screenType, userId, data}, + }), + ); + loadAllSocialsForUser(userId).then((data) => + dispatch({ + type: userXSocialsFetched.type, + payload: {screenType, userId, data}, + }), + ); + loadAvatar(token, userId).then((data) => + dispatch({ + type: userXAvatarFetched.type, + payload: {screenType, userId, data}, + }), + ); + loadCover(token, userId).then((data) => + dispatch({ + type: userXCoverFetched.type, + payload: {screenType, userId, data}, + }), + ); + loadFollowers(userId, token).then((data) => + dispatch({ + type: userXFollowersFetched.type, + payload: {screenType, userId, data}, + }), + ); + loadFollowing(userId, token).then((data) => + dispatch({ + type: userXFollowingFetched.type, + payload: {screenType, userId, data}, + }), + ); + loadMoments(userId, token).then((data) => + dispatch({ + type: userXMomentsFetched.type, + payload: {screenType, userId, data}, + }), + ); + } catch (error) { + console.log(error); + } +}; + +export const updateUserXFollowersAndFollowing = ( + userId: string, + state: RootState, +): ThunkAction<Promise<void>, RootState, unknown, Action<string>> => async ( + dispatch, +) => { + try { + const screens = <ScreenType[]>[ScreenType.Profile, ScreenType.Search]; + const token = await getTokenOrLogout(dispatch); + screens.forEach((screenType) => { + if (userXInStore(state, screenType, userId)) { + loadFollowers(userId, token).then((data) => + dispatch({ + type: userXFollowersFetched.type, + payload: {screenType, userId, data}, + }), + ); + loadFollowing(userId, token).then((data) => + dispatch({ + type: userXFollowingFetched.type, + payload: {screenType, userId, data}, + }), + ); + } + }); + } catch (error) { + console.log(error); + } +}; + +export const resetScreenType = ( + screenType: ScreenType, +): ThunkAction<Promise<void>, RootState, unknown, Action<string>> => async ( + dispatch, +) => { + try { + dispatch({ + type: resetScreen.type, + payload: {screenType}, + }); + } catch (error) { + console.log(error); + } +}; diff --git a/src/store/configureStore.ts b/src/store/configureStore.ts new file mode 100644 index 00000000..7689af5c --- /dev/null +++ b/src/store/configureStore.ts @@ -0,0 +1,20 @@ +import {configureStore, getDefaultMiddleware} from '@reduxjs/toolkit'; +import reducer from './rootReducer'; + +/** + * The entry point to our store + * getDefaultMiddleware : This returns an array of default middlewares like Thunk (used for async calls) + */ + +const store = configureStore({ + reducer, + middleware: [...getDefaultMiddleware()], +}); + +/** + * The exports below come in handy when dispatching from a file outside of any of the Child component's + */ +export type AppDispatch = typeof store.dispatch; +export type GetState = typeof store.getState; + +export default store; diff --git a/src/store/initialStates.ts b/src/store/initialStates.ts new file mode 100644 index 00000000..4087b97c --- /dev/null +++ b/src/store/initialStates.ts @@ -0,0 +1,95 @@ +import {MomentType} from 'src/types'; +import { + ProfileType, + SocialAccountType, + ProfilePreviewType, + ScreenType, + UserXType, + UserType, +} from '../types'; + +export const NO_PROFILE: ProfileType = { + biography: '', + website: '', + name: '', + gender: '', + birthday: undefined, +}; + +export const EMPTY_MOMENTS_LIST = <MomentType[]>[]; + +export const NO_USER: UserType = { + userId: '', + username: '', +}; + +export const EMPTY_PROFILE_PREVIEW_LIST = <ProfilePreviewType[]>[]; + +export const NO_USER_DATA = { + user: <UserType>NO_USER, + profile: <ProfileType>NO_PROFILE, + avatar: <string | null>'', + cover: <string | null>'', +}; + +export const NO_FOLLOW_DATA = { + followers: EMPTY_PROFILE_PREVIEW_LIST, + following: EMPTY_PROFILE_PREVIEW_LIST, +}; + +export const NO_MOMENTS = { + moments: EMPTY_MOMENTS_LIST, +}; + +export const NO_SOCIAL_ACCOUNTS: Record<string, SocialAccountType> = { + Instagram: {posts: []}, + Facebook: {posts: []}, + Twitter: {posts: []}, +}; + +export const NO_TAGG_USERS = { + recentSearches: EMPTY_PROFILE_PREVIEW_LIST, + taggUsers: EMPTY_PROFILE_PREVIEW_LIST, +}; + +export const NO_SOCIALS = { + socialAccounts: NO_SOCIAL_ACCOUNTS, +}; + +export const NO_BLOCKED_USERS = { + blockedUsers: EMPTY_PROFILE_PREVIEW_LIST, +}; + +/** + * The dummy userId and username serve the purpose of preventing app crash + * For instance, if it may happen that data in our store is not loaded yet for the userXId being visited. + * Then we will set the userXId / username to this dummy username / userid + */ +export const DUMMY_USERID = 'ID-1234-567'; +export const DUMMY_USERNAME = 'tagg_userX'; + +export const EMPTY_USER_X = <UserXType>{ + followers: EMPTY_PROFILE_PREVIEW_LIST, + following: EMPTY_PROFILE_PREVIEW_LIST, + moments: EMPTY_MOMENTS_LIST, + socialAccounts: NO_SOCIAL_ACCOUNTS, + user: NO_USER, + profile: NO_PROFILE, + avatar: '', + cover: '', +}; + +/** + * A dummy userX to always be there in out initial app state + */ +export const EMPTY_USERX_LIST = <Record<string, UserXType>>{ + [DUMMY_USERID]: EMPTY_USER_X, +}; + +export const EMPTY_SCREEN_TO_USERS_LIST: Record< + ScreenType, + Record<string, UserXType> +> = { + [ScreenType.Profile]: EMPTY_USERX_LIST, + [ScreenType.Search]: EMPTY_USERX_LIST, +}; diff --git a/src/store/reducers/index.ts b/src/store/reducers/index.ts new file mode 100644 index 00000000..0e378bc5 --- /dev/null +++ b/src/store/reducers/index.ts @@ -0,0 +1,7 @@ +export * from './userFollowReducer'; +export * from './userReducer'; +export * from './userMomentsReducer'; +export * from './userSocialsReducer'; +export * from './taggUsersReducer'; +export * from './userBlockReducer'; +export * from './userXReducer'; diff --git a/src/store/reducers/taggUsersReducer.ts b/src/store/reducers/taggUsersReducer.ts new file mode 100644 index 00000000..ff30f7a0 --- /dev/null +++ b/src/store/reducers/taggUsersReducer.ts @@ -0,0 +1,16 @@ +import {NO_TAGG_USERS} from '../initialStates'; +import {createSlice} from '@reduxjs/toolkit'; + +const taggUsersSlice = createSlice({ + name: 'taggUsers', + initialState: NO_TAGG_USERS, + reducers: { + taggUsersFetched: (state, action) => { + state.recentSearches = action.payload.taggUsers; + state.taggUsers = action.payload.taggUsers; + }, + }, +}); + +export const {taggUsersFetched} = taggUsersSlice.actions; +export const taggUsersReducer = taggUsersSlice.reducer; diff --git a/src/store/reducers/userBlockReducer.ts b/src/store/reducers/userBlockReducer.ts new file mode 100644 index 00000000..90e4a04a --- /dev/null +++ b/src/store/reducers/userBlockReducer.ts @@ -0,0 +1,25 @@ +import {createSlice} from '@reduxjs/toolkit'; +import {NO_BLOCKED_USERS} from '../initialStates'; + +const userBlockSlice = createSlice({ + name: 'userBlock', + initialState: NO_BLOCKED_USERS, + reducers: { + userBlockFetched: (state, action) => { + state.blockedUsers = action.payload; + }, + + updateBlockedList: (state, action) => { + const {isBlocked, data} = action.payload; + if (!isBlocked) state.blockedUsers.push(data); + else { + state.blockedUsers = state.blockedUsers.filter( + (user) => user.username != data.username, + ); + } + }, + }, +}); + +export const {userBlockFetched, updateBlockedList} = userBlockSlice.actions; +export const userBlockReducer = userBlockSlice.reducer; diff --git a/src/store/reducers/userFollowReducer.ts b/src/store/reducers/userFollowReducer.ts new file mode 100644 index 00000000..55e16532 --- /dev/null +++ b/src/store/reducers/userFollowReducer.ts @@ -0,0 +1,27 @@ +import {createSlice} from '@reduxjs/toolkit'; +import {act} from 'react-test-renderer'; +import {NO_FOLLOW_DATA} from '../initialStates'; + +const userFollowSlice = createSlice({ + name: 'userFollow', + initialState: NO_FOLLOW_DATA, + reducers: { + userFollowFetched: (state, action) => { + state.followers = action.payload.followers; + state.following = action.payload.following; + }, + + updateFollowing: (state, action) => { + const {isFollowed, data} = action.payload; + if (!isFollowed) state.following.push(data); + else { + state.following = state.following.filter( + (follow) => follow.username !== data.username, + ); + } + }, + }, +}); + +export const {userFollowFetched, updateFollowing} = userFollowSlice.actions; +export const userFollowReducer = userFollowSlice.reducer; diff --git a/src/store/reducers/userMomentsReducer.ts b/src/store/reducers/userMomentsReducer.ts new file mode 100644 index 00000000..456ca2fa --- /dev/null +++ b/src/store/reducers/userMomentsReducer.ts @@ -0,0 +1,15 @@ +import {createSlice} from '@reduxjs/toolkit'; +import {NO_MOMENTS} from '../initialStates'; + +const userMomentsSlice = createSlice({ + name: 'userMoments', + initialState: NO_MOMENTS, + reducers: { + userMomentsFetched: (state, action) => { + state.moments = action.payload; + }, + }, +}); + +export const {userMomentsFetched} = userMomentsSlice.actions; +export const userMomentsReducer = userMomentsSlice.reducer; diff --git a/src/store/reducers/userReducer.ts b/src/store/reducers/userReducer.ts new file mode 100644 index 00000000..f43bd0bc --- /dev/null +++ b/src/store/reducers/userReducer.ts @@ -0,0 +1,36 @@ +import {createSlice, Action} from '@reduxjs/toolkit'; +import {NO_USER_DATA} from '../initialStates'; + +/** + * A reducer is a pure function with the sole responsibility of updating the state and nothing else. + * No side effects are allowed. + */ + +/** + * Actions are a way to indicate what just happened / what is going to happen and update the state accordingly. + */ + +/** + * Create slice allows us + * To initialise State , create Actions and Reducers in one go + * Read more here https://redux.js.org/introduction/installation + */ + +const userDataSlice = createSlice({ + name: 'userData', + initialState: NO_USER_DATA, + reducers: { + userLoggedIn: (state, action) => { + state.user = action.payload; + }, + + userDetailsFetched: (state, action) => { + state.profile = action.payload.profile; + state.avatar = action.payload.avatar; + state.cover = action.payload.cover; + }, + }, +}); + +export const {userLoggedIn, userDetailsFetched} = userDataSlice.actions; +export const userDataReducer = userDataSlice.reducer; diff --git a/src/store/reducers/userSocialsReducer.ts b/src/store/reducers/userSocialsReducer.ts new file mode 100644 index 00000000..de79568c --- /dev/null +++ b/src/store/reducers/userSocialsReducer.ts @@ -0,0 +1,21 @@ +import {createSlice} from '@reduxjs/toolkit'; +import {NO_SOCIALS} from '../initialStates'; + +const userSocialsSlice = createSlice({ + name: 'userSocials', + initialState: NO_SOCIALS, + reducers: { + individualSocialfetched: (state, actions) => { + state.socialAccounts[actions.payload.socialType] = actions.payload.social; + }, + userSocialsFetched: (state, action) => { + state.socialAccounts = action.payload; + }, + }, +}); + +export const { + userSocialsFetched, + individualSocialfetched, +} = userSocialsSlice.actions; +export const userSocialsReducer = userSocialsSlice.reducer; diff --git a/src/store/reducers/userXReducer.ts b/src/store/reducers/userXReducer.ts new file mode 100644 index 00000000..154dd7dc --- /dev/null +++ b/src/store/reducers/userXReducer.ts @@ -0,0 +1,77 @@ +import {ScreenType} from '../../types/types'; +import {EMPTY_SCREEN_TO_USERS_LIST, EMPTY_USER_X} from '../initialStates'; +import {createSlice} from '@reduxjs/toolkit'; + +const userXSlice = createSlice({ + name: 'userX', + initialState: EMPTY_SCREEN_TO_USERS_LIST, + reducers: { + userXRequested: (state, action) => { + state[<ScreenType>action.payload.screenType][ + action.payload.userId + ] = EMPTY_USER_X; + }, + + userXProfileFetched: (state, action) => { + state[<ScreenType>action.payload.screenType][ + action.payload.userId + ].profile = action.payload.data; + }, + + userXUserFetched: (state, action) => { + state[<ScreenType>action.payload.screenType][action.payload.userId].user = + action.payload.user; + }, + + userXMomentsFetched: (state, action) => { + state[<ScreenType>action.payload.screenType][ + action.payload.userId + ].moments = action.payload.data; + }, + userXFollowersFetched: (state, action) => { + state[<ScreenType>action.payload.screenType][ + action.payload.userId + ].followers = action.payload.data; + }, + userXFollowingFetched: (state, action) => { + state[<ScreenType>action.payload.screenType][ + action.payload.userId + ].following = action.payload.data; + }, + userXAvatarFetched: (state, action) => { + state[<ScreenType>action.payload.screenType][ + action.payload.userId + ].avatar = action.payload.data; + }, + userXCoverFetched: (state, action) => { + state[<ScreenType>action.payload.screenType][ + action.payload.userId + ].cover = action.payload.data; + }, + userXSocialsFetched: (state, action) => { + state[<ScreenType>action.payload.screenType][ + action.payload.userId + ].socialAccounts = action.payload.data; + }, + + resetScreen: (state, action) => { + for (let userId in state[<ScreenType>action.payload.screenType]) { + state[<ScreenType>action.payload.screenType][userId] = EMPTY_USER_X; + } + }, + }, +}); + +export const { + userXUserFetched, + userXRequested, + userXAvatarFetched, + userXFollowersFetched, + userXFollowingFetched, + userXCoverFetched, + userXMomentsFetched, + userXProfileFetched, + userXSocialsFetched, + resetScreen, +} = userXSlice.actions; +export const userXReducer = userXSlice.reducer; diff --git a/src/store/rootReducer.ts b/src/store/rootReducer.ts new file mode 100644 index 00000000..695ed8c7 --- /dev/null +++ b/src/store/rootReducer.ts @@ -0,0 +1,30 @@ +import {combineReducers} from 'redux'; +import { + userDataReducer, + userSocialsReducer, + userFollowReducer, + userMomentsReducer, + taggUsersReducer, + userBlockReducer, + userXReducer, +} from './reducers'; + +/** + * Combine all the reducers in our application. + */ + +const rootReducer = combineReducers({ + user: userDataReducer, + follow: userFollowReducer, + moments: userMomentsReducer, + socialAccounts: userSocialsReducer, + taggUsers: taggUsersReducer, + blocked: userBlockReducer, + userX: userXReducer, +}); + +/** + * This RootState export is needed when a component subscribes to a slice of the state. + */ +export type RootState = ReturnType<typeof rootReducer>; +export default rootReducer; |
