From 0fd892ad288f2e1eaaa4fdf5e1fd6f15dbd45860 Mon Sep 17 00:00:00 2001
From: Ashm Walia <40498934+ashmgarv@users.noreply.github.com>
Date: Fri, 4 Dec 2020 08:50:24 -0800
Subject: [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
---
src/routes/Routes.tsx | 24 ++-
src/routes/authentication/AuthProvider.tsx | 315 -----------------------------
src/routes/authentication/index.ts | 2 -
src/routes/index.ts | 4 -
src/routes/profile/Profile.tsx | 38 ++--
src/routes/profile/ProfileStack.tsx | 36 ++--
src/routes/tabs/NavigationBar.tsx | 5 +-
src/routes/viewProfile/ProfileProvider.tsx | 207 -------------------
src/routes/viewProfile/index.ts | 2 -
9 files changed, 68 insertions(+), 565 deletions(-)
delete mode 100644 src/routes/authentication/AuthProvider.tsx
delete mode 100644 src/routes/authentication/index.ts
delete mode 100644 src/routes/viewProfile/ProfileProvider.tsx
delete mode 100644 src/routes/viewProfile/index.ts
(limited to 'src/routes')
diff --git a/src/routes/Routes.tsx b/src/routes/Routes.tsx
index 92cd3dd2..e54f038d 100644
--- a/src/routes/Routes.tsx
+++ b/src/routes/Routes.tsx
@@ -1,13 +1,29 @@
-import React from 'react';
-
-import {AuthContext} from './authentication';
+import React, {useEffect} from 'react';
import NavigationBar from './tabs';
import Onboarding from './onboarding';
+import {useSelector, useDispatch} from 'react-redux';
+import {RootState} from '../store/rootReducer';
+import {userLogin} from '../utils';
const Routes: React.FC = () => {
const {
user: {userId},
- } = React.useContext(AuthContext);
+ } = useSelector((state: RootState) => state.user);
+ const dispatch = useDispatch();
+
+ /**
+ * Load the user from AsyncStorage if any
+ * Note that this makes logout triggered by invalid Token have no effect.
+ * We should figure out a way to handle that.
+ * Suggestions?
+ * NOTE : Not something introduced by this commit but something we already have.
+ */
+ useEffect(() => {
+ if (!userId) {
+ userLogin(dispatch, {userId: '', username: ''});
+ }
+ }, [userId, userLogin]);
+
return userId ? : ;
};
diff --git a/src/routes/authentication/AuthProvider.tsx b/src/routes/authentication/AuthProvider.tsx
deleted file mode 100644
index 46f761e1..00000000
--- a/src/routes/authentication/AuthProvider.tsx
+++ /dev/null
@@ -1,315 +0,0 @@
-import AsyncStorage from '@react-native-community/async-storage';
-import React, {createContext, useEffect, useState} from 'react';
-import {INTEGRATED_SOCIAL_LIST} from '../../constants';
-import {
- loadAvatar,
- loadCover,
- loadFollowers,
- loadFollowing,
- loadMoments,
- loadProfileInfo,
- loadRecentlySearchedUsers,
- loadSocialPosts,
- getAllTaggUsers,
- loadBlockedUsers,
-} from '../../services';
-import {
- MomentType,
- ProfilePreviewType,
- ProfileType,
- SocialAccountType,
- UserType,
-} from '../../types';
-
-interface AuthContextProps {
- user: UserType;
- profile: ProfileType;
- login: (userId: string, username: string) => void;
- logout: () => void;
- avatar: string | null;
- cover: string | null;
- socialAccounts: Record;
- recentSearches: Array;
- taggUsers: Array;
- newMomentsAvailable: boolean;
- updateMoments: (value: boolean) => void;
- socialsNeedUpdate: (_: string[]) => void;
- moments: MomentType[];
- followers: ProfilePreviewType[];
- following: ProfilePreviewType[];
- followersNeedUpdate: boolean;
- updateFollowers: (value: boolean) => void;
- blockedUsers: ProfilePreviewType[];
- blockedUsersNeedUpdate: boolean;
- updateBlockedUsers: (value: boolean) => void;
- isEditedProfile: boolean;
- updateIsEditedProfile: (value: boolean) => void;
-}
-
-const NO_USER: UserType = {
- userId: '',
- username: '',
-};
-
-const NO_PROFILE: ProfileType = {
- biography: '',
- website: '',
- name: '',
- gender: '',
- birthday: undefined,
-};
-
-const NO_SOCIAL_ACCOUNTS: Record = {
- Instagram: {posts: []},
- Facebook: {posts: []},
- Twitter: {posts: []},
-};
-
-export const AuthContext = createContext({
- user: NO_USER,
- profile: NO_PROFILE,
- login: () => {},
- logout: () => {},
- avatar: null,
- cover: null,
- recentSearches: [],
- taggUsers: [],
- newMomentsAvailable: true,
- updateMoments: () => {},
- socialAccounts: NO_SOCIAL_ACCOUNTS,
- socialsNeedUpdate: () => {},
- moments: [],
- followers: [],
- following: [],
- followersNeedUpdate: true,
- updateFollowers: () => {},
- blockedUsers: [],
- blockedUsersNeedUpdate: true,
- updateBlockedUsers: () => {},
- isEditedProfile: false,
- updateIsEditedProfile: () => {},
-});
-
-/**
- * Authentication provider for the application.
- */
-const AuthProvider: React.FC = ({children}) => {
- const [user, setUser] = useState(NO_USER);
- const [profile, setProfile] = useState(NO_PROFILE);
- const [avatar, setAvatar] = useState(null);
- const [cover, setCover] = useState(null);
- const [socialAccounts, setSocialAccounts] = useState<
- Record
- >(NO_SOCIAL_ACCOUNTS);
- const [recentSearches, setRecentSearches] = useState<
- Array
- >([]);
- const [taggUsers, setTaggUsers] = useState>([]);
- const [newMomentsAvailable, setNewMomentsAvailable] = useState(true);
- // Default update all integrated social lists on start
- const [socialsNeedUpdate, setSocialsNeedUpdate] = useState([
- ...INTEGRATED_SOCIAL_LIST,
- ]);
- const [moments, setMoments] = useState>([]);
- const [followers, setFollowers] = useState>([]);
- const [following, setFollowing] = useState>([]);
- const [followersNeedUpdate, setFollowersNeedUpdate] = useState(true);
- const [blockedUsers, setBlockedUsers] = useState>(
- [],
- );
- const [blockedUsersNeedUpdate, setBlockedUsersNeedUpdate] = useState(
- true,
- );
- const [isEditedProfile, setIsEditedProfile] = useState(false);
- const {userId} = user;
-
- useEffect(() => {
- const loadUserInfoFromStorage = async () => {
- const [id, username, token] = await Promise.all([
- AsyncStorage.getItem('userId'),
- AsyncStorage.getItem('username'),
- AsyncStorage.getItem('token'),
- ]);
- if (id && username && token) {
- setUser({...user, userId: id, username});
- }
- };
- if (user === NO_USER) {
- loadUserInfoFromStorage();
- }
- }, [user]);
-
- useEffect(() => {
- if (!userId) {
- return;
- }
-
- const loadData = async () => {
- try {
- const token = await AsyncStorage.getItem('token');
- if (!token) {
- setUser(NO_USER);
- return;
- }
- loadProfileInfo(token, userId, setProfile);
- loadAvatar(token, userId, setAvatar);
- loadCover(token, userId, setCover);
- loadRecentlySearchedUsers(setRecentSearches);
- } catch (err) {
- console.log(err);
- }
- };
- loadData();
- }, [userId, isEditedProfile]);
-
- useEffect(() => {
- const loadNewMoments = async () => {
- try {
- const token = await AsyncStorage.getItem('token');
- if (!token) {
- setUser(NO_USER);
- return;
- }
- const newMoments = await loadMoments(userId, token);
- if (newMoments) {
- setMoments(newMoments);
- }
- setNewMomentsAvailable(false);
- } catch (error) {
- console.log(error);
- }
- };
- if (newMomentsAvailable && userId) {
- loadNewMoments();
- }
- }, [newMomentsAvailable, userId, moments]);
-
- useEffect(() => {
- const loadNewFollowers = async () => {
- try {
- const token = await AsyncStorage.getItem('token');
- if (!token) {
- setUser(NO_USER);
- return;
- }
- loadFollowers(userId, token, setFollowers);
- loadFollowing(userId, token, setFollowing);
- setFollowersNeedUpdate(false);
- } catch (error) {
- console.log(error);
- }
- };
- if (followersNeedUpdate && userId) {
- loadNewFollowers();
- }
- }, [followersNeedUpdate, userId, followers, following]);
-
- useEffect(() => {
- if (socialsNeedUpdate.length > 0 && userId) {
- for (let social of socialsNeedUpdate) {
- loadSocialPosts(userId, social).then((accountData) => {
- socialAccounts[social] = accountData;
- setSocialAccounts(socialAccounts);
- console.log('Refreshed posts data:', social);
- });
- }
- setSocialsNeedUpdate([]);
- }
- }, [socialAccounts, socialsNeedUpdate, userId]);
-
- useEffect(() => {
- const loadNewBlockedUsers = async () => {
- try {
- const token = await AsyncStorage.getItem('token');
- if (!token) {
- setUser(NO_USER);
- return;
- }
- loadBlockedUsers(userId, token, setBlockedUsers);
- setBlockedUsersNeedUpdate(false);
- } catch (error) {
- console.log(error);
- }
- };
- if (blockedUsersNeedUpdate && userId) {
- loadNewBlockedUsers();
- }
- }, [
- setBlockedUsersNeedUpdate,
- blockedUsersNeedUpdate,
- userId,
- setBlockedUsers,
- ]);
-
- useEffect(() => {
- const loadTaggUsers = async () => {
- try {
- const token = await AsyncStorage.getItem('token');
- if (!token) {
- setUser(NO_USER);
- return;
- }
- await getAllTaggUsers(token, setTaggUsers);
- } catch (error) {
- console.log(error);
- }
- };
- loadTaggUsers();
- }, [userId]);
-
- return (
- {
- setUser({...user, userId: id, username});
- },
- logout: () => {
- try {
- new Promise(() => {
- AsyncStorage.removeItem('token');
- AsyncStorage.removeItem('userId');
- AsyncStorage.removeItem('username');
- }).then(() => {
- setUser(NO_USER);
- });
- } catch (err) {
- console.log(err);
- }
- },
- recentSearches,
- taggUsers,
- updateMoments: (value) => {
- setNewMomentsAvailable(value);
- },
- socialsNeedUpdate: (socials: string[]) => {
- setSocialsNeedUpdate(socials);
- },
- updateFollowers: (value) => {
- setFollowersNeedUpdate(value);
- },
- updateBlockedUsers: (value) => {
- setBlockedUsersNeedUpdate(value);
- },
- updateIsEditedProfile: (value: boolean) => {
- setIsEditedProfile(value);
- },
- }}>
- {children}
-
- );
-};
-
-export default AuthProvider;
diff --git a/src/routes/authentication/index.ts b/src/routes/authentication/index.ts
deleted file mode 100644
index 9968ae93..00000000
--- a/src/routes/authentication/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export * from './AuthProvider';
-export {default} from './AuthProvider';
diff --git a/src/routes/index.ts b/src/routes/index.ts
index 7e8a84ce..3b74e130 100644
--- a/src/routes/index.ts
+++ b/src/routes/index.ts
@@ -1,7 +1,3 @@
-export {default as AuthProvider} from './authentication';
-export {default as ProfileProvider} from './viewProfile';
-export * from './authentication';
-export * from './viewProfile';
export * from './onboarding';
export * from './profile';
export {default} from './Routes';
diff --git a/src/routes/profile/Profile.tsx b/src/routes/profile/Profile.tsx
index b6672c85..f47d25c4 100644
--- a/src/routes/profile/Profile.tsx
+++ b/src/routes/profile/Profile.tsx
@@ -11,17 +11,17 @@ import {
} from '../../screens';
import {ProfileStack, ProfileStackParams} from './ProfileStack';
import {RouteProp} from '@react-navigation/native';
+import {ScreenType} from '../../types';
/**
- * What will be the First Screen of the stack depends on value of isProfileView (Search if its true else Profile)
* Trying to explain the purpose of each route on the stack (ACTUALLY A STACK)
- * Profile : To display the logged in user's profile when isProfileView is false, else displays profile of any user the logged in user wants to view.
- * When you click on the profile icon after looking at a user's profile, the stack is reset and you come back to the top of the stack (First screen : Profile in this case)
- * Search : To display the search screen. Search for a user on this screen, click on a result tile and navigate to the same (isProfileView = true).
+ * Profile : To display the logged in user's profile when the userXId passed in to it is (undefined | null | empty string) else displays profile of the user being visited.
+ * Search : To display the search screen. Search for a user on this screen, click on a result tile and navigate to the same.
* When you click on the search icon after looking at a user's profile, the stack gets reset and you come back to the top of the stack (First screen : Search in this case)
* SocialMediaTaggs : To display user data for any social media account set up by the user.
* IndividualMoment : To display individual images uploaded by the user (Navigate to comments from this screen, click on a commenter's profile pic / username, look at a user's profile. Click on the profile icon again to come back to your own profile).
* MomentCommentsScreen : Displays comments posted by users on an image uploaded by the user.
+ * EditProfile : To edit logged in user's information.
*/
type ProfileStackRouteProps = RouteProp;
@@ -31,7 +31,12 @@ interface ProfileStackProps {
}
const Profile: React.FC = ({route}) => {
- const {isProfileView} = route.params;
+ const {screenType} = route.params;
+
+ /**
+ * This parameter isProfileStack acts as a switch between Search and Profile Stacks
+ */
+ const isProfileStack = screenType === ScreenType.Profile;
return (
= ({route}) => {
}),
}}
mode="modal"
- initialRouteName={!isProfileView ? 'Profile' : 'Search'}>
+ initialRouteName={isProfileStack ? 'Profile' : 'Search'}>
- {isProfileView ? (
-
+ {!isProfileStack ? (
+
) : (
)}
@@ -77,8 +88,9 @@ const Profile: React.FC = ({route}) => {
headerBackTitleVisible: false,
headerTintColor: 'white',
}}
+ initialParams={{screenType}}
/>
- {!isProfileView ? (
+ {isProfileStack ? (
) : (
@@ -87,18 +99,18 @@ const Profile: React.FC = ({route}) => {
name="IndividualMoment"
component={IndividualMoment}
options={{headerShown: false}}
- initialParams={{isProfileView: isProfileView}}
+ initialParams={{screenType}}
/>
{
);
diff --git a/src/routes/viewProfile/ProfileProvider.tsx b/src/routes/viewProfile/ProfileProvider.tsx
deleted file mode 100644
index f2d27a84..00000000
--- a/src/routes/viewProfile/ProfileProvider.tsx
+++ /dev/null
@@ -1,207 +0,0 @@
-import AsyncStorage from '@react-native-community/async-storage';
-import React, {createContext, useEffect, useState} from 'react';
-import {Value} from 'react-native-reanimated';
-import {INTEGRATED_SOCIAL_LIST} from '../../constants';
-import {
- loadAvatar,
- loadCover,
- loadProfileInfo,
- loadSocialPosts,
- loadMoments,
- loadFollowers,
- loadFollowing,
-} from '../../services';
-import {
- ProfileType,
- SocialAccountType,
- ProfilePreviewType,
- UserType,
- MomentType,
-} from '../../types';
-
-interface ProfileContextProps {
- user: UserType;
- profile: ProfileType;
- avatar: string | null;
- cover: string | null;
- socialAccounts: Record;
- socialsNeedUpdate: (_: string[]) => void;
- moments: MomentType[];
- followers: ProfilePreviewType[];
- following: ProfilePreviewType[];
- followersNeedUpdate: boolean;
- updateFollowers: (value: boolean) => void;
-}
-const NO_USER: UserType = {
- userId: '',
- username: '',
-};
-const NO_PROFILE: ProfileType = {
- biography: '',
- website: '',
- name: '',
-};
-
-const NO_SOCIAL_ACCOUNTS: Record = {
- Instagram: {posts: []},
- Facebook: {posts: []},
- Twitter: {posts: []},
-};
-
-export const ProfileContext = createContext({
- user: NO_USER,
- profile: NO_PROFILE,
- avatar: null,
- cover: null,
- socialAccounts: NO_SOCIAL_ACCOUNTS,
- socialsNeedUpdate: () => {},
- moments: [],
- followers: [],
- following: [],
- followersNeedUpdate: true,
- updateFollowers: () => {},
-});
-
-/**
- * This is the context provider for user profiles that the logged in user wants to see
- * The ProfileProviderProps is used to initialise data as soon as the component is initialised.
- */
-
-type ProfileProviderProps = {
- uname: string;
- uId: string;
-};
-
-const ProfileProvider: React.FC = ({
- children,
- uId,
- uname,
-}) => {
- const [user, setUser] = useState({userId: uId, username: uname});
- const [profile, setProfile] = useState(NO_PROFILE);
- const [avatar, setAvatar] = useState(null);
- const [cover, setCover] = useState(null);
- const [newMomentsAvailable, setNewMomentsAvailable] = useState(true);
- const [socialAccounts, setSocialAccounts] = useState<
- Record
- >(NO_SOCIAL_ACCOUNTS);
- const [moments, setMoments] = useState>([]);
- const [followers, setFollowers] = useState>([]);
- const [following, setFollowing] = useState>([]);
- const [followersNeedUpdate, setFollowersNeedUpdate] = useState(true);
- // Default update all integrated social lists on start
- const [socialsNeedUpdate, setSocialsNeedUpdate] = useState([
- ...INTEGRATED_SOCIAL_LIST,
- ]);
-
- const {userId} = user;
- useEffect(() => {
- if (!userId) {
- return;
- }
- const loadData = async () => {
- try {
- const token = await AsyncStorage.getItem('token');
- if (!token) {
- setUser(NO_USER);
- return;
- }
- loadProfileInfo(token, userId, setProfile);
- loadAvatar(token, userId, setAvatar);
- loadCover(token, userId, setCover);
- } catch (err) {
- console.log(err);
- }
- };
- loadData();
- }, [userId]);
-
- useEffect(() => {
- const loadNewMoments = async () => {
- try {
- const token = await AsyncStorage.getItem('token');
- if (!token) {
- setUser(NO_USER);
- return;
- }
- const newMoments = await loadMoments(userId, token);
- if (newMoments) {
- setMoments(newMoments);
- }
- setNewMomentsAvailable(false);
- } catch (error) {
- console.log(error);
- }
- };
- if (newMomentsAvailable && userId) {
- loadNewMoments();
- }
- }, [newMomentsAvailable, userId]);
-
- useEffect(() => {
- const loadNewFollowers = async () => {
- try {
- const token = await AsyncStorage.getItem('token');
- if (!token) {
- setUser(NO_USER);
- return;
- }
- loadFollowers(userId, token, setFollowers);
- loadFollowing(userId, token, setFollowing);
- setFollowersNeedUpdate(false);
- } catch (error) {
- console.log(error);
- }
- };
- if (followersNeedUpdate && userId) {
- loadNewFollowers();
- }
- }, [followersNeedUpdate, userId, followers, following]);
-
- useEffect(() => {
- if (socialsNeedUpdate.length > 0 && userId) {
- for (let social of socialsNeedUpdate) {
- loadSocialPosts(userId, social).then((accountData) => {
- /**
- * Please use the following syntax when updating an object, fixing this problem broke our head. LOLs
- * ref1 : https://stackoverflow.com/questions/56423256/set-dynamic-key-in-state-via-usestate-react-hooks
- * ref2: https://stackoverflow.com/questions/43638938/updating-an-object-with-setstate-in-react/43639228
- * The spread operator {...} helps us make a simple copy of the object
- * And form there on we can use the [] to specify the dynamically constructed key and set its value.
- */
- setSocialAccounts((prevSocialAccounts) => ({
- ...prevSocialAccounts,
- [social]: accountData,
- }));
- console.log('Updated posts data', social);
- });
- }
- setSocialsNeedUpdate([]);
- }
- }, [socialAccounts, socialsNeedUpdate, userId]);
-
- return (
- {
- setSocialsNeedUpdate(socials);
- },
- updateFollowers: (value) => {
- setFollowersNeedUpdate(value);
- },
- }}>
- {children}
-
- );
-};
-
-export default ProfileProvider;
diff --git a/src/routes/viewProfile/index.ts b/src/routes/viewProfile/index.ts
deleted file mode 100644
index 7035ce4a..00000000
--- a/src/routes/viewProfile/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export * from './ProfileProvider';
-export {default} from './ProfileProvider';
--
cgit v1.2.3-70-g09d2