feat: implement onboarding stack and various feature screens for OTP, bank details, and profile management.
This commit is contained in:
parent
65f685d5cf
commit
525ed45b23
@ -56,7 +56,9 @@ export const OtpScreen: React.FC<{ route: any }> = ({ route }) => {
|
|||||||
await dispatch(
|
await dispatch(
|
||||||
verifyOtp({ phone, code: otp, role: 'DELIVERY' }),
|
verifyOtp({ phone, code: otp, role: 'DELIVERY' }),
|
||||||
).unwrap();
|
).unwrap();
|
||||||
navigation.navigate('OnBoarding', { screen: RouteNames.CompleteProfile });
|
// Navigation is handled automatically by rootNavigator's conditional
|
||||||
|
// rendering: once accessToken is set, the Auth stack unmounts and
|
||||||
|
// OnBoarding or App stack mounts based on user.status.
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Alert.alert('Error', error as string);
|
Alert.alert('Error', error as string);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,10 +12,8 @@ import { WalletIcon, CheckCircleIcon, ClipboardIcon } from '@icons';
|
|||||||
import { useNavigation } from '@react-navigation/native';
|
import { useNavigation } from '@react-navigation/native';
|
||||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
||||||
import { AppStackParamList } from '@navigation/navigationTypes';
|
import { AppStackParamList } from '@navigation/navigationTypes';
|
||||||
import { RouteNames } from '@utils/constants';
|
|
||||||
import { BankAccount } from '@interfaces';
|
|
||||||
import { getStyles } from './bankDetailsScreen.styles';
|
import { getStyles } from './bankDetailsScreen.styles';
|
||||||
import { formatDate, maskAccountNumber } from '@utils';
|
import { formatDate, maskAccountNumber, RouteNames } from '@utils';
|
||||||
import { fetchBankAccounts } from '../addBankDetailsScreen';
|
import { fetchBankAccounts } from '../addBankDetailsScreen';
|
||||||
import { useAppDispatch, useAppSelector } from '@store';
|
import { useAppDispatch, useAppSelector } from '@store';
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@ export interface completeProfileState {
|
|||||||
error: string | null;
|
error: string | null;
|
||||||
submitError: string | null;
|
submitError: string | null;
|
||||||
userProfile: UserProfile | null;
|
userProfile: UserProfile | null;
|
||||||
|
alreadyNavigate: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialState: completeProfileState = {
|
const initialState: completeProfileState = {
|
||||||
@ -15,6 +16,7 @@ const initialState: completeProfileState = {
|
|||||||
error: null,
|
error: null,
|
||||||
submitError: null,
|
submitError: null,
|
||||||
userProfile: null,
|
userProfile: null,
|
||||||
|
alreadyNavigate: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const completeProfileReducer = createReducer(initialState, builder => {
|
export const completeProfileReducer = createReducer(initialState, builder => {
|
||||||
@ -26,6 +28,7 @@ export const completeProfileReducer = createReducer(initialState, builder => {
|
|||||||
.addCase(completeOnboard.fulfilled, (state, action) => {
|
.addCase(completeOnboard.fulfilled, (state, action) => {
|
||||||
state.isLoading = false;
|
state.isLoading = false;
|
||||||
state.userProfile = action.payload;
|
state.userProfile = action.payload;
|
||||||
|
state.alreadyNavigate = true;
|
||||||
})
|
})
|
||||||
.addCase(completeOnboard.rejected, (state, action) => {
|
.addCase(completeOnboard.rejected, (state, action) => {
|
||||||
state.isLoading = false;
|
state.isLoading = false;
|
||||||
|
|||||||
@ -198,7 +198,7 @@ export const DocumentsScreen: React.FC = () => {
|
|||||||
statusBarTranslucent
|
statusBarTranslucent
|
||||||
onRequestClose={() => setSelectedDoc(null)}
|
onRequestClose={() => setSelectedDoc(null)}
|
||||||
>
|
>
|
||||||
<SafeAreaView style={styles.modalContainer}>
|
<View style={styles.modalContainer}>
|
||||||
{/* Modal Header */}
|
{/* Modal Header */}
|
||||||
<View style={styles.modalHeader}>
|
<View style={styles.modalHeader}>
|
||||||
<View style={styles.modalHeaderInfo}>
|
<View style={styles.modalHeaderInfo}>
|
||||||
@ -259,7 +259,7 @@ export const DocumentsScreen: React.FC = () => {
|
|||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
</SafeAreaView>
|
</View>
|
||||||
</Modal>
|
</Modal>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -10,35 +10,75 @@ export const EarningsScreen: React.FC = () => {
|
|||||||
const { colors } = useAppTheme();
|
const { colors } = useAppTheme();
|
||||||
const styles = getStyles(colors);
|
const styles = getStyles(colors);
|
||||||
|
|
||||||
const { todayEarnings, completedCount, onlineMinutes } = useAppSelector((state) => state.earnings);
|
const { todayEarnings, completedCount, onlineMinutes } = useAppSelector(
|
||||||
const { jobHistory } = useAppSelector((state) => state.job);
|
state => state.earnings,
|
||||||
|
);
|
||||||
|
const { jobHistory } = useAppSelector(state => state.job);
|
||||||
|
|
||||||
// Default mock jobs history if none completed yet
|
// Default mock jobs history if none completed yet
|
||||||
const defaultHistory: { orderId: string; time: string; amount: number; paymentType: 'online' | 'cod'; }[] = [
|
const defaultHistory: {
|
||||||
{ orderId: '#ORD125487', time: '12:35 PM', amount: 78.0, paymentType: 'online' },
|
orderId: string;
|
||||||
{ orderId: '#ORD125422', time: '11:15 AM', amount: 65.0, paymentType: 'cod' },
|
time: string;
|
||||||
{ orderId: '#ORD125389', time: '09:40 AM', amount: 120.0, paymentType: 'online' },
|
amount: string;
|
||||||
{ orderId: '#ORD125310', time: 'Yesterday', amount: 85.0, paymentType: 'online' },
|
paymentType: 'online' | 'cod';
|
||||||
|
}[] = [
|
||||||
|
{
|
||||||
|
orderId: '#ORD125487',
|
||||||
|
time: '12:35 PM',
|
||||||
|
amount: '78.0',
|
||||||
|
paymentType: 'online',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
orderId: '#ORD125422',
|
||||||
|
time: '11:15 AM',
|
||||||
|
amount: '65.0',
|
||||||
|
paymentType: 'cod',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
orderId: '#ORD125389',
|
||||||
|
time: '09:40 AM',
|
||||||
|
amount: '120.0',
|
||||||
|
paymentType: 'online',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
orderId: '#ORD125310',
|
||||||
|
time: 'Yesterday',
|
||||||
|
amount: '85.0',
|
||||||
|
paymentType: 'online',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const displayHistory = jobHistory.length > 0
|
const displayHistory =
|
||||||
? jobHistory.map(job => ({
|
jobHistory.length > 0
|
||||||
orderId: job.orderId,
|
? jobHistory
|
||||||
time: job.deliveredAt ? new Date(job.deliveredAt).toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'}) : 'Delivered',
|
.map(job => ({
|
||||||
amount: job.amount,
|
orderId: job.orderId,
|
||||||
paymentType: job.paymentType,
|
time: job.deliveredAt
|
||||||
})).concat(defaultHistory)
|
? new Date(job.deliveredAt).toLocaleTimeString([], {
|
||||||
: defaultHistory;
|
hour: '2-digit',
|
||||||
|
minute: '2-digit',
|
||||||
|
})
|
||||||
|
: 'Delivered',
|
||||||
|
amount: job.amount,
|
||||||
|
paymentType: job.paymentType,
|
||||||
|
}))
|
||||||
|
.concat(defaultHistory)
|
||||||
|
: defaultHistory;
|
||||||
|
|
||||||
const formatOnlineTime = (mins: number) => {
|
const formatOnlineTime = (mins: number) => {
|
||||||
const hours = Math.floor(mins / 60);
|
const hours = Math.floor(mins / 60);
|
||||||
const remainingMins = mins % 60;
|
const remainingMins = mins % 60;
|
||||||
return `${hours}h ${remainingMins < 10 ? `0${remainingMins}` : remainingMins}m`;
|
return `${hours}h ${
|
||||||
|
remainingMins < 10 ? `0${remainingMins}` : remainingMins
|
||||||
|
}m`;
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<ScrollView contentContainerStyle={styles.scrollContainer} showsVerticalScrollIndicator={false}>
|
<ScrollView
|
||||||
|
contentContainerStyle={styles.scrollContainer}
|
||||||
|
showsVerticalScrollIndicator={false}
|
||||||
|
>
|
||||||
<View style={styles.headerContainer}>
|
<View style={styles.headerContainer}>
|
||||||
<Text style={styles.title}>Earnings</Text>
|
<Text style={styles.title}>Earnings</Text>
|
||||||
</View>
|
</View>
|
||||||
@ -46,7 +86,9 @@ export const EarningsScreen: React.FC = () => {
|
|||||||
{/* Total Earnings Card */}
|
{/* Total Earnings Card */}
|
||||||
<View style={styles.summaryCard}>
|
<View style={styles.summaryCard}>
|
||||||
<Text style={styles.summaryTitle}>Today's Earnings</Text>
|
<Text style={styles.summaryTitle}>Today's Earnings</Text>
|
||||||
<Text style={styles.totalAmount}>{formatCurrency(todayEarnings)}</Text>
|
<Text style={styles.totalAmount}>
|
||||||
|
{formatCurrency(todayEarnings)}
|
||||||
|
</Text>
|
||||||
|
|
||||||
<View style={styles.statsRow}>
|
<View style={styles.statsRow}>
|
||||||
<View style={styles.statBox}>
|
<View style={styles.statBox}>
|
||||||
@ -57,7 +99,9 @@ export const EarningsScreen: React.FC = () => {
|
|||||||
<View style={styles.statDivider} />
|
<View style={styles.statDivider} />
|
||||||
|
|
||||||
<View style={styles.statBox}>
|
<View style={styles.statBox}>
|
||||||
<Text style={styles.statVal}>{formatOnlineTime(onlineMinutes)}</Text>
|
<Text style={styles.statVal}>
|
||||||
|
{formatOnlineTime(onlineMinutes)}
|
||||||
|
</Text>
|
||||||
<Text style={styles.statLabel}>Online Time</Text>
|
<Text style={styles.statLabel}>Online Time</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
@ -87,9 +131,13 @@ export const EarningsScreen: React.FC = () => {
|
|||||||
</View>
|
</View>
|
||||||
|
|
||||||
<View style={styles.itemRight}>
|
<View style={styles.itemRight}>
|
||||||
<Text style={styles.itemAmount}>+{formatCurrency(item.amount)}</Text>
|
<Text style={styles.itemAmount}>
|
||||||
|
+{formatCurrency(Number(item.amount))}
|
||||||
|
</Text>
|
||||||
<View style={styles.paymentBadge}>
|
<View style={styles.paymentBadge}>
|
||||||
<Text style={styles.paymentText}>{item.paymentType.toUpperCase()}</Text>
|
<Text style={styles.paymentText}>
|
||||||
|
{item.paymentType.toUpperCase()}
|
||||||
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@ -19,11 +19,6 @@ export const ProfileScreen: React.FC = () => {
|
|||||||
const { profile } = useAppSelector(state => state.accountInfo);
|
const { profile } = useAppSelector(state => state.accountInfo);
|
||||||
|
|
||||||
const menuItems = [
|
const menuItems = [
|
||||||
{
|
|
||||||
id: 'personal',
|
|
||||||
title: 'Personal Info',
|
|
||||||
icon: <PersonIcon size={20} color={colors.primary} />,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'vehicle',
|
id: 'vehicle',
|
||||||
title: 'Vehicle Info',
|
title: 'Vehicle Info',
|
||||||
|
|||||||
@ -8,20 +8,24 @@ import {
|
|||||||
KycScreen,
|
KycScreen,
|
||||||
} from '@features/screens';
|
} from '@features/screens';
|
||||||
import { RouteNames } from '@utils/constants';
|
import { RouteNames } from '@utils/constants';
|
||||||
|
import { useAppSelector } from '@store';
|
||||||
|
|
||||||
const Stack = createNativeStackNavigator<OnBoardingParamList>();
|
const Stack = createNativeStackNavigator<OnBoardingParamList>();
|
||||||
|
|
||||||
const onBoardingStack: React.FC = () => {
|
const onBoardingStack: React.FC = () => {
|
||||||
|
const { alreadyNavigate } = useAppSelector(state => state.onboard);
|
||||||
return (
|
return (
|
||||||
<Stack.Navigator screenOptions={{ headerShown: false }}>
|
<Stack.Navigator screenOptions={{ headerShown: false }}>
|
||||||
{/* <Stack.Screen
|
{/* <Stack.Screen
|
||||||
name={RouteNames.SetLocation}
|
name={RouteNames.SetLocation}
|
||||||
component={SetLocationScreen}
|
component={SetLocationScreen}
|
||||||
/> */}
|
/> */}
|
||||||
<Stack.Screen
|
{!alreadyNavigate && (
|
||||||
name={RouteNames.CompleteProfile}
|
<Stack.Screen
|
||||||
component={CompleteProfileScreen}
|
name={RouteNames.CompleteProfile}
|
||||||
/>
|
component={CompleteProfileScreen}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<Stack.Screen name={RouteNames.Kyc} component={KycScreen} />
|
<Stack.Screen name={RouteNames.Kyc} component={KycScreen} />
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name={RouteNames.OnboardingComplete}
|
name={RouteNames.OnboardingComplete}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user