231 lines
5.9 KiB
TypeScript
231 lines
5.9 KiB
TypeScript
import React, { memo } from 'react';
|
|
import { Pressable, StyleSheet, Text, View } from 'react-native';
|
|
import Ionicons from '@react-native-vector-icons/ionicons';
|
|
|
|
import { Button, Card } from '../../../components';
|
|
import { useTheme, fontFamily } from '../../../theme';
|
|
import type { InsurancePlan } from '../types';
|
|
import { formatCompactCurrency, formatCurrency } from '../../../utils/formatters';
|
|
|
|
interface InsurancePlanCardProps {
|
|
plan: InsurancePlan;
|
|
selected?: boolean;
|
|
compared?: boolean;
|
|
onSelect?: () => void;
|
|
onCompare?: () => void;
|
|
}
|
|
|
|
const InsurancePlanCardComponent = ({
|
|
plan,
|
|
selected = false,
|
|
compared = false,
|
|
onSelect,
|
|
onCompare,
|
|
}: InsurancePlanCardProps) => {
|
|
const theme = useTheme();
|
|
|
|
return (
|
|
<Card
|
|
style={[
|
|
styles.card,
|
|
{
|
|
borderColor: selected ? theme.colors.primary : theme.colors.cardBorder,
|
|
borderWidth: selected ? 2 : 1,
|
|
},
|
|
]}
|
|
>
|
|
<View style={styles.header}>
|
|
<View style={styles.copy}>
|
|
<Text style={[styles.title, { color: theme.colors.textPrimary }]}>{plan.name}</Text>
|
|
<Text style={[styles.subtitle, { color: theme.colors.textSecondary }]}>
|
|
{plan.insurerName}
|
|
</Text>
|
|
</View>
|
|
<View
|
|
style={[styles.ratioBadge, { backgroundColor: `${theme.colors.accent}14` }]}
|
|
>
|
|
<Text style={[styles.ratioValue, { color: theme.colors.accent }]}>
|
|
{plan.claimSettlementRatio}%
|
|
</Text>
|
|
<Text style={[styles.ratioLabel, { color: theme.colors.textSecondary }]}>
|
|
CSR
|
|
</Text>
|
|
</View>
|
|
</View>
|
|
|
|
<Text style={[styles.summary, { color: theme.colors.textMuted }]}>{plan.summary}</Text>
|
|
|
|
<View style={styles.metrics}>
|
|
<View style={[styles.metricCard, { backgroundColor: theme.colors.surfaceMuted }]}>
|
|
<Text style={[styles.metricLabel, { color: theme.colors.textSecondary }]}>
|
|
Premium
|
|
</Text>
|
|
<Text style={[styles.metricValue, { color: theme.colors.textPrimary }]}>
|
|
{formatCurrency(plan.premium)}
|
|
</Text>
|
|
<Text style={[styles.metricCaption, { color: theme.colors.textMuted }]}>
|
|
{plan.premiumFrequency}
|
|
</Text>
|
|
</View>
|
|
<View style={[styles.metricCard, { backgroundColor: theme.colors.surfaceMuted }]}>
|
|
<Text style={[styles.metricLabel, { color: theme.colors.textSecondary }]}>
|
|
Coverage
|
|
</Text>
|
|
<Text style={[styles.metricValue, { color: theme.colors.textPrimary }]}>
|
|
{formatCompactCurrency(plan.coverAmount)}
|
|
</Text>
|
|
<Text style={[styles.metricCaption, { color: theme.colors.textMuted }]}>
|
|
{plan.tenureYears} year tenure
|
|
</Text>
|
|
</View>
|
|
</View>
|
|
|
|
<View style={styles.listWrap}>
|
|
{plan.benefits.slice(0, 3).map((benefit) => (
|
|
<View key={benefit} style={styles.listRow}>
|
|
<Ionicons name="checkmark-circle" size={16} color={theme.colors.accent} />
|
|
<Text style={[styles.listText, { color: theme.colors.textPrimary }]}>{benefit}</Text>
|
|
</View>
|
|
))}
|
|
</View>
|
|
|
|
<View style={styles.actionRow}>
|
|
<Pressable
|
|
onPress={onCompare}
|
|
style={({ pressed }) => [
|
|
styles.compareButton,
|
|
{
|
|
backgroundColor: compared ? `${theme.colors.info}12` : theme.colors.surfaceMuted,
|
|
opacity: pressed ? 0.9 : 1,
|
|
},
|
|
]}
|
|
>
|
|
<Ionicons
|
|
name={compared ? 'checkbox' : 'square-outline'}
|
|
size={18}
|
|
color={compared ? theme.colors.info : theme.colors.textMuted}
|
|
/>
|
|
<Text
|
|
style={[
|
|
styles.compareLabel,
|
|
{ color: compared ? theme.colors.info : theme.colors.textSecondary },
|
|
]}
|
|
>
|
|
Compare
|
|
</Text>
|
|
</Pressable>
|
|
<Button
|
|
title={selected ? 'Selected' : 'Select Plan'}
|
|
onPress={onSelect}
|
|
variant={selected ? 'secondary' : 'primary'}
|
|
fullWidth={false}
|
|
style={styles.selectButton}
|
|
/>
|
|
</View>
|
|
</Card>
|
|
);
|
|
};
|
|
|
|
const styles = StyleSheet.create({
|
|
card: {
|
|
gap: 14,
|
|
},
|
|
header: {
|
|
flexDirection: 'row',
|
|
gap: 12,
|
|
},
|
|
copy: {
|
|
flex: 1,
|
|
gap: 2,
|
|
},
|
|
title: {
|
|
fontSize: 16,
|
|
fontFamily: fontFamily.bold,
|
|
},
|
|
subtitle: {
|
|
fontSize: 12,
|
|
fontFamily: fontFamily.semibold,
|
|
},
|
|
ratioBadge: {
|
|
minWidth: 68,
|
|
borderRadius: 14,
|
|
paddingHorizontal: 10,
|
|
paddingVertical: 8,
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
},
|
|
ratioValue: {
|
|
fontSize: 16,
|
|
fontFamily: fontFamily.bold,
|
|
},
|
|
ratioLabel: {
|
|
fontSize: 10,
|
|
fontFamily: fontFamily.bold,
|
|
letterSpacing: 0.5,
|
|
},
|
|
summary: {
|
|
fontSize: 13,
|
|
lineHeight: 18,
|
|
},
|
|
metrics: {
|
|
flexDirection: 'row',
|
|
gap: 10,
|
|
},
|
|
metricCard: {
|
|
flex: 1,
|
|
borderRadius: 14,
|
|
padding: 12,
|
|
gap: 4,
|
|
},
|
|
metricLabel: {
|
|
fontSize: 11,
|
|
fontFamily: fontFamily.bold,
|
|
textTransform: 'uppercase',
|
|
letterSpacing: 0.5,
|
|
},
|
|
metricValue: {
|
|
fontSize: 18,
|
|
fontFamily: fontFamily.bold,
|
|
},
|
|
metricCaption: {
|
|
fontSize: 11,
|
|
fontFamily: fontFamily.semibold,
|
|
},
|
|
listWrap: {
|
|
gap: 8,
|
|
},
|
|
listRow: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
gap: 8,
|
|
},
|
|
listText: {
|
|
flex: 1,
|
|
fontSize: 12,
|
|
fontFamily: fontFamily.semibold,
|
|
lineHeight: 17,
|
|
},
|
|
actionRow: {
|
|
flexDirection: 'row',
|
|
gap: 10,
|
|
alignItems: 'center',
|
|
},
|
|
compareButton: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
gap: 8,
|
|
borderRadius: 12,
|
|
paddingHorizontal: 12,
|
|
paddingVertical: 12,
|
|
},
|
|
compareLabel: {
|
|
fontSize: 12,
|
|
fontFamily: fontFamily.bold,
|
|
},
|
|
selectButton: {
|
|
flex: 1,
|
|
},
|
|
});
|
|
|
|
export const InsurancePlanCard = memo(InsurancePlanCardComponent);
|