Fix form keyboard issues and sticky footers in agent screens

This commit is contained in:
Abin Toppo
2026-05-26 16:34:05 +05:30
commit 9ac5e95d52
410 changed files with 86650 additions and 0 deletions
@@ -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',
},
});