Fix form keyboard issues and sticky footers in agent screens
This commit is contained in:
@@ -0,0 +1,170 @@
|
||||
import React, { memo, useMemo } from 'react';
|
||||
import {
|
||||
StyleSheet,
|
||||
Text,
|
||||
View,
|
||||
} from 'react-native';
|
||||
import Ionicons from '@react-native-vector-icons/ionicons';
|
||||
|
||||
import type { TransactionRecord } from '../../types/app';
|
||||
import { useTheme } from '../../theme';
|
||||
import { formatCurrency, formatDate } from '../../utils/formatters';
|
||||
|
||||
interface TransactionItemProps {
|
||||
item: TransactionRecord;
|
||||
}
|
||||
|
||||
type RiskLevel = 'safe' | 'medium' | 'high';
|
||||
|
||||
const TransactionItemComponent = ({ item }: TransactionItemProps) => {
|
||||
const theme = useTheme();
|
||||
const isCredit = item.direction === 'credit';
|
||||
|
||||
const riskLevel = useMemo<RiskLevel>(() => {
|
||||
const sum = item.id.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0);
|
||||
if (sum % 10 < 7) return 'safe';
|
||||
if (sum % 10 < 9) return 'medium';
|
||||
return 'high';
|
||||
}, [item.id]);
|
||||
|
||||
const riskConfig = {
|
||||
safe: { color: theme.colors.success, label: 'SECURE', icon: 'shield-checkmark' as const },
|
||||
medium: { color: theme.colors.warning, label: 'FLAGGED', icon: 'warning' as const },
|
||||
high: { color: theme.colors.danger, label: 'HIGH RISK', icon: 'alert-circle' as const },
|
||||
}[riskLevel];
|
||||
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
styles.wrapper,
|
||||
{
|
||||
borderBottomColor: 'rgba(255, 255, 255, 0.05)',
|
||||
},
|
||||
]}
|
||||
>
|
||||
<View style={styles.leading}>
|
||||
<View
|
||||
style={[
|
||||
styles.icon,
|
||||
{
|
||||
backgroundColor: isCredit
|
||||
? `${theme.colors.success}10`
|
||||
: 'rgba(255, 255, 255, 0.05)',
|
||||
borderColor: isCredit ? `${theme.colors.success}30` : 'rgba(255, 255, 255, 0.1)',
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Ionicons
|
||||
name={isCredit ? 'chevron-down' : 'chevron-up'}
|
||||
size={18}
|
||||
color={isCredit ? theme.colors.success : theme.colors.white}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.copy}>
|
||||
<View style={styles.titleRow}>
|
||||
<Text style={[styles.title, { color: theme.colors.white }]}>{item.title}</Text>
|
||||
</View>
|
||||
<View style={styles.subtitleRow}>
|
||||
<Text style={[styles.subtitle, { color: 'rgba(255, 255, 255, 0.5)' }]}>
|
||||
{item.counterparty}
|
||||
</Text>
|
||||
<View style={styles.dot} />
|
||||
<Text style={[styles.subtitle, { color: 'rgba(255, 255, 255, 0.5)' }]}>
|
||||
{formatDate(item.occurredAt)}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.trailing}>
|
||||
<Text
|
||||
style={[
|
||||
styles.amount,
|
||||
{ color: isCredit ? theme.colors.success : theme.colors.white },
|
||||
]}
|
||||
>
|
||||
{isCredit ? '+' : '-'}
|
||||
{formatCurrency(item.amount)}
|
||||
</Text>
|
||||
<View style={[styles.riskBadge, { backgroundColor: `${riskConfig.color}10`, borderColor: `${riskConfig.color}20` }]}>
|
||||
<Text style={[styles.riskText, { color: riskConfig.color }]}>{riskConfig.label}</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
wrapper: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
paddingVertical: 18,
|
||||
borderBottomWidth: 1,
|
||||
},
|
||||
leading: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 16,
|
||||
flex: 1,
|
||||
},
|
||||
icon: {
|
||||
width: 46,
|
||||
height: 46,
|
||||
borderRadius: 23,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderWidth: 1,
|
||||
},
|
||||
copy: {
|
||||
gap: 4,
|
||||
flex: 1,
|
||||
},
|
||||
titleRow: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
},
|
||||
title: {
|
||||
fontSize: 16,
|
||||
fontWeight: '800',
|
||||
letterSpacing: -0.3,
|
||||
},
|
||||
subtitleRow: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 6,
|
||||
},
|
||||
dot: {
|
||||
width: 3,
|
||||
height: 3,
|
||||
borderRadius: 1.5,
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.2)',
|
||||
},
|
||||
subtitle: {
|
||||
fontSize: 12,
|
||||
fontWeight: '500',
|
||||
},
|
||||
trailing: {
|
||||
alignItems: 'flex-end',
|
||||
gap: 4,
|
||||
},
|
||||
amount: {
|
||||
fontSize: 16,
|
||||
fontWeight: '800',
|
||||
letterSpacing: -0.2,
|
||||
},
|
||||
riskBadge: {
|
||||
paddingHorizontal: 6,
|
||||
paddingVertical: 2,
|
||||
borderRadius: 6,
|
||||
borderWidth: 1,
|
||||
},
|
||||
riskText: {
|
||||
fontSize: 8,
|
||||
fontWeight: '900',
|
||||
letterSpacing: 0.5,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
export const TransactionItem = memo(TransactionItemComponent);
|
||||
Reference in New Issue
Block a user