diff options
Diffstat (limited to 'src/routes')
| -rw-r--r-- | src/routes/Routes.tsx | 24 | ||||
| -rw-r--r-- | src/routes/authentication/AuthProvider.tsx | 315 | ||||
| -rw-r--r-- | src/routes/authentication/index.ts | 2 | ||||
| -rw-r--r-- | src/routes/index.ts | 4 | ||||
| -rw-r--r-- | src/routes/profile/Profile.tsx | 38 | ||||
| -rw-r--r-- | src/routes/profile/ProfileStack.tsx | 36 | ||||
| -rw-r--r-- | src/routes/tabs/NavigationBar.tsx | 5 | ||||
| -rw-r--r-- | src/routes/viewProfile/ProfileProvider.tsx | 207 | ||||
| -rw-r--r-- | src/routes/viewProfile/index.ts | 2 |
9 files changed, 68 insertions, 565 deletions
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 ? <NavigationBar /> : <Onboarding />; }; 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<string, SocialAccountType>; - recentSearches: Array<ProfilePreviewType>; - taggUsers: Array<ProfilePreviewType>; - 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<string, SocialAccountType> = { - Instagram: {posts: []}, - Facebook: {posts: []}, - Twitter: {posts: []}, -}; - -export const AuthContext = createContext<AuthContextProps>({ - 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<UserType>(NO_USER); - const [profile, setProfile] = useState<ProfileType>(NO_PROFILE); - const [avatar, setAvatar] = useState<string | null>(null); - const [cover, setCover] = useState<string | null>(null); - const [socialAccounts, setSocialAccounts] = useState< - Record<string, SocialAccountType> - >(NO_SOCIAL_ACCOUNTS); - const [recentSearches, setRecentSearches] = useState< - Array<ProfilePreviewType> - >([]); - const [taggUsers, setTaggUsers] = useState<Array<ProfilePreviewType>>([]); - const [newMomentsAvailable, setNewMomentsAvailable] = useState<boolean>(true); - // Default update all integrated social lists on start - const [socialsNeedUpdate, setSocialsNeedUpdate] = useState<string[]>([ - ...INTEGRATED_SOCIAL_LIST, - ]); - const [moments, setMoments] = useState<Array<MomentType>>([]); - const [followers, setFollowers] = useState<Array<ProfilePreviewType>>([]); - const [following, setFollowing] = useState<Array<ProfilePreviewType>>([]); - const [followersNeedUpdate, setFollowersNeedUpdate] = useState<boolean>(true); - const [blockedUsers, setBlockedUsers] = useState<Array<ProfilePreviewType>>( - [], - ); - const [blockedUsersNeedUpdate, setBlockedUsersNeedUpdate] = useState<boolean>( - true, - ); - const [isEditedProfile, setIsEditedProfile] = useState<boolean>(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 ( - <AuthContext.Provider - value={{ - user, - profile, - avatar, - cover, - newMomentsAvailable, - socialAccounts, - moments, - followers, - following, - followersNeedUpdate, - blockedUsers, - blockedUsersNeedUpdate, - isEditedProfile, - login: (id, username) => { - 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} - </AuthContext.Provider> - ); -}; - -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<ProfileStackParams, 'Profile'>; @@ -31,7 +31,12 @@ interface ProfileStackProps { } const Profile: React.FC<ProfileStackProps> = ({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 ( <ProfileStack.Navigator screenOptions={{ @@ -56,15 +61,21 @@ const Profile: React.FC<ProfileStackProps> = ({route}) => { }), }} mode="modal" - initialRouteName={!isProfileView ? 'Profile' : 'Search'}> + initialRouteName={isProfileStack ? 'Profile' : 'Search'}> <ProfileStack.Screen name="Profile" component={ProfileScreen} options={{headerShown: false}} - initialParams={{isProfileView: isProfileView}} + initialParams={{ + screenType, + }} /> - {isProfileView ? ( - <ProfileStack.Screen name="Search" component={SearchScreen} /> + {!isProfileStack ? ( + <ProfileStack.Screen + name="Search" + component={SearchScreen} + initialParams={{screenType}} + /> ) : ( <React.Fragment /> )} @@ -77,8 +88,9 @@ const Profile: React.FC<ProfileStackProps> = ({route}) => { headerBackTitleVisible: false, headerTintColor: 'white', }} + initialParams={{screenType}} /> - {!isProfileView ? ( + {isProfileStack ? ( <ProfileStack.Screen name="CaptionScreen" component={CaptionScreen} /> ) : ( <React.Fragment /> @@ -87,18 +99,18 @@ const Profile: React.FC<ProfileStackProps> = ({route}) => { name="IndividualMoment" component={IndividualMoment} options={{headerShown: false}} - initialParams={{isProfileView: isProfileView}} + initialParams={{screenType}} /> <ProfileStack.Screen name="MomentCommentsScreen" component={MomentCommentsScreen} options={{headerShown: false}} - initialParams={{isProfileView: isProfileView}} + initialParams={{screenType}} /> <ProfileStack.Screen name="FollowersListScreen" component={FollowersListScreen} - initialParams={{isProfileView: isProfileView}} + initialParams={{screenType}} /> <ProfileStack.Screen name="EditProfile" diff --git a/src/routes/profile/ProfileStack.tsx b/src/routes/profile/ProfileStack.tsx index 5590f78a..e7db9f37 100644 --- a/src/routes/profile/ProfileStack.tsx +++ b/src/routes/profile/ProfileStack.tsx @@ -1,41 +1,45 @@ +/** + * Note the name userXId here, it refers to the id of the user being visited + */ import {createStackNavigator} from '@react-navigation/stack'; -import {MomentType, ProfilePreviewType, SocialAccountType} from '../../types'; +import {MomentType, ScreenType} from '../../types'; export type ProfileStackParams = { - Search: undefined; + Search: { + screenType: ScreenType; + }; Profile: { - isProfileView: boolean; - username: string; - userId: string; + userXId: string | undefined; + screenType: ScreenType; }; SocialMediaTaggs: { socialMediaType: string; - socialMediaHandle: string; - isProfileView: boolean; - name: string; - accountData: SocialAccountType; - avatar: string; + userXId: string | undefined; + screenType: ScreenType; }; CaptionScreen: { title: string; image: object; + screenType: ScreenType; }; IndividualMoment: { moment: MomentType; - isProfileView: boolean; - username: string; + userXId: string | undefined; + screenType: ScreenType; }; MomentCommentsScreen: { - isProfileView: boolean; moment_id: string; + userXId: string | undefined; + screenType: ScreenType; }; FollowersListScreen: { isFollowers: boolean; - list: ProfilePreviewType[]; + userXId: string | undefined; + screenType: ScreenType; }; EditProfile: { - userId: boolean; - username: ProfilePreviewType[]; + userId: string; + username: string; }; }; diff --git a/src/routes/tabs/NavigationBar.tsx b/src/routes/tabs/NavigationBar.tsx index 67f842e0..8fcbb869 100644 --- a/src/routes/tabs/NavigationBar.tsx +++ b/src/routes/tabs/NavigationBar.tsx @@ -1,6 +1,7 @@ import {createBottomTabNavigator} from '@react-navigation/bottom-tabs'; import React, {Fragment} from 'react'; import {NavigationIcon} from '../../components'; +import {ScreenType} from '../../types'; import Profile from '../profile/Profile'; const Tabs = createBottomTabNavigator(); @@ -45,12 +46,12 @@ const NavigationBar: React.FC = () => { <Tabs.Screen name="Search" component={Profile} - initialParams={{isProfileView: true}} + initialParams={{screenType: ScreenType.Search}} /> <Tabs.Screen name="Profile" component={Profile} - initialParams={{isProfileView: false}} + initialParams={{screenType: ScreenType.Profile}} /> </Tabs.Navigator> ); 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<string, SocialAccountType>; - 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<string, SocialAccountType> = { - Instagram: {posts: []}, - Facebook: {posts: []}, - Twitter: {posts: []}, -}; - -export const ProfileContext = createContext<ProfileContextProps>({ - 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<ProfileProviderProps> = ({ - children, - uId, - uname, -}) => { - const [user, setUser] = useState<UserType>({userId: uId, username: uname}); - const [profile, setProfile] = useState<ProfileType>(NO_PROFILE); - const [avatar, setAvatar] = useState<string | null>(null); - const [cover, setCover] = useState<string | null>(null); - const [newMomentsAvailable, setNewMomentsAvailable] = useState<boolean>(true); - const [socialAccounts, setSocialAccounts] = useState< - Record<string, SocialAccountType> - >(NO_SOCIAL_ACCOUNTS); - const [moments, setMoments] = useState<Array<MomentType>>([]); - const [followers, setFollowers] = useState<Array<ProfilePreviewType>>([]); - const [following, setFollowing] = useState<Array<ProfilePreviewType>>([]); - const [followersNeedUpdate, setFollowersNeedUpdate] = useState<boolean>(true); - // Default update all integrated social lists on start - const [socialsNeedUpdate, setSocialsNeedUpdate] = useState<string[]>([ - ...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 ( - <ProfileContext.Provider - value={{ - user, - profile, - avatar, - cover, - socialAccounts, - moments, - followers, - following, - followersNeedUpdate, - socialsNeedUpdate: (socials: string[]) => { - setSocialsNeedUpdate(socials); - }, - updateFollowers: (value) => { - setFollowersNeedUpdate(value); - }, - }}> - {children} - </ProfileContext.Provider> - ); -}; - -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'; |
