Browse Source

Profile Tab Screen Setup

fsavio-lab 1 year ago
parent
commit
3047649b10

+ 73 - 0
components/molecules/FormTextInput.js

@@ -0,0 +1,73 @@
+import {StyleSheet, Text, View} from 'react-native';
+import {TextInput} from 'react-native-paper'
+import React from 'react';
+import colors from '../../theme/colors';
+import fonts from '../../theme/fonts';
+
+const FormTextInput = props => {
+  const {title, placeholder, value, onChange } = props;
+
+  return (
+    <View style={styles.inputContainer}>
+      <View style={styles.header}>
+        <Text style={styles.inputTitleText}>{title}</Text>
+        <Text style={styles.requiredSymbol}>*</Text>
+      </View>
+      <TextInput
+        editable
+        mode='outlined'
+        placeholder={placeholder ?? 'Title'}
+        placeholderTextColor={colors.grayShade_300}
+        dense
+        style={{
+          fontFamily: fonts.type.medium,
+          fontSize: fonts.getSize(11),
+          paddingVertical: 2,
+          paddingHorizontal: 4,
+        }}
+        outlineStyle={{
+          borderRadius: 4,
+        }}
+        contentStyle={{
+          fontFamily: fonts.type.regular,
+          fontSize: fonts.getSize(14),
+          color: colors.gray,
+        }}
+        left={() => (
+          <IonIcon name="search-outline" size={24} color={colors.black} />
+        )}
+        right={() => <List.Icon icon={'search'} color={colors.black} />}
+        activeOutlineColor={colors.grayShade_300}
+        activeUnderlineColor={colors.grayShade_300}
+        outlineColor={colors.grayShade_300}
+        cursorColor={colors.secondaryColor}
+        selectionColor={colors.secondaryColor}
+        onChangeText={(text) => {
+         
+        }}
+        onSubmitEditing={null}
+        value={value}
+      />
+    </View>
+  );
+};
+
+export default FormTextInput;
+
+const styles = StyleSheet.create({
+  inputContainer: {
+    paddingTop: 4
+  },
+  inputTitleText: {
+    fontFamily: fonts.type.semibold,
+    color: colors.grayShade_200,
+  },
+  requiredSymbol: {
+    fontFamily: fonts.type.semibold,
+    color: colors.primaryColor,
+    marginLeft: 1
+  },
+  header: {
+    flexDirection: 'row'
+  },
+});

+ 29 - 0
components/organisms/Buttons/EditButton.js

@@ -0,0 +1,29 @@
+import { StyleSheet, Text, View } from 'react-native'
+import React from 'react'
+import MaterialIcon from 'react-native-vector-icons/MaterialIcons'
+import colors from '../../../theme/colors'
+import ButtonWrapper from '../../atoms/ButtonWrapper'
+const EditButton = (props) => {
+
+    const {
+        onPress,
+        buttonStyle,
+        iconColor,
+        iconSize
+    } = props
+
+  return (
+    <ButtonWrapper onPress={onPress} buttonStyle={buttonStyle}>
+      <MaterialIcon name='create' color={iconColor ? iconColor : styles.icon.color} size={iconSize ? iconSize : styles.icon.fontSize} />
+    </ButtonWrapper>
+  )
+}
+
+export default EditButton
+
+const styles = StyleSheet.create({
+    icon:{
+        fontSize: 20,
+        color: colors.primaryColor
+    }
+})

+ 1 - 1
components/organisms/Buttons/PrimaryButton.js

@@ -22,7 +22,7 @@ export default PrimaryButton
 const styles = StyleSheet.create({
   
     button:{
-        backgroundColor: colors.tertiaryColor,
+        backgroundColor: colors.primaryColor,
         maxWidth: '100%',
         width: '100%',
         alignItems:'center'

+ 29 - 8
components/organisms/Buttons/SecondaryButton.js

@@ -1,14 +1,35 @@
-import { StyleSheet, Text, View } from 'react-native'
+import { StyleSheet, Text, View} from 'react-native'
+import Button from '../../atoms/Button'
 import React from 'react'
+import colors from '../../../theme/colors'
+import fonts from '../../../theme/fonts'
 
-const SecondaryButton = () => {
-  return (
-    <View>
-      <Text>SecondaryButton</Text>
-    </View>
-  )
+const SecondaryButton = ({ onPress, title, buttonStyle, titleStyle }) => {
+    return (
+        <Button
+            onPress={onPress}
+            style={[styles.button,buttonStyle]}
+        >
+            <Text style={[styles.buttonTextStyle,titleStyle]}>
+                {title}
+            </Text>
+        </Button>
+    )
 }
 
 export default SecondaryButton
 
-const styles = StyleSheet.create({})
+const styles = StyleSheet.create({
+  
+    button:{
+        backgroundColor: colors.secondaryColor,
+        maxWidth: '100%',
+        width: '100%',
+        alignItems:'center'
+    },
+    buttonTextStyle:{
+        fontFamily: fonts.type.medium,
+        color: colors.white
+    }
+
+})

+ 23 - 0
components/organisms/Buttons/SettingsButton.js

@@ -0,0 +1,23 @@
+import { StyleSheet, Text, View } from 'react-native'
+import React from 'react'
+import FeatherIcon from 'react-native-vector-icons/Feather'
+import colors from '../../../theme/colors'
+import ButtonWrapper from '../../atoms/ButtonWrapper'
+
+const SettingsButton = ({onPress,buttonStyle,iconColor,iconSize}) => {
+    
+  return (
+    <ButtonWrapper onPress={onPress} buttonStyle={buttonStyle}>
+      <FeatherIcon name='settings' color={iconColor ? iconColor : styles.icon.color} size={iconSize ? iconSize : styles.icon.fontSize} />
+    </ButtonWrapper>
+  )
+}
+
+export default SettingsButton
+
+const styles = StyleSheet.create({
+    icon:{
+        fontSize: 20,
+        color: colors.primaryColor
+    }
+})

+ 3 - 7
navigation/HomePageNavigator.js

@@ -7,9 +7,7 @@ import fonts from '../theme/fonts';
 import NewscoutTitleHeader from '../components/organisms/Headers/NewscoutTitleHeader';
 import BookmarkNavigator from './BookmarkNavigator';
 import LandingPageNavigator from './LandingPageNavigator';
-import ProfilePage from '../screens/ProfilePage';
-
-
+import ProfileNavigator from './ProfileNavigator';
 
 const Tab = createBottomTabNavigator();
 
@@ -71,11 +69,9 @@ const HomePageNavigator = ({ route, navigation }) => {
             />
             <Tab.Screen
                 name="Profile"
-                component={ProfilePage}
+                component={ProfileNavigator}
                 options={() => ({
-                    header: () => <NewscoutTitleHeader title={"My Profile"} backButtonShown={false}>
-                        
-                    </NewscoutTitleHeader>
+                   headerShown: false
                 })}
             />
         </Tab.Navigator>

+ 17 - 7
navigation/ProfileNavigator.js

@@ -3,28 +3,38 @@ import React from 'react'
 import { createNativeStackNavigator } from '@react-navigation/native-stack'
 import ProfilePage from '../screens/ProfilePage';
 import SettingsPage from '../screens/SettingsPage';
+import EditProfilePage from '../screens/EditProfilePage';
 
 
 const Stack = createNativeStackNavigator();
 const ProfileNavigator = ({ route, navigation}) => {
     return (
         <Stack.Navigator
-            initialRouteName='Profile'
+            initialRouteName='DisplayProfile'
         >
             <Stack.Screen
-                name="Profile"
+                name="DisplayProfile"
                 options={(navigation) => ({
-                    
+                    headerShown: false
                 })}
                 component={ProfilePage}
             />
             <Stack.Screen
                 name="Settings"
-                options={(navigation) => {
-
-                }}
+                options={(navigation) => ({
+                    headerShown: false
+                })}
                 component={SettingsPage}
             />
+            <Stack.Screen
+                name="EditProfile"
+                options={(navigation) => ({
+                    headerShown: false
+                })}
+                component={EditProfilePage}
+            />
         </Stack.Navigator>
     )
-}
+}
+
+export default ProfileNavigator;

+ 78 - 0
screens/EditProfilePage.js

@@ -0,0 +1,78 @@
+import {Image, StyleSheet, Text, View, ScrollView} from 'react-native';
+import React, {useState} from 'react';
+import NewscoutTitleHeader from '../components/organisms/Headers/NewscoutTitleHeader';
+import fonts from '../theme/fonts';
+import images from '../assets/images/images';
+import colors from '../theme/colors';
+import FormTextInput from '../components/molecules/FormTextInput';
+import {capitalize} from '../utils/Constants/functions';
+import SecondaryButton from '../components/organisms/Buttons/SecondaryButton';
+
+const PROFILE_SIZE = 128;
+
+const EditProfilePage = props => {
+  const {navigation, route, name, profileQuote, metrics} = props;
+
+  const [profileData, setProfileData] = useState({
+    username: '',
+    fullname: '',
+    email: '',
+    phone: '',
+    about: '',
+  });
+
+  return (
+    <View style={styles.container}>
+      <ScrollView showsVerticalScrollIndicator={false}>
+        <NewscoutTitleHeader
+          title={'Edit Profile'}
+          backButtonShown={true}
+          onBackClick={() => navigation.goBack()}
+          titleStyle={{fontFamily: fonts.type.medium}}
+        />
+        <View style={styles.profileImageContainer}>
+          <Image source={images.imageCard} style={styles.profileImage}></Image>
+        </View>
+        <View style={{paddingHorizontal: 16, gap: 4}}>
+          {Object.keys(profileData).map(key => (
+            <FormTextInput
+              title={capitalize(key)}
+              placeholder={capitalize(key)}
+              value={profileData[key]}
+              onChange={text =>
+                setProfileData(prev => ({...prev, [key]: text}))
+              }
+            />
+          ))}
+          <SecondaryButton 
+            title={'Continue'} 
+            onPress={true}
+            buttonStyle={{
+              marginVertical: 16,
+              width:'auto'
+            }}
+        />
+        </View>
+        
+      </ScrollView>
+    </View>
+  );
+};
+
+export default EditProfilePage;
+
+const styles = StyleSheet.create({
+  container: {
+    backgroundColor: colors.white,
+    height: '100%',
+  },
+  profileImageContainer: {
+    paddingVertical: 16,
+    alignItems: 'center',
+  },
+  profileImage: {
+    borderRadius: PROFILE_SIZE,
+    height: PROFILE_SIZE,
+    width: PROFILE_SIZE,
+  },
+});

+ 2 - 2
screens/LoginPage.js

@@ -1,10 +1,10 @@
 import { Image, StyleSheet, Text, View } from 'react-native'
 import React from 'react'
 import colors from '../theme/colors'
-import PrimaryButton from '../components/organisms/Buttons/PrimaryButton'
 import fonts from '../theme/fonts'
 import NewscoutTextLogo from '../components/molecules/NewscoutTextLogo'
 import images from '../assets/images/images'
+import SecondaryButton from '../components/organisms/Buttons/SecondaryButton'
 
 
 const LoginPage = ({ navigation }) => {
@@ -25,7 +25,7 @@ const LoginPage = ({ navigation }) => {
                 <Text style={[styles.tagline,{color:colors.black}]}> Get the latest news from </Text>
                 <Text style={[styles.tagline,{color:colors.topColor}]}> reliable sources. </Text>
             </View>
-            <PrimaryButton
+            <SecondaryButton
                 title="Next"
                 onPress={homePageNavigation}
             />

+ 202 - 44
screens/ProfilePage.js

@@ -1,48 +1,206 @@
-import { Image, StyleSheet, Text, View } from 'react-native'
-import React from 'react'
-import images from '../assets/images/images'
-
-const PROFILE_SIZE = 128
-
-const ProfilePage = (props) => {
-
-    const {
-        navigation,
-        route,
-        name,
-        profileQuote,
-        metrics
-    } = props
-
-    return (
-        <View style={styles.profileContainer}>
-            <View style={styles.profileImageContainer}>
-                <Image source={images.imageCard} style={styles.profileImage}>
-
-                </Image>
-            </View>
-            <Text>Semina Gurung</Text>
-            <Text>
-                The reason behind their disappointment is that iPhone users have been..
-            </Text>
-            
+import {
+  FlatList,
+  ScrollView,
+  Image,
+  StyleSheet,
+  Text,
+  View,
+} from 'react-native';
+import React, {useState} from 'react';
+import images from '../assets/images/images';
+import fonts from '../theme/fonts';
+import colors from '../theme/colors';
+import {ToggleButton} from 'react-native-paper';
+import HorizontalNewsCardVariant from '../components/organisms/Cards/HorizontalNewsCardVariant';
+import NewscoutTitleHeader from '../components/organisms/Headers/NewscoutTitleHeader';
+import SettingsButton from '../components/organisms/Buttons/SettingsButton';
+import EditButton from '../components/organisms/Buttons/EditButton';
+
+const PROFILE_SIZE = 128;
+
+const profileTabs = ['Recently Read', 'Others'];
+
+const ProfilePage = props => {
+  const {navigation, route, name, profileQuote, metrics} = props;
+
+  const metricsCount = {
+    bookmarks: 158,
+    followers: 158,
+    following: 158,
+  };
+
+  const [categoryValue, setCategoryValue] = useState(
+    profileTabs[0].toLowerCase(),
+  );
+
+  return (
+    <View style={styles.profileContainer}>
+      <ScrollView showsVerticalScrollIndicator={false}>
+        <NewscoutTitleHeader
+          title="My Profile"
+          backButtonShown={true}
+          onBackClick={() => navigation.goBack()}>
+          <View style={{flexDirection: 'row', gap: 16}}>
+            <SettingsButton onPress={() => navigation.navigate('Settings')} />
+            <EditButton
+              onPress={() =>
+                navigation.navigate('Profile', {screen: 'EditProfile'})
+              }
+            />
+          </View>
+        </NewscoutTitleHeader>
+
+        <View style={styles.profileImageContainer}>
+          <Image source={images.imageCard} style={styles.profileImage}></Image>
+        </View>
+        <Text
+          style={{
+            alignSelf: 'center',
+            paddingVertical: 8,
+            fontFamily: fonts.type.semibold,
+            fontSize: fonts.getSize(14),
+            color: colors.black,
+          }}>
+          Semina Gurung
+        </Text>
+        <Text
+          style={{
+            paddingHorizontal: 16,
+            fontFamily: fonts.type.regular,
+            fontSize: fonts.getSize(12),
+          }}>
+          The reason behind their disappointment is that iPhone users have
+          been..
+        </Text>
+        <View style={styles.metricsCountContainer}>
+          <View style={styles.metricsCard}>
+            <Text style={styles.metricsCount}>158</Text>
+            <Text style={styles.metricsTitle}>Bookmarks</Text>
+          </View>
+          <View style={styles.verticalLine}></View>
+          <View style={styles.metricsCard}>
+            <Text style={styles.metricsCount}>158</Text>
+            <Text style={styles.metricsTitle}>Followers</Text>
+          </View>
+          <View style={styles.verticalLine}></View>
+          <View style={styles.metricsCard}>
+            <Text style={styles.metricsCount}>158</Text>
+            <Text style={styles.metricsTitle}>Following</Text>
+          </View>
+        </View>
+        <View style={styles.underlinePillContainer}>
+          {/* <ScrollView horizontal showsHorizontalScrollIndicator={false}> */}
+          <ToggleButton.Group onValueChange={value => setCategoryValue(value)}>
+            {profileTabs.map(tab => {
+              let valueId = tab.toLowerCase();
+              return (
+                <ToggleButton
+                  icon={() => (
+                    <Text
+                      style={[
+                        valueId === categoryValue
+                          ? styles.selectedPillText
+                          : styles.pillText,
+                        {
+                          paddingHorizontal: fonts.getSize(11),
+                          fontSize: fonts.getSize(16),
+                        },
+                      ]}>
+                      {tab}
+                    </Text>
+                  )}
+                  style={[styles.underlinePill]}
+                  value={valueId}
+                />
+              );
+            })}
+          </ToggleButton.Group>
+          {/* </ScrollView> */}
+        </View>
+        <View style={styles.profileCardContainer}>
+          <FlatList
+            scrollEnabled={false}
+            showsVerticalScrollIndicator={false}
+            ItemSeparatorComponent={() => (
+              <View style={{height: fonts.getSize(8)}}></View>
+            )}
+            // ListFooterComponent={() => <View style={{height: fonts.getSize(16)}}></View>}
+            ListHeaderComponent={() => (
+              <View style={{height: fonts.getSize(16)}}></View>
+            )}
+            data={[{}, {}, {}]}
+            renderItem={item => <HorizontalNewsCardVariant onPress={true} />}
+            keyExtractor={item => item.index}
+          />
         </View>
-    )
-}
+      </ScrollView>
+    </View>
+  );
+};
 
-export default ProfilePage
+export default ProfilePage;
 
 const styles = StyleSheet.create({
-    profileContainer: {
-
-    },
-    profileImageContainer: {
-        paddingVertical: 16,
-        alignItems: 'center'
-    },
-    profileImage: {
-        borderRadius: PROFILE_SIZE,
-        height: PROFILE_SIZE,
-        width: PROFILE_SIZE
-    }
-})
+  profileContainer: {
+    backgroundColor: colors.white,
+  },
+  profileImageContainer: {
+    paddingVertical: 16,
+    alignItems: 'center',
+  },
+  profileImage: {
+    borderRadius: PROFILE_SIZE,
+    height: PROFILE_SIZE,
+    width: PROFILE_SIZE,
+  },
+  metricsCountContainer: {
+    flexDirection: 'row',
+    alignItems: 'center',
+    justifyContent: 'space-evenly',
+    paddingVertical: 20,
+    paddingHorizontal: 16,
+  },
+  metricsCard: {},
+  metricsTitle: {
+    color: colors.primaryColor,
+    fontFamily: fonts.type.medium,
+    fontSize: 16,
+  },
+  metricsCount: {
+    color: colors.black,
+    fontFamily: fonts.type.semibold,
+    fontSize: 16,
+    textAlign: 'center',
+  },
+  verticalLine: {
+    height: '100%',
+    width: 2,
+    backgroundColor: colors.grayShade_400,
+  },
+  underlinePillContainer: {
+    paddingVertical: fonts.getSize(8),
+    flexDirection: 'row',
+    alignItems: 'space-between',
+    justifyContent: 'space-around',
+    paddingHorizontal: 16,
+  },
+  selectedPillText: {
+    fontFamily: fonts.type.semibold,
+    fontSize: fonts.getSize(12),
+    color: colors.black,
+    borderBottomWidth: fonts.getSize(4),
+    borderBottomColor: colors.primaryColor,
+    borderRadius: 0,
+  },
+  pillText: {
+    fontFamily: fonts.type.semibold,
+    fontSize: fonts.getSize(12),
+    color: colors.gray,
+  },
+  underlinePill: {
+    width: 'auto',
+  },
+  profileCardContainer: {
+    paddingHorizontal: 16,
+  },
+});

+ 46 - 6
screens/SettingsPage.js

@@ -4,9 +4,14 @@ import { List } from 'react-native-paper';
 import EntypoIcon from 'react-native-vector-icons/dist/Entypo'
 import colors from '../theme/colors';
 import fonts from '../theme/fonts';
+import NewscoutTitleHeader from '../components/organisms/Headers/NewscoutTitleHeader';
 
 
-const SettingsPage = () => {
+const SettingsPage = (props) => {
+
+    const {
+      navigation
+    } = props
 
   const listItem = [
     {
@@ -47,13 +52,10 @@ const SettingsPage = () => {
   ]
   return (
     <View style={styles.container}>
+      <NewscoutTitleHeader title="Settings" backButtonShown={true} onBackClick={() => navigation.goBack()}/>
       <ScrollView>
       {listItem.map((item) => 
-        <List.Item title={item.title}
-          titleStyle={styles.listItemText}
-          key={item.id}
-          left={props=><List.Icon {...props} size={24} style={{paddingHorizontal: 16}}  icon={item.icon} color={colors.topColor}/>} 
-          right={props => <EntypoIcon name="chevron-thin-right" size={16} color={colors.black}/>}/>
+         <SettingListItem title={item.title} key={item.id} id={item.id} icon={item.icon}/> 
       )}
       </ScrollView>
      
@@ -61,10 +63,48 @@ const SettingsPage = () => {
   )
 }
 
+const SettingListItem = (props) => {
+  const {
+    title,
+    id,
+    icon
+  } = props
+  
+  return (
+    <>
+      <List.Item title={title}
+          titleStyle={styles.listItemText}
+          key={id}
+          left={props => 
+              <List.Icon 
+              {...props}
+              size={24} 
+              style={styles.circularIcon}
+              icon={icon}
+              color={colors.topColor}/>
+            } 
+          right={props => <EntypoIcon name="chevron-thin-right" size={16} color={colors.black}/>}/>
+    </>
+  )
+}
+
 export default SettingsPage
 
 const styles = StyleSheet.create({
+    container:{
+      backgroundColor: colors.white,
+      height: '100%'
+    },
     listItemText:{
       fontFamily: fonts.type.medium
+    },
+    circularIcon:{
+      backgroundColor: colors.primaryTintColor,
+      marginLeft: 16,
+      padding:8,
+      // maxHeight:48,
+      // maxWidth: 48,
+      borderRadius: 32,
+      
     }
 })

+ 3 - 2
screens/UnsignedLandingPage.js

@@ -6,6 +6,7 @@ import PrimaryButton from '../components/organisms/Buttons/PrimaryButton'
 import { Portal, ToggleButton, Modal, PaperProvider, IconButton } from 'react-native-paper'
 import HorizontalNewsCardVariant from '../components/organisms/Cards/HorizontalNewsCardVariant'
 import NewscoutHomeHeader from '../components/organisms/Headers/NewscoutHomeHeader'
+import SecondaryButton from '../components/organisms/Buttons/SecondaryButton'
 
 const UnsignedLandingPage = ({ navigation }) => {
 
@@ -44,7 +45,7 @@ const UnsignedLandingPage = ({ navigation }) => {
                         >
                             You are not logged in. Log in to bookmark news, leave comment and to explore more!
                         </Text>
-                        <PrimaryButton title="Login" onPress={homePageNavigation} />
+                        <SecondaryButton title="Login" onPress={homePageNavigation} />
                         <View style={{ flexDirection: 'row', justifyContent:'center',alignItems:'center',paddingVertical:fonts.getSize(16)}}>
                             <Text 
                                 style={{
@@ -55,7 +56,7 @@ const UnsignedLandingPage = ({ navigation }) => {
                             <TouchableWithoutFeedback onPress={true}>
                                 <Text
                                     style={{
-                                        color: colors.tertiaryColor,
+                                        color: colors.secondaryColor,
                                         fontFamily: fonts.type.regular
                                     }}
                                 >

+ 2 - 0
utils/Constants/functions.js

@@ -10,3 +10,5 @@ export const useConstructor = (callBack = () => {}) => {
     setHasBeenCalled(true);
 }
 
+export const capitalize = (str) => str.charAt(0).toUpperCase() + str.substring(1,str.length).toLowerCase()
+