Files
CBS-Mobile-App/src/modules/insurance/screens/InsurancePolicyDetailsScreen.tsx
T

340 lines
11 KiB
TypeScript

import React from 'react';
import { Pressable, ScrollView, StyleSheet, Text, View } from 'react-native';
import type { NativeStackScreenProps } from '@react-navigation/native-stack';
import Ionicons from '@react-native-vector-icons/ionicons';
import { Button, Card, EmptyState, Loader, ScreenShell } from '../../../components';
import { useToast } from '../../../hooks/useToast';
import type { InsuranceStackParamList } from '../../../navigation/types';
import { useTheme } from '../../../theme';
import { formatCompactCurrency, formatCurrency, formatDate } from '../../../utils/formatters';
import { InsuranceStatusPill } from '../components/InsuranceStatusPill';
import { useGetInsurancePolicyDetailQuery } from '../services/insuranceApi';
type Props = NativeStackScreenProps<InsuranceStackParamList, 'InsurancePolicyDetails'>;
export default function InsurancePolicyDetailsScreen({ navigation, route }: Props) {
const theme = useTheme();
const toast = useToast();
const { data, isLoading, isError, refetch } = useGetInsurancePolicyDetailQuery(
route.params.policyId,
);
return (
<ScreenShell title="Policy Details" subtitle="Coverage, insurer, and servicing actions">
{isLoading ? (
<Card>
<Loader />
</Card>
) : null}
{isError || !data ? (
<EmptyState
title="Unable to load policy"
description="Please retry in a moment."
actionLabel="Retry"
onAction={refetch}
/>
) : (
<ScrollView contentContainerStyle={styles.scroll} showsVerticalScrollIndicator={false}>
<Card style={styles.heroCard}>
<View style={styles.heroHeader}>
<View style={styles.heroCopy}>
<Text style={[styles.heroTitle, { color: theme.colors.textPrimary }]}>
{data.planName}
</Text>
<Text style={[styles.heroMeta, { color: theme.colors.textSecondary }]}>
{data.policyNumber} · {data.insurer.name}
</Text>
</View>
<InsuranceStatusPill status={data.status} />
</View>
<View style={styles.metricGrid}>
<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(data.coverageAmount)}
</Text>
</View>
<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(data.premiumAmount)}
</Text>
<Text style={[styles.metricCaption, { color: theme.colors.textMuted }]}>
{data.premiumFrequency}
</Text>
</View>
</View>
<View style={styles.infoList}>
<Text style={[styles.infoRow, { color: theme.colors.textSecondary }]}>
Start date:{' '}
<Text style={[styles.infoStrong, { color: theme.colors.textPrimary }]}>
{formatDate(data.startDate)}
</Text>
</Text>
<Text style={[styles.infoRow, { color: theme.colors.textSecondary }]}>
Expiry date:{' '}
<Text style={[styles.infoStrong, { color: theme.colors.textPrimary }]}>
{formatDate(data.expiryDate)}
</Text>
</Text>
<Text style={[styles.infoRow, { color: theme.colors.textSecondary }]}>
Next premium due:{' '}
<Text style={[styles.infoStrong, { color: theme.colors.textPrimary }]}>
{formatDate(data.nextPremiumDueDate)}
</Text>
</Text>
<Text style={[styles.infoRow, { color: theme.colors.textSecondary }]}>
Nominee:{' '}
<Text style={[styles.infoStrong, { color: theme.colors.textPrimary }]}>
{data.nomineeName} ({data.nomineeRelationship})
</Text>
</Text>
</View>
</Card>
<Card style={styles.actionCard}>
<View style={styles.actionRow}>
<View style={styles.actionCol}>
<Button
title="Pay Premium"
onPress={() =>
navigation.navigate('InsuranceRenewals', { policyId: data.id })
}
/>
</View>
<View style={styles.actionCol}>
<Button
title="File Claim"
variant="secondary"
onPress={() =>
navigation.navigate('InsuranceClaims', { policyId: data.id })
}
/>
</View>
</View>
<Button
title="Download Policy PDF"
variant="secondary"
onPress={() =>
toast(
'Policy download ready',
'success',
`${data.documents[0]?.name ?? 'Policy schedule'} is ready from the secure vault.`,
)
}
/>
</Card>
<Card style={styles.sectionCard}>
<Text style={[styles.sectionTitle, { color: theme.colors.textPrimary }]}>
Benefits and inclusions
</Text>
{data.benefits.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>
))}
{data.inclusions.map((inclusion) => (
<View key={inclusion} style={styles.listRow}>
<Ionicons name="shield-checkmark" size={16} color={theme.colors.primary} />
<Text style={[styles.listText, { color: theme.colors.textPrimary }]}>
{inclusion}
</Text>
</View>
))}
</Card>
<Card style={styles.sectionCard}>
<Text style={[styles.sectionTitle, { color: theme.colors.textPrimary }]}>
Exclusions
</Text>
{data.exclusions.map((exclusion) => (
<View key={exclusion} style={styles.listRow}>
<Ionicons name="close-circle" size={16} color={theme.colors.error} />
<Text style={[styles.listText, { color: theme.colors.textPrimary }]}>
{exclusion}
</Text>
</View>
))}
</Card>
<Card style={styles.sectionCard}>
<Text style={[styles.sectionTitle, { color: theme.colors.textPrimary }]}>
Insurer details
</Text>
<Text style={[styles.infoRow, { color: theme.colors.textSecondary }]}>
Claims ratio:{' '}
<Text style={[styles.infoStrong, { color: theme.colors.textPrimary }]}>
{data.insurer.claimSettlementRatio}%
</Text>
</Text>
<Text style={[styles.infoRow, { color: theme.colors.textSecondary }]}>
Support:{' '}
<Text style={[styles.infoStrong, { color: theme.colors.textPrimary }]}>
{data.insurer.supportPhone}
</Text>
</Text>
<Text style={[styles.infoRow, { color: theme.colors.textSecondary }]}>
Email:{' '}
<Text style={[styles.infoStrong, { color: theme.colors.textPrimary }]}>
{data.insurer.supportEmail}
</Text>
</Text>
<Text style={[styles.infoRow, { color: theme.colors.textSecondary }]}>
Address:{' '}
<Text style={[styles.infoStrong, { color: theme.colors.textPrimary }]}>
{data.insurer.address}
</Text>
</Text>
</Card>
<Card style={styles.sectionCard}>
<Text style={[styles.sectionTitle, { color: theme.colors.textPrimary }]}>
Policy documents
</Text>
{data.documents.map((document) => (
<Pressable
key={document.id}
onPress={() =>
toast('Document available', 'info', `${document.name} is available in PDF.`)
}
style={[styles.documentRow, { backgroundColor: theme.colors.surfaceMuted }]}
>
<View style={styles.documentCopy}>
<Text style={[styles.documentName, { color: theme.colors.textPrimary }]}>
{document.name}
</Text>
<Text style={[styles.documentMeta, { color: theme.colors.textMuted }]}>
{document.mimeType} · {document.sizeKb} KB
</Text>
</View>
<Ionicons name="download-outline" size={18} color={theme.colors.primary} />
</Pressable>
))}
</Card>
</ScrollView>
)}
<View style={{ height: theme.spacing.xxl }} />
</ScreenShell>
);
}
const styles = StyleSheet.create({
scroll: {
gap: 16,
paddingBottom: 32,
},
heroCard: {
gap: 14,
},
heroHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
gap: 12,
},
heroCopy: {
flex: 1,
gap: 2,
},
heroTitle: {
fontSize: 18,
fontWeight: '800',
},
heroMeta: {
fontSize: 12,
fontWeight: '600',
},
metricGrid: {
flexDirection: 'row',
gap: 12,
},
metricCard: {
flex: 1,
borderRadius: 16,
padding: 14,
gap: 4,
},
metricLabel: {
fontSize: 11,
fontWeight: '700',
textTransform: 'uppercase',
letterSpacing: 0.5,
},
metricValue: {
fontSize: 18,
fontWeight: '900',
},
metricCaption: {
fontSize: 11,
fontWeight: '600',
},
infoList: {
gap: 6,
},
infoRow: {
fontSize: 12,
lineHeight: 18,
},
infoStrong: {
fontWeight: '700',
},
actionCard: {
gap: 12,
},
actionRow: {
flexDirection: 'row',
gap: 12,
},
actionCol: {
flex: 1,
},
sectionCard: {
gap: 10,
},
sectionTitle: {
fontSize: 16,
fontWeight: '800',
},
listRow: {
flexDirection: 'row',
alignItems: 'flex-start',
gap: 8,
},
listText: {
flex: 1,
fontSize: 12,
lineHeight: 18,
fontWeight: '600',
},
documentRow: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
borderRadius: 14,
padding: 12,
},
documentCopy: {
flex: 1,
gap: 3,
},
documentName: {
fontSize: 14,
fontWeight: '700',
},
documentMeta: {
fontSize: 11,
fontWeight: '600',
},
});