Fix form keyboard issues and sticky footers in agent screens
This commit is contained in:
@@ -0,0 +1,154 @@
|
||||
import React from 'react';
|
||||
import { View, Text, StyleSheet, FlatList } from 'react-native';
|
||||
import { NativeStackScreenProps } from '@react-navigation/native-stack';
|
||||
import Ionicons from '@react-native-vector-icons/ionicons';
|
||||
import Animated, { FadeInUp } from 'react-native-reanimated';
|
||||
|
||||
import { ScreenShell } from '../../../components';
|
||||
import { useTheme } from '../../../theme';
|
||||
import { useAppSelector } from '../../../app/hooks';
|
||||
import { selectCustomerById } from '../store/agentSelectors';
|
||||
import type { AgentCustomersStackParamList } from '../navigation/agentNavigationTypes';
|
||||
import { formatAgentCurrency, formatDateTime } from '../utils/agentFormatters';
|
||||
|
||||
import { AgentEmptyState } from '../components/AgentEmptyState';
|
||||
|
||||
type Props = NativeStackScreenProps<AgentCustomersStackParamList, 'CustomerInstallmentHistory'>;
|
||||
|
||||
export default function CustomerInstallmentHistoryScreen({ route, navigation }: Props) {
|
||||
const { customerId } = route.params;
|
||||
const theme = useTheme();
|
||||
|
||||
const customer = useAppSelector(selectCustomerById(customerId));
|
||||
|
||||
if (!customer) {
|
||||
return (
|
||||
<ScreenShell title="Installment History">
|
||||
<AgentEmptyState title="Error" description="Customer not found" />
|
||||
</ScreenShell>
|
||||
);
|
||||
}
|
||||
|
||||
// Generate mock history based on totalCollected for demo purposes
|
||||
const history = Array.from({ length: 10 }).map((_, i) => {
|
||||
const isPaid = i < (customer.totalCollected / 500);
|
||||
const date = new Date();
|
||||
date.setDate(date.getDate() - (i * 30));
|
||||
return {
|
||||
id: `hist-${i}`,
|
||||
amount: 500,
|
||||
date: date.toISOString(),
|
||||
status: isPaid ? 'paid' : 'pending',
|
||||
receiptNo: isPaid ? `RCP-${date.getFullYear()}${String(date.getMonth()+1).padStart(2,'0')}${String(date.getDate()).padStart(2,'0')}-${1000+i}` : null,
|
||||
};
|
||||
});
|
||||
|
||||
const renderItem = ({ item, index }: { item: any, index: number }) => (
|
||||
<Animated.View entering={FadeInUp.delay(index * 50)} style={[styles.card, { backgroundColor: theme.colors.surface, borderColor: theme.colors.cardBorder }]}>
|
||||
<View style={styles.leftSide}>
|
||||
<View style={[styles.iconFrame, { backgroundColor: item.status === 'paid' ? `${theme.colors.success}15` : `${theme.colors.warning}15` }]}>
|
||||
<Ionicons
|
||||
name={item.status === 'paid' ? 'checkmark-circle' : 'time'}
|
||||
size={20}
|
||||
color={item.status === 'paid' ? theme.colors.success : theme.colors.warning}
|
||||
/>
|
||||
</View>
|
||||
<View>
|
||||
<Text style={[styles.date, { color: theme.colors.textPrimary }]}>{formatDateTime(item.date)}</Text>
|
||||
{item.receiptNo ? (
|
||||
<Text style={[styles.receipt, { color: theme.colors.textMuted }]}>{item.receiptNo}</Text>
|
||||
) : (
|
||||
<Text style={[styles.receipt, { color: theme.colors.textMuted }]}>Pending Installment</Text>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.rightSide}>
|
||||
<Text style={[styles.amount, { color: theme.colors.textPrimary }]}>{formatAgentCurrency(item.amount)}</Text>
|
||||
<Text style={[styles.status, { color: item.status === 'paid' ? theme.colors.success : theme.colors.warning }]}>
|
||||
{item.status.toUpperCase()}
|
||||
</Text>
|
||||
</View>
|
||||
</Animated.View>
|
||||
);
|
||||
|
||||
return (
|
||||
<ScreenShell title="Installment History" scrollable={false}>
|
||||
<View style={styles.header}>
|
||||
<Text style={[styles.customerName, { color: theme.colors.textPrimary }]}>{customer.name}</Text>
|
||||
<Text style={[styles.accNumber, { color: theme.colors.textMuted }]}>
|
||||
{customer.accounts[0]?.type} A/C: {customer.accounts[0]?.accountNumber}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<FlatList
|
||||
data={history}
|
||||
keyExtractor={item => item.id}
|
||||
renderItem={renderItem}
|
||||
contentContainerStyle={styles.listContent}
|
||||
showsVerticalScrollIndicator={false}
|
||||
/>
|
||||
</ScreenShell>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
header: {
|
||||
padding: 16,
|
||||
paddingTop: 8,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: 'rgba(0,0,0,0.05)',
|
||||
},
|
||||
customerName: {
|
||||
fontSize: 18,
|
||||
fontWeight: '700',
|
||||
marginBottom: 4,
|
||||
},
|
||||
accNumber: {
|
||||
fontSize: 14,
|
||||
fontFamily: 'monospace',
|
||||
},
|
||||
listContent: {
|
||||
padding: 16,
|
||||
},
|
||||
card: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
padding: 16,
|
||||
borderRadius: 16,
|
||||
borderWidth: 1,
|
||||
marginBottom: 12,
|
||||
},
|
||||
leftSide: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 12,
|
||||
},
|
||||
iconFrame: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: 20,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
date: {
|
||||
fontSize: 14,
|
||||
fontWeight: '600',
|
||||
marginBottom: 2,
|
||||
},
|
||||
receipt: {
|
||||
fontSize: 11,
|
||||
},
|
||||
rightSide: {
|
||||
alignItems: 'flex-end',
|
||||
},
|
||||
amount: {
|
||||
fontSize: 15,
|
||||
fontWeight: '700',
|
||||
marginBottom: 2,
|
||||
},
|
||||
status: {
|
||||
fontSize: 10,
|
||||
fontWeight: '700',
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user