feat: implement earnings overview and bank account management screens
This commit is contained in:
parent
525ed45b23
commit
2148f4e0c3
@ -36,23 +36,33 @@ import { useAppDispatch, useAppSelector } from '@store';
|
||||
// updatedAt: '2026-07-21T07:29:42.582Z',
|
||||
// },
|
||||
// ];
|
||||
export const BankDetailsScreen: React.FC = () => {
|
||||
export const BankDetailsScreen = () => {
|
||||
const { colors } = useAppTheme();
|
||||
const styles = getStyles(colors);
|
||||
const navigation =
|
||||
useNavigation<NativeStackNavigationProp<AppStackParamList>>();
|
||||
const dispatch = useAppDispatch();
|
||||
const { bankAccounts, isLoading, error } = useAppSelector(
|
||||
state => state.addBankDetails,
|
||||
);
|
||||
|
||||
|
||||
// Replace this state with Redux selector when wiring real API
|
||||
// const [accounts] = useState<BankAccount[]>(bankAccounts);
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
// console.log('-------');
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(fetchBankAccounts());
|
||||
}, []);
|
||||
// console.log('object')
|
||||
}, [dispatch]);
|
||||
|
||||
const { bankAccounts, isLoading, error } = useAppSelector(
|
||||
state => state.addBankDetails,
|
||||
);
|
||||
|
||||
const accountsList = Array.isArray(bankAccounts)
|
||||
? bankAccounts
|
||||
: (bankAccounts as any)?.data || (bankAccounts as any)?.bankAccounts || [];
|
||||
|
||||
// console.log(accountsList);
|
||||
|
||||
const handleRefresh = () => {
|
||||
setRefreshing(true);
|
||||
@ -100,7 +110,7 @@ export const BankDetailsScreen: React.FC = () => {
|
||||
</View>
|
||||
|
||||
{/* Empty State */}
|
||||
{bankAccounts?.length === 0 ? (
|
||||
{!accountsList || accountsList.length === 0 ? (
|
||||
<View style={styles.emptyContainer}>
|
||||
<View style={styles.emptyIconCircle}>
|
||||
<WalletIcon size={36} color={colors.primary} />
|
||||
@ -118,22 +128,22 @@ export const BankDetailsScreen: React.FC = () => {
|
||||
<Text style={styles.sectionTitle}>Your Accounts</Text>
|
||||
<View style={styles.countBadge}>
|
||||
<Text style={styles.countBadgeText}>
|
||||
{bankAccounts?.length}
|
||||
{accountsList.length}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Account Cards */}
|
||||
{bankAccounts?.map(account => (
|
||||
{accountsList.map((account: any) => (
|
||||
<View
|
||||
key={account.id}
|
||||
key={account?.id}
|
||||
style={[
|
||||
styles.accountCard,
|
||||
account.isDefault ? styles.defaultCard : null,
|
||||
account?.isDefault ? styles.defaultCard : null,
|
||||
]}
|
||||
>
|
||||
{/* Top color strip for default account */}
|
||||
{account.isDefault && <View style={styles.cardTopStrip} />}
|
||||
{account?.isDefault && <View style={styles.cardTopStrip} />}
|
||||
|
||||
<View style={styles.cardBody}>
|
||||
{/* Card Header Row */}
|
||||
@ -144,36 +154,36 @@ export const BankDetailsScreen: React.FC = () => {
|
||||
</View>
|
||||
<View style={styles.cardTitleGroup}>
|
||||
<Text style={styles.bankName} numberOfLines={1}>
|
||||
{account.bankName}
|
||||
{account?.bankName}
|
||||
</Text>
|
||||
<Text style={styles.holderName} numberOfLines={1}>
|
||||
{account.accountHolderName}
|
||||
{account?.accountHolderName}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Status Badges */}
|
||||
<View style={styles.badgeRow}>
|
||||
{account.isDefault && (
|
||||
{account?.isDefault && (
|
||||
<View style={styles.defaultBadge}>
|
||||
<Text style={styles.defaultBadgeText}>DEFAULT</Text>
|
||||
</View>
|
||||
)}
|
||||
<View
|
||||
style={
|
||||
account.isVerified
|
||||
account?.isVerified
|
||||
? styles.verifiedBadge
|
||||
: styles.unverifiedBadge
|
||||
}
|
||||
>
|
||||
<Text
|
||||
style={
|
||||
account.isVerified
|
||||
account?.isVerified
|
||||
? styles.verifiedBadgeText
|
||||
: styles.unverifiedBadgeText
|
||||
}
|
||||
>
|
||||
{account.isVerified ? 'VERIFIED' : 'PENDING'}
|
||||
{account?.isVerified ? 'VERIFIED' : 'PENDING'}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
@ -186,22 +196,22 @@ export const BankDetailsScreen: React.FC = () => {
|
||||
<View style={styles.fieldItem}>
|
||||
<Text style={styles.fieldLabel}>Account Number</Text>
|
||||
<Text style={styles.fieldValueMasked}>
|
||||
{maskAccountNumber(account.accountNumber)}
|
||||
{maskAccountNumber(account?.accountNumber)}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.fieldItem}>
|
||||
<Text style={styles.fieldLabel}>IFSC Code</Text>
|
||||
<Text style={styles.fieldValue}>
|
||||
{account.ifscCode || '—'}
|
||||
{account?.ifscCode || '—'}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{account.branchName ? (
|
||||
{account?.branchName ? (
|
||||
<View style={styles.fieldItem}>
|
||||
<Text style={styles.fieldLabel}>Branch</Text>
|
||||
<Text style={styles.fieldValue} numberOfLines={1}>
|
||||
{account.branchName}
|
||||
{account?.branchName}
|
||||
</Text>
|
||||
</View>
|
||||
) : null}
|
||||
@ -209,7 +219,7 @@ export const BankDetailsScreen: React.FC = () => {
|
||||
<View style={styles.fieldItem}>
|
||||
<Text style={styles.fieldLabel}>Owner Type</Text>
|
||||
<Text style={styles.fieldValue}>
|
||||
{account.ownerType || '—'}
|
||||
{account?.ownerType || '—'}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
@ -219,9 +229,9 @@ export const BankDetailsScreen: React.FC = () => {
|
||||
{/* Card Footer */}
|
||||
<View style={styles.cardFooter}>
|
||||
<Text style={styles.addedAtText}>
|
||||
Added {formatDate(account.createdAt)}
|
||||
Added {formatDate(account?.createdAt)}
|
||||
</Text>
|
||||
{account.isVerified && (
|
||||
{account?.isVerified && (
|
||||
<CheckCircleIcon size={16} color={colors.success} />
|
||||
)}
|
||||
</View>
|
||||
|
||||
@ -1,77 +1,95 @@
|
||||
import React from 'react';
|
||||
import React, { useCallback } from 'react';
|
||||
import { View, Text, ScrollView } from 'react-native';
|
||||
import { useAppTheme } from '@theme';
|
||||
import { WalletIcon } from '@icons';
|
||||
import { useAppSelector } from '@store';
|
||||
import { formatCurrency } from '@utils/formatters';
|
||||
import { useAppDispatch, useAppSelector } from '@store';
|
||||
import { formatCurrency, formatDate } from '@utils';
|
||||
import { getStyles } from './earningsScreen.styles';
|
||||
import { getCompletedDeliveries } from '../jobsScreen';
|
||||
import { useFocusEffect } from '@react-navigation/native';
|
||||
|
||||
export const EarningsScreen: React.FC = () => {
|
||||
const { colors } = useAppTheme();
|
||||
const styles = getStyles(colors);
|
||||
|
||||
const { todayEarnings, completedCount, onlineMinutes } = useAppSelector(
|
||||
state => state.earnings,
|
||||
);
|
||||
const { jobHistory } = useAppSelector(state => state.job);
|
||||
// const { todayEarnings, completedCount, onlineMinutes } = useAppSelector(
|
||||
// state => state.earnings,
|
||||
// );
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
// const { jobHistory } = useAppSelector(state => state.job);
|
||||
const { completedDeliveries } = useAppSelector(state => state.deliveries)
|
||||
// console.log('completedDeliveries', completedDeliveries)
|
||||
|
||||
// Default mock jobs history if none completed yet
|
||||
const defaultHistory: {
|
||||
orderId: string;
|
||||
time: string;
|
||||
amount: string;
|
||||
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 defaultHistory: {
|
||||
// orderId: string;
|
||||
// time: string;
|
||||
// amount: string;
|
||||
// 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
|
||||
? jobHistory
|
||||
.map(job => ({
|
||||
orderId: job.orderId,
|
||||
time: job.deliveredAt
|
||||
? new Date(job.deliveredAt).toLocaleTimeString([], {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
})
|
||||
: 'Delivered',
|
||||
amount: job.amount,
|
||||
paymentType: job.paymentType,
|
||||
}))
|
||||
.concat(defaultHistory)
|
||||
: defaultHistory;
|
||||
const totalAmount = completedDeliveries?.reduce((acc, item) => {
|
||||
return acc + Number(item?.order?.deliveryFee);
|
||||
}, 0);
|
||||
|
||||
const formatOnlineTime = (mins: number) => {
|
||||
const hours = Math.floor(mins / 60);
|
||||
const remainingMins = mins % 60;
|
||||
return `${hours}h ${
|
||||
remainingMins < 10 ? `0${remainingMins}` : remainingMins
|
||||
}m`;
|
||||
};
|
||||
// console.log('totalAmount', totalAmount)
|
||||
|
||||
useFocusEffect(useCallback(() => {
|
||||
dispatch(getCompletedDeliveries());
|
||||
}, [dispatch]))
|
||||
// const deliveryList = Array.isArray(completedDeliveries)
|
||||
// ? completedDeliveries
|
||||
// : (completedDeliveries as any)?.data || (completedDeliveries as any)?.bankAccounts || [];
|
||||
|
||||
// const displayHistory =
|
||||
// deliveryList?.length > 0
|
||||
// ? deliveryList
|
||||
// .map((delivery: any) => ({
|
||||
// orderId: delivery.orderId,
|
||||
// time: delivery.deliveredAt
|
||||
// ? new Date(delivery.deliveredAt).toLocaleTimeString([], {
|
||||
// hour: '2-digit',
|
||||
// minute: '2-digit',
|
||||
// })
|
||||
// : 'Delivered',
|
||||
// amount: delivery?.totalAmount,
|
||||
// paymentType: delivery?.paymentMethod,
|
||||
// }))
|
||||
// .concat(defaultHistory)
|
||||
// : defaultHistory;
|
||||
|
||||
// const formatOnlineTime = (mins: number) => {
|
||||
// const hours = Math.floor(mins / 60);
|
||||
// const remainingMins = mins % 60;
|
||||
// return `${hours}h ${remainingMins < 10 ? `0${remainingMins}` : remainingMins
|
||||
// }m`;
|
||||
// };
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
@ -85,18 +103,18 @@ export const EarningsScreen: React.FC = () => {
|
||||
|
||||
{/* Total Earnings Card */}
|
||||
<View style={styles.summaryCard}>
|
||||
<Text style={styles.summaryTitle}>Today's Earnings</Text>
|
||||
<Text style={styles.summaryTitle}>Total Earnings</Text>
|
||||
<Text style={styles.totalAmount}>
|
||||
{formatCurrency(todayEarnings)}
|
||||
{formatCurrency(totalAmount || 0)}
|
||||
</Text>
|
||||
|
||||
<View style={styles.statsRow}>
|
||||
{/* <View style={styles.statsRow}>
|
||||
<View style={styles.statBox}>
|
||||
<Text style={styles.statVal}>{completedCount}</Text>
|
||||
<Text style={styles.statVal}>{completedDeliveries?.length}</Text>
|
||||
<Text style={styles.statLabel}>Deliveries</Text>
|
||||
</View>
|
||||
</View> */}
|
||||
|
||||
<View style={styles.statDivider} />
|
||||
{/* <View style={styles.statDivider} />
|
||||
|
||||
<View style={styles.statBox}>
|
||||
<Text style={styles.statVal}>
|
||||
@ -110,15 +128,15 @@ export const EarningsScreen: React.FC = () => {
|
||||
<View style={styles.statBox}>
|
||||
<Text style={styles.statVal}>₹78.50</Text>
|
||||
<Text style={styles.statLabel}>Avg / Order</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>*/}
|
||||
{/* </View> */}
|
||||
</View>
|
||||
|
||||
{/* Recent Deliveries List */}
|
||||
<View style={styles.listSection}>
|
||||
<Text style={styles.sectionTitle}>Recent Deliveries</Text>
|
||||
|
||||
{displayHistory.map((item, index) => (
|
||||
{completedDeliveries?.map((item, index) => (
|
||||
<View key={index} style={styles.earningItem}>
|
||||
<View style={styles.itemLeft}>
|
||||
<View style={styles.iconContainer}>
|
||||
@ -126,17 +144,17 @@ export const EarningsScreen: React.FC = () => {
|
||||
</View>
|
||||
<View>
|
||||
<Text style={styles.orderIdText}>{item.orderId}</Text>
|
||||
<Text style={styles.timeText}>{item.time}</Text>
|
||||
<Text style={styles.timeText}>{formatDate(item?.deliveredAt || '')}</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.itemRight}>
|
||||
<Text style={styles.itemAmount}>
|
||||
+{formatCurrency(Number(item.amount))}
|
||||
+{formatCurrency(Number(item?.order?.deliveryFee))}
|
||||
</Text>
|
||||
<View style={styles.paymentBadge}>
|
||||
<Text style={styles.paymentText}>
|
||||
{item.paymentType.toUpperCase()}
|
||||
{/* {item?.order?.pa.toUpperCase()} */}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user