Overview
The profile screen provides riders with access to their personal information, account settings, and logout functionality. It displays user details retrieved from secure storage and offers quick access to account management features.
Profile Screen
Main Component
The profile screen combines user information display with navigation to various settings.
src/app/(parcel)/(tabs)/profile.tsx
import { IconSymbol } from "@/components/ui/icon-symbol" ;
import { ProfileMenuItem } from "@/modules/dashboard/profile/profile-menu-item" ;
import type { User } from "@/types/auth.types" ;
import { getInitials } from "@/utils/common" ;
import { Storage , StorageKeys } from "@/utils/storage" ;
import { useRouter } from "expo-router" ;
import { useMemo } from "react" ;
import { Alert , Pressable , ScrollView , Text , View } from "react-native" ;
export default function Profile () {
const router = useRouter ();
const user = useMemo (() => {
return Storage . getObject ( StorageKeys . USER ) as User | null ;
}, []);
const handleLogout = () => {
Alert . alert (
"Logout" ,
"Are you sure you want to logout?" ,
[
{ text: "Cancel" , style: "cancel" },
{
text: "Logout" ,
style: "destructive" ,
onPress : async () => {
try {
await Storage . deleteToken ( StorageKeys . AUTH_TOKEN );
await Storage . deleteToken ( StorageKeys . REFRESH_TOKEN );
Storage . removeItem ( StorageKeys . USER );
router . replace ( "/(public)/(auth)/sign-in" );
} catch ( error ) {
console . error ( "Logout error:" , error );
Alert . alert ( "Error" , "Failed to logout. Please try again." );
}
},
},
],
{ cancelable: true },
);
};
return (
< View className = "flex-1 bg-background pt-safe" >
< ScrollView showsVerticalScrollIndicator = { false } >
{ /* Header Section */ }
< View className = "items-center pt-8 pb-6 px-5" >
< View className = "relative mb-4" >
< View
className = "w-[100px] h-[100px] rounded-full items-center justify-center"
style = { { backgroundColor: accentColor } }
>
< Text className = "text-4xl font-bold text-white" >
{ getInitials ( user ?. fullName || "U" ) }
</ Text >
</ View >
{ user ?. isVerified && (
< View className = "absolute bottom-0 right-0 bg-white rounded-xl p-1" >
< IconSymbol name = "checkmark.seal.fill" size = { 16 } color = "#10B981" />
</ View >
) }
</ View >
< Text className = "text-[32px] font-bold text-center text-secondary" >
{ user ?. fullName || "User" }
</ Text >
{ user ?. phone && (
< View className = "flex-row items-center gap-2 mb-2" >
< IconSymbol name = "phone.fill" size = { 16 } />
< Text className = "text-sm opacity-70 text-secondary" > { user . phone } </ Text >
</ View >
) }
{ user ?. email && (
< View className = "flex-row items-center gap-2 mb-2" >
< IconSymbol name = "envelope.fill" size = { 16 } />
< Text className = "text-sm opacity-70 text-secondary" > { user . email } </ Text >
</ View >
) }
</ View >
{ /* Account Section */ }
< View className = "mt-2 px-5" >
< Text className = "text-xl font-bold mb-3 mt-2 opacity-80 text-secondary" >
Account
</ Text >
< View className = "bg-transparent rounded-xl overflow-hidden mb-2" >
< ProfileMenuItem
icon = "pencil"
title = "Edit Profile"
subtitle = "Update your personal information"
disabled = { true }
/>
< ProfileMenuItem
icon = "lock.fill"
title = "Change Password"
subtitle = "Update your password"
disabled = { true }
/>
</ View >
</ View >
{ /* Settings Section */ }
< View className = "mt-2 px-5" >
< Text className = "text-xl font-bold mb-3 mt-2 opacity-80 text-secondary" >
Settings
</ Text >
< View className = "bg-transparent rounded-xl overflow-hidden mb-2" >
< ProfileMenuItem
icon = "gearshape.fill"
title = "App Settings"
subtitle = "Notifications, preferences, and more"
disabled = { true }
/>
< ProfileMenuItem
icon = "phone.fill"
title = "Contact Support"
subtitle = "Get help from our support team"
disabled = { true }
/>
</ View >
</ View >
{ /* Logout Button */ }
< View className = "px-5 mt-6" >
< Pressable
onPress = { handleLogout }
className = "flex-row items-center justify-center gap-2 py-3.5 rounded-xl bg-red-500"
>
< IconSymbol
name = "rectangle.portrait.and.arrow.right"
size = { 20 }
color = "#FFFFFF"
/>
< Text className = "text-white text-base font-semibold" > Logout </ Text >
</ Pressable >
</ View >
{ /* Version Info */ }
< View className = "items-center mt-8 px-5" >
< Text className = "text-xs opacity-50 text-secondary" > Version 1.0.0 </ Text >
</ View >
</ ScrollView >
</ View >
);
}
The profile screen displays key user information retrieved from secure storage.
Avatar Shows user initials with a colored background and verification badge if applicable.
Full Name Displays the rider’s complete name prominently.
Contact Details Shows phone number and email address with appropriate icons.
User Data Retrieval
const user = useMemo (() => {
return Storage . getObject ( StorageKeys . USER ) as User | null ;
}, []);
User Type Definition
export interface User {
id : string ;
fullName : string ;
phone : string ;
email ?: string ;
address ?: string ;
profilePicture ?: string ;
isVerified : boolean ;
role : string ;
createdAt : string ;
updatedAt : string ;
}
Avatar Display
The profile avatar shows user initials with a verification badge for verified accounts.
< View className = "relative mb-4" >
< View
className = "w-[100px] h-[100px] rounded-full items-center justify-center"
style = { { backgroundColor: accentColor } }
>
< Text className = "text-4xl font-bold text-white" >
{ getInitials ( user ?. fullName || "U" ) }
</ Text >
</ View >
{ user ?. isVerified && (
< View className = "absolute bottom-0 right-0 bg-white rounded-xl p-1" >
< IconSymbol name = "checkmark.seal.fill" size = { 16 } color = "#10B981" />
</ View >
) }
</ View >
Get Initials Helper
export function getInitials ( name : string ) : string {
return name
. split ( " " )
. map (( n ) => n [ 0 ])
. join ( "" )
. toUpperCase ()
. slice ( 0 , 2 );
}
The profile screen includes organized menu sections for account and settings.
src/modules/dashboard/profile/profile-menu-item.tsx
import { IconSymbol } from "@/components/ui/icon-symbol" ;
import { Pressable , Text , View } from "react-native" ;
interface ProfileMenuItemProps {
icon : string ;
title : string ;
subtitle : string ;
onPress ?: () => void ;
disabled ?: boolean ;
}
export function ProfileMenuItem ({
icon ,
title ,
subtitle ,
onPress ,
disabled = false ,
} : ProfileMenuItemProps ) {
return (
< Pressable
onPress = { onPress }
disabled = { disabled }
className = "flex-row items-center py-4 px-4 border-b border-gray-100"
>
< View className = "bg-gray-100 rounded-full p-3 mr-4" >
< IconSymbol name = { icon } size = { 20 } />
</ View >
< View className = "flex-1" >
< Text className = "text-base font-semibold text-secondary" > { title } </ Text >
< Text className = "text-sm text-gray-500 mt-0.5" > { subtitle } </ Text >
</ View >
{ ! disabled && < IconSymbol name = "chevron.right" size = { 20 } color = "#9ca3af" /> }
</ Pressable >
);
}
Edit Profile : Update personal information (coming soon)
Change Password : Modify account password (coming soon)
App Settings : Configure notifications and preferences (coming soon)
Contact Support : Reach out to the support team (coming soon)
Some menu items are currently disabled as their functionality is under development. They’re displayed to provide a preview of upcoming features.
Logout Functionality
The logout feature securely clears all user data and tokens.
Logout Handler
const handleLogout = () => {
Alert . alert (
"Logout" ,
"Are you sure you want to logout?" ,
[
{
text: "Cancel" ,
style: "cancel" ,
},
{
text: "Logout" ,
style: "destructive" ,
onPress : async () => {
try {
await Storage . deleteToken ( StorageKeys . AUTH_TOKEN );
await Storage . deleteToken ( StorageKeys . REFRESH_TOKEN );
Storage . removeItem ( StorageKeys . USER );
router . replace ( "/(public)/(auth)/sign-in" );
} catch ( error ) {
console . error ( "Logout error:" , error );
Alert . alert ( "Error" , "Failed to logout. Please try again." );
}
},
},
],
{ cancelable: true },
);
};
Logout Process
Show Confirmation
Display a native alert asking the user to confirm logout action.
Delete Tokens
Remove authentication and refresh tokens from secure storage.
Clear User Data
Remove cached user object from MMKV storage.
Navigate to Login
Redirect to the sign-in screen using router.replace.
Error Handling
Show error alert if logout process fails.
Storage Cleanup
// Delete secure tokens
await Storage . deleteToken ( StorageKeys . AUTH_TOKEN );
await Storage . deleteToken ( StorageKeys . REFRESH_TOKEN );
// Remove user object
Storage . removeItem ( StorageKeys . USER );
The logout process uses router.replace() instead of router.push() to prevent users from navigating back to authenticated screens using the back button.
Confirmation Dialog
The app uses the native Alert API for logout confirmation.
Alert . alert (
"Logout" , // Title
"Are you sure you want to logout?" , // Message
[
{
text: "Cancel" ,
style: "cancel" ,
},
{
text: "Logout" ,
style: "destructive" , // Red color on iOS
onPress : async () => { /* logout logic */ },
},
],
{ cancelable: true } // Allow tap outside to dismiss
);
Verification Badge
Verified users receive a green checkmark badge on their avatar.
{ user ?. isVerified && (
< View className = "absolute bottom-0 right-0 bg-white rounded-xl p-1 border-2 border-white" >
< IconSymbol
name = "checkmark.seal.fill"
size = { 16 }
color = "#10B981"
/>
</ View >
)}
The app version is displayed at the bottom of the profile screen.
< View className = "items-center mt-8 px-5" >
< Text className = "text-xs opacity-50 text-secondary" >
Version 1.0.0
</ Text >
</ View >
User Data Structure
The user object contains all relevant rider information.
address : Residential address
profilePicture : URL to avatar image (optional)
isVerified : Verification status flag
Security Considerations
Secure Storage User data is stored in encrypted MMKV storage on native platforms.
Token Cleanup All authentication tokens are properly removed on logout.
Confirmation Required Users must confirm before logging out to prevent accidental logouts.
Error Handling Logout errors are caught and reported to the user.
Authentication Learn about the login process and token management.
Dashboard Return to the main dashboard.
Transactions View transaction history and earnings.