Update CBS Mobile App codebase
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import React, { memo } from 'react';
|
||||
import { Pressable, StyleSheet, Text, View } from 'react-native';
|
||||
import Ionicons from '@react-native-vector-icons/ionicons';
|
||||
import { useTheme } from '../../../theme';
|
||||
import { useTheme, fontFamily } from '../../../theme';
|
||||
import { formatDate } from '../../../utils/formatters';
|
||||
import type { LoanDocument } from '../../../types/app';
|
||||
|
||||
@@ -19,7 +19,7 @@ const STATUS_CONFIG: Record<string, { color: string; icon: string; label: string
|
||||
const DocumentItemComponent = ({ document, onReupload }: DocumentItemProps) => {
|
||||
const theme = useTheme();
|
||||
const status = STATUS_CONFIG[document.status] || {
|
||||
color: '#3B82F6',
|
||||
color: theme.colors.info,
|
||||
icon: 'time-outline',
|
||||
label: 'Processing',
|
||||
};
|
||||
@@ -35,7 +35,7 @@ const DocumentItemComponent = ({ document, onReupload }: DocumentItemProps) => {
|
||||
{document.type} · {formatDate(document.uploadedAt)}
|
||||
</Text>
|
||||
{document.rejectionReason && (
|
||||
<Text style={[styles.reason, { color: '#EF4444' }]}>{document.rejectionReason}</Text>
|
||||
<Text style={[styles.reason, { color: theme.colors.danger }]}>{document.rejectionReason}</Text>
|
||||
)}
|
||||
</View>
|
||||
<View style={styles.right}>
|
||||
@@ -70,7 +70,7 @@ const styles = StyleSheet.create({
|
||||
justifyContent: 'center',
|
||||
},
|
||||
copy: { flex: 1, gap: 3 },
|
||||
name: { fontSize: 14, fontWeight: '700' },
|
||||
name: { fontSize: 14, fontFamily: fontFamily.bold },
|
||||
meta: { fontSize: 12 },
|
||||
reason: { fontSize: 11, marginTop: 2, lineHeight: 16 },
|
||||
right: { alignItems: 'flex-end', gap: 6 },
|
||||
@@ -82,9 +82,9 @@ const styles = StyleSheet.create({
|
||||
paddingVertical: 4,
|
||||
borderRadius: 999,
|
||||
},
|
||||
statusText: { fontSize: 11, fontWeight: '700' },
|
||||
statusText: { fontSize: 11, fontFamily: fontFamily.bold },
|
||||
reuploadBtn: { paddingHorizontal: 4, paddingVertical: 2 },
|
||||
reuploadText: { fontSize: 12, fontWeight: '700' },
|
||||
reuploadText: { fontSize: 12, fontFamily: fontFamily.bold },
|
||||
});
|
||||
|
||||
export const DocumentItem = memo(DocumentItemComponent);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { memo } from 'react';
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
import Ionicons from '@react-native-vector-icons/ionicons';
|
||||
import { useTheme } from '../../../theme';
|
||||
import { useTheme, fontFamily } from '../../../theme';
|
||||
import { formatCurrency } from '../../../utils/formatters';
|
||||
import { Card } from '../../../components';
|
||||
import type { LoanEligibilityResult } from '../../../types/app';
|
||||
@@ -20,13 +20,13 @@ const EligibilityResultCardComponent = ({ result }: EligibilityResultCardProps)
|
||||
<View
|
||||
style={[
|
||||
styles.iconContainer,
|
||||
{ backgroundColor: isEligible ? '#10B98114' : '#EF444414' },
|
||||
{ backgroundColor: isEligible ? theme.colors.successSurface : theme.colors.dangerSurface },
|
||||
]}
|
||||
>
|
||||
<Ionicons
|
||||
name={isEligible ? 'checkmark-circle' : 'close-circle'}
|
||||
size={32}
|
||||
color={isEligible ? '#10B981' : '#EF4444'}
|
||||
color={isEligible ? theme.colors.success : theme.colors.danger}
|
||||
/>
|
||||
</View>
|
||||
<Text style={[styles.title, { color: theme.colors.textPrimary }]}>
|
||||
@@ -81,7 +81,7 @@ const styles = StyleSheet.create({
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
title: { fontSize: 20, fontWeight: '900' },
|
||||
title: { fontSize: 20, fontFamily: fontFamily.bold },
|
||||
subtitle: { fontSize: 13, textAlign: 'center', lineHeight: 20 },
|
||||
detailsGrid: {
|
||||
flexDirection: 'row',
|
||||
@@ -91,8 +91,8 @@ const styles = StyleSheet.create({
|
||||
gap: 12,
|
||||
},
|
||||
detailItem: { width: '45%', gap: 4 },
|
||||
detailLabel: { fontSize: 10, fontWeight: '700', textTransform: 'uppercase', letterSpacing: 0.5 },
|
||||
detailValue: { fontSize: 16, fontWeight: '800' },
|
||||
detailLabel: { fontSize: 10, fontFamily: fontFamily.bold, textTransform: 'uppercase', letterSpacing: 0.5 },
|
||||
detailValue: { fontSize: 16, fontFamily: fontFamily.bold },
|
||||
});
|
||||
|
||||
export const EligibilityResultCard = memo(EligibilityResultCardComponent);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { memo } from 'react';
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
import { useTheme } from '../../../theme';
|
||||
import { useTheme, fontFamily } from '../../../theme';
|
||||
import { formatCurrency } from '../../../utils/formatters';
|
||||
import type { LoanEmiScheduleItem } from '../../../types/app';
|
||||
|
||||
@@ -48,7 +48,7 @@ const styles = StyleSheet.create({
|
||||
cell: {
|
||||
flex: 1,
|
||||
fontSize: 11,
|
||||
fontWeight: '500',
|
||||
fontFamily: fontFamily.medium,
|
||||
textAlign: 'right',
|
||||
},
|
||||
monthCell: {
|
||||
@@ -57,7 +57,7 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
headerText: {
|
||||
fontSize: 10,
|
||||
fontWeight: '700',
|
||||
fontFamily: fontFamily.bold,
|
||||
textTransform: 'uppercase',
|
||||
letterSpacing: 0.3,
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { memo } from 'react';
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
import Ionicons from '@react-native-vector-icons/ionicons';
|
||||
import { useTheme } from '../../../theme';
|
||||
import { useTheme, fontFamily } from '../../../theme';
|
||||
import { formatCurrency } from '../../../utils/formatters';
|
||||
import { Card, Button } from '../../../components';
|
||||
import type { LoanForeclosureQuote } from '../../../types/app';
|
||||
@@ -19,7 +19,7 @@ const ForeclosureSheetComponent = ({ quote, onConfirm, onCancel, isLoading }: Fo
|
||||
return (
|
||||
<Card style={styles.card}>
|
||||
<View style={styles.header}>
|
||||
<View style={[styles.icon, { backgroundColor: '#F59E0B14' }]}>
|
||||
<View style={[styles.icon, { backgroundColor: theme.colors.warningSurface }]}>
|
||||
<Ionicons name="warning-outline" size={24} color="#F59E0B" />
|
||||
</View>
|
||||
<Text style={[styles.title, { color: theme.colors.textPrimary }]}>Foreclosure Summary</Text>
|
||||
@@ -73,20 +73,20 @@ const styles = StyleSheet.create({
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
title: { fontSize: 20, fontWeight: '900' },
|
||||
title: { fontSize: 20, fontFamily: fontFamily.bold },
|
||||
subtitle: { fontSize: 13, textAlign: 'center', lineHeight: 20 },
|
||||
breakdown: { borderRadius: 16, padding: 16, gap: 12 },
|
||||
breakdownRow: { flexDirection: 'row', justifyContent: 'space-between' },
|
||||
breakdownLabel: { fontSize: 13, fontWeight: '600' },
|
||||
breakdownValue: { fontSize: 14, fontWeight: '700' },
|
||||
breakdownLabel: { fontSize: 13, fontFamily: fontFamily.semibold },
|
||||
breakdownValue: { fontSize: 14, fontFamily: fontFamily.bold },
|
||||
totalRow: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
paddingTop: 12,
|
||||
borderTopWidth: 1,
|
||||
},
|
||||
totalLabel: { fontSize: 15, fontWeight: '800' },
|
||||
totalValue: { fontSize: 18, fontWeight: '900' },
|
||||
totalLabel: { fontSize: 15, fontFamily: fontFamily.bold },
|
||||
totalValue: { fontSize: 18, fontFamily: fontFamily.bold },
|
||||
actions: { gap: 10 },
|
||||
});
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Pressable, StyleSheet, Text, View } from 'react-native';
|
||||
import Ionicons from '@react-native-vector-icons/ionicons';
|
||||
|
||||
import type { ActiveLoan } from '../../../types/app';
|
||||
import { useTheme } from '../../../theme';
|
||||
import { useTheme, fontFamily } from '../../../theme';
|
||||
import { formatCurrency, formatDate } from '../../../utils/formatters';
|
||||
import { Card } from '../../../components';
|
||||
|
||||
@@ -21,7 +21,7 @@ const STATUS_CONFIG: Record<string, { color: string; icon: string }> = {
|
||||
const LoanAccountCardComponent = ({ loan, onPress }: LoanAccountCardProps) => {
|
||||
const theme = useTheme();
|
||||
const statusConfig = STATUS_CONFIG[loan.status] || {
|
||||
color: '#10B981',
|
||||
color: theme.colors.success,
|
||||
icon: 'checkmark-circle',
|
||||
};
|
||||
const progress = loan.totalEmis > 0 ? (loan.paidEmis / loan.totalEmis) * 100 : 0;
|
||||
@@ -73,7 +73,7 @@ const LoanAccountCardComponent = ({ loan, onPress }: LoanAccountCardProps) => {
|
||||
styles.progressFill,
|
||||
{
|
||||
width: `${Math.min(progress, 100)}%`,
|
||||
backgroundColor: loan.status === 'Overdue' ? '#EF4444' : theme.colors.primary,
|
||||
backgroundColor: loan.status === 'Overdue' ? theme.colors.danger : theme.colors.primary,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
@@ -103,8 +103,8 @@ const styles = StyleSheet.create({
|
||||
card: { gap: 14 },
|
||||
header: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'flex-start' },
|
||||
headerLeft: { gap: 2 },
|
||||
loanType: { fontSize: 16, fontWeight: '800' },
|
||||
accountNumber: { fontSize: 12, fontWeight: '600' },
|
||||
loanType: { fontSize: 16, fontFamily: fontFamily.bold },
|
||||
accountNumber: { fontSize: 12, fontFamily: fontFamily.semibold },
|
||||
statusBadge: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
@@ -113,20 +113,20 @@ const styles = StyleSheet.create({
|
||||
paddingVertical: 5,
|
||||
borderRadius: 999,
|
||||
},
|
||||
statusText: { fontSize: 12, fontWeight: '700' },
|
||||
statusText: { fontSize: 12, fontFamily: fontFamily.bold },
|
||||
amountRow: { flexDirection: 'row', borderRadius: 14, padding: 14, gap: 12 },
|
||||
amountItem: { flex: 1, gap: 4 },
|
||||
amountLabel: { fontSize: 10, fontWeight: '700', textTransform: 'uppercase', letterSpacing: 0.5 },
|
||||
amountValue: { fontSize: 16, fontWeight: '900' },
|
||||
amountLabel: { fontSize: 10, fontFamily: fontFamily.bold, textTransform: 'uppercase', letterSpacing: 0.5 },
|
||||
amountValue: { fontSize: 16, fontFamily: fontFamily.bold },
|
||||
progressSection: { gap: 8 },
|
||||
progressHeader: { flexDirection: 'row', justifyContent: 'space-between' },
|
||||
progressLabel: { fontSize: 12, fontWeight: '600' },
|
||||
progressPercent: { fontSize: 12, fontWeight: '800' },
|
||||
progressLabel: { fontSize: 12, fontFamily: fontFamily.semibold },
|
||||
progressPercent: { fontSize: 12, fontFamily: fontFamily.bold },
|
||||
progressTrack: { height: 6, borderRadius: 3, overflow: 'hidden' },
|
||||
progressFill: { height: '100%', borderRadius: 3 },
|
||||
footer: { flexDirection: 'row', justifyContent: 'space-between' },
|
||||
footerItem: { flexDirection: 'row', alignItems: 'center', gap: 6 },
|
||||
footerText: { fontSize: 12, fontWeight: '600' },
|
||||
footerText: { fontSize: 12, fontFamily: fontFamily.semibold },
|
||||
});
|
||||
|
||||
export const LoanAccountCard = memo(LoanAccountCardComponent);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { memo } from 'react';
|
||||
import { Pressable, StyleSheet, Text } from 'react-native';
|
||||
import { useTheme } from '../../../theme';
|
||||
import { useTheme, fontFamily } from '../../../theme';
|
||||
|
||||
interface LoanFilterChipProps {
|
||||
label: string;
|
||||
@@ -43,7 +43,7 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
label: {
|
||||
fontSize: 13,
|
||||
fontWeight: '700',
|
||||
fontFamily: fontFamily.bold,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { memo } from 'react';
|
||||
import { Pressable, StyleSheet, Text, View } from 'react-native';
|
||||
import Ionicons from '@react-native-vector-icons/ionicons';
|
||||
import { useTheme } from '../../../theme';
|
||||
import { useTheme, fontFamily } from '../../../theme';
|
||||
import type { LoanNotification } from '../../../types/app';
|
||||
|
||||
interface LoanNotificationItemProps {
|
||||
@@ -22,7 +22,7 @@ const LoanNotificationItemComponent = ({ notification, onPress }: LoanNotificati
|
||||
const theme = useTheme();
|
||||
const config = TYPE_CONFIG[notification.type] || {
|
||||
icon: 'alarm-outline',
|
||||
color: '#F59E0B',
|
||||
color: theme.colors.warning,
|
||||
};
|
||||
const timeAgo = getTimeAgo(notification.createdAt);
|
||||
|
||||
@@ -77,7 +77,7 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
copy: { flex: 1, gap: 3 },
|
||||
titleRow: { flexDirection: 'row', alignItems: 'center', gap: 6 },
|
||||
title: { fontSize: 14, fontWeight: '700', flex: 1 },
|
||||
title: { fontSize: 14, fontFamily: fontFamily.bold, flex: 1 },
|
||||
unreadDot: { width: 8, height: 8, borderRadius: 4 },
|
||||
body: { fontSize: 12, lineHeight: 18 },
|
||||
time: { fontSize: 11, marginTop: 2 },
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Pressable, StyleSheet, Text, View } from 'react-native';
|
||||
import Ionicons from '@react-native-vector-icons/ionicons';
|
||||
|
||||
import type { LoanProduct } from '../../../types/app';
|
||||
import { useTheme } from '../../../theme';
|
||||
import { useTheme, fontFamily } from '../../../theme';
|
||||
import { formatCompactCurrency } from '../../../utils/formatters';
|
||||
import { Card } from '../../../components';
|
||||
|
||||
@@ -18,6 +18,7 @@ const CATEGORY_ICONS: Record<string, string> = {
|
||||
'Car Loan': 'car-outline',
|
||||
'Gold Loan': 'diamond-outline',
|
||||
'Education Loan': 'school-outline',
|
||||
'Loan Against DDS Deposit': 'wallet-outline',
|
||||
};
|
||||
|
||||
const CATEGORY_COLORS: Record<string, string> = {
|
||||
@@ -26,6 +27,7 @@ const CATEGORY_COLORS: Record<string, string> = {
|
||||
'Car Loan': '#F59E0B',
|
||||
'Gold Loan': '#EAB308',
|
||||
'Education Loan': '#10B981',
|
||||
'Loan Against DDS Deposit': '#14B8A6',
|
||||
};
|
||||
|
||||
const LoanOfferCardComponent = ({ product, onPress }: LoanOfferCardProps) => {
|
||||
@@ -92,7 +94,7 @@ const styles = StyleSheet.create({
|
||||
justifyContent: 'center',
|
||||
},
|
||||
headerCopy: { flex: 1, gap: 4 },
|
||||
title: { fontSize: 16, fontWeight: '800' },
|
||||
title: { fontSize: 16, fontFamily: fontFamily.bold },
|
||||
description: { fontSize: 12, lineHeight: 18 },
|
||||
rateRow: {
|
||||
flexDirection: 'row',
|
||||
@@ -101,12 +103,12 @@ const styles = StyleSheet.create({
|
||||
padding: 12,
|
||||
},
|
||||
rateItem: { flex: 1, alignItems: 'center', gap: 4 },
|
||||
rateLabel: { fontSize: 10, fontWeight: '700', textTransform: 'uppercase', letterSpacing: 0.5 },
|
||||
rateValue: { fontSize: 16, fontWeight: '900' },
|
||||
rateLabel: { fontSize: 10, fontFamily: fontFamily.bold, textTransform: 'uppercase', letterSpacing: 0.5 },
|
||||
rateValue: { fontSize: 16, fontFamily: fontFamily.bold },
|
||||
divider: { width: 1, height: 28 },
|
||||
features: { flexDirection: 'row', flexWrap: 'wrap', gap: 8 },
|
||||
featureBadge: { borderRadius: 999, paddingHorizontal: 10, paddingVertical: 5 },
|
||||
featureText: { fontSize: 11, fontWeight: '700' },
|
||||
featureText: { fontSize: 11, fontFamily: fontFamily.bold },
|
||||
});
|
||||
|
||||
export const LoanOfferCard = memo(LoanOfferCardComponent);
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { memo } from 'react';
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
import Ionicons from '@react-native-vector-icons/ionicons';
|
||||
|
||||
import { useTheme } from '../../../theme';
|
||||
import { useTheme, fontFamily } from '../../../theme';
|
||||
import { formatCurrency, formatDate } from '../../../utils/formatters';
|
||||
import { Card } from '../../../components';
|
||||
import type { ActiveLoan } from '../../../types/app';
|
||||
@@ -48,8 +48,8 @@ const LoanSummaryHeroComponent = ({ totalOutstanding, nextEmi, summary }: LoanSu
|
||||
</Text>
|
||||
</View>
|
||||
{summary.overdueCount > 0 && (
|
||||
<View style={[styles.alertBadge, { backgroundColor: '#EF444414' }]}>
|
||||
<Text style={[styles.alertBadgeValue, { color: '#EF4444' }]}>{summary.overdueCount}</Text>
|
||||
<View style={[styles.alertBadge, { backgroundColor: theme.colors.dangerSurface }]}>
|
||||
<Text style={[styles.alertBadgeValue, { color: theme.colors.danger }]}>{summary.overdueCount}</Text>
|
||||
<Text style={[styles.alertBadgeLabel, { color: theme.colors.textSecondary }]}>overdue</Text>
|
||||
</View>
|
||||
)}
|
||||
@@ -90,8 +90,8 @@ const styles = StyleSheet.create({
|
||||
justifyContent: 'center',
|
||||
},
|
||||
heroCopy: { flex: 1, gap: 4 },
|
||||
eyebrow: { fontSize: 11, fontWeight: '700', textTransform: 'uppercase', letterSpacing: 0.8 },
|
||||
heroTitle: { fontSize: 18, fontWeight: '900', lineHeight: 24 },
|
||||
eyebrow: { fontSize: 11, fontFamily: fontFamily.bold, textTransform: 'uppercase', letterSpacing: 0.8 },
|
||||
heroTitle: { fontSize: 18, fontFamily: fontFamily.bold, lineHeight: 24 },
|
||||
highlight: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
@@ -101,8 +101,8 @@ const styles = StyleSheet.create({
|
||||
padding: 16,
|
||||
},
|
||||
highlightCopy: { flex: 1, gap: 4 },
|
||||
highlightLabel: { fontSize: 11, fontWeight: '700', textTransform: 'uppercase', letterSpacing: 0.8 },
|
||||
highlightValue: { fontSize: 26, fontWeight: '900', letterSpacing: -0.8 },
|
||||
highlightLabel: { fontSize: 11, fontFamily: fontFamily.bold, textTransform: 'uppercase', letterSpacing: 0.8 },
|
||||
highlightValue: { fontSize: 26, fontFamily: fontFamily.bold, letterSpacing: -0.8 },
|
||||
highlightCaption: { fontSize: 12, lineHeight: 18 },
|
||||
alertBadge: {
|
||||
minWidth: 72,
|
||||
@@ -113,12 +113,12 @@ const styles = StyleSheet.create({
|
||||
paddingHorizontal: 14,
|
||||
paddingVertical: 12,
|
||||
},
|
||||
alertBadgeValue: { fontSize: 22, fontWeight: '900', letterSpacing: -0.5 },
|
||||
alertBadgeLabel: { fontSize: 11, fontWeight: '700', textTransform: 'uppercase', letterSpacing: 0.5 },
|
||||
alertBadgeValue: { fontSize: 22, fontFamily: fontFamily.bold, letterSpacing: -0.5 },
|
||||
alertBadgeLabel: { fontSize: 11, fontFamily: fontFamily.bold, textTransform: 'uppercase', letterSpacing: 0.5 },
|
||||
metrics: { flexDirection: 'row', flexWrap: 'wrap', gap: 12 },
|
||||
metricCard: { flex: 1, minWidth: 140, borderRadius: 18, padding: 14, gap: 6 },
|
||||
metricLabel: { fontSize: 11, fontWeight: '700', textTransform: 'uppercase', letterSpacing: 0.8 },
|
||||
metricValue: { fontSize: 18, fontWeight: '900', letterSpacing: -0.4 },
|
||||
metricLabel: { fontSize: 11, fontFamily: fontFamily.bold, textTransform: 'uppercase', letterSpacing: 0.8 },
|
||||
metricValue: { fontSize: 18, fontFamily: fontFamily.bold, letterSpacing: -0.4 },
|
||||
metricCaption: { fontSize: 12, lineHeight: 18 },
|
||||
});
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { memo } from 'react';
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
import Ionicons from '@react-native-vector-icons/ionicons';
|
||||
|
||||
import { useTheme } from '../../../theme';
|
||||
import { useTheme, fontFamily } from '../../../theme';
|
||||
import { formatDate } from '../../../utils/formatters';
|
||||
import { Card } from '../../../components';
|
||||
|
||||
@@ -69,7 +69,7 @@ const LoanTimelineCardComponent = ({ title, subtitle, timeline }: LoanTimelineCa
|
||||
styles.stepLabel,
|
||||
{
|
||||
color: isPending ? theme.colors.textMuted : theme.colors.textPrimary,
|
||||
fontWeight: isCurrent ? '800' : '600',
|
||||
fontFamily: isCurrent ? fontFamily.bold : fontFamily.semibold,
|
||||
},
|
||||
]}
|
||||
>
|
||||
@@ -94,7 +94,7 @@ const LoanTimelineCardComponent = ({ title, subtitle, timeline }: LoanTimelineCa
|
||||
const styles = StyleSheet.create({
|
||||
card: { gap: 14 },
|
||||
header: { gap: 4 },
|
||||
title: { fontSize: 16, fontWeight: '800' },
|
||||
title: { fontSize: 16, fontFamily: fontFamily.bold },
|
||||
subtitle: { fontSize: 13, lineHeight: 18 },
|
||||
timeline: { gap: 0 },
|
||||
stepRow: { flexDirection: 'row', gap: 12 },
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { memo } from 'react';
|
||||
import { Pressable, StyleSheet, Text, View } from 'react-native';
|
||||
import Ionicons from '@react-native-vector-icons/ionicons';
|
||||
import { useTheme } from '../../../theme';
|
||||
import { useTheme, fontFamily } from '../../../theme';
|
||||
import type { LoanPaymentMethod } from '../../../types/app';
|
||||
|
||||
interface PaymentMethodTileProps {
|
||||
@@ -65,7 +65,7 @@ const styles = StyleSheet.create({
|
||||
justifyContent: 'center',
|
||||
},
|
||||
copy: { flex: 1, gap: 2 },
|
||||
label: { fontSize: 15, fontWeight: '700' },
|
||||
label: { fontSize: 15, fontFamily: fontFamily.bold },
|
||||
description: { fontSize: 12 },
|
||||
});
|
||||
|
||||
|
||||
@@ -5,11 +5,13 @@ import Ionicons from '@react-native-vector-icons/ionicons';
|
||||
|
||||
import type { LoanStackParamList } from '../../../navigation/types';
|
||||
import { Button, Card, Loader, ScreenShell } from '../../../components';
|
||||
import { useTheme } from '../../../theme';
|
||||
import { useTheme, fontFamily } from '../../../theme';
|
||||
import { formatCurrency, formatDate } from '../../../utils/formatters';
|
||||
import { useGetLoanDetailQuery, useGetEmiScheduleQuery, useGetForeclosureQuoteQuery } from '../services/loanApi';
|
||||
import { EmiScheduleRow } from '../components/EmiScheduleRow';
|
||||
import { ForeclosureSheet } from '../components/ForeclosureSheet';
|
||||
import { FeatureKey } from '../../../constants/featureKeys';
|
||||
import { FeatureGate, isFeatureEnabled } from '../../../features';
|
||||
|
||||
type Props = NativeStackScreenProps<LoanStackParamList, 'ActiveLoanDetails'>;
|
||||
|
||||
@@ -80,14 +82,16 @@ export default function ActiveLoanDetailsScreen({ navigation, route }: Props) {
|
||||
<Button title="Pay EMI" onPress={() => navigation.navigate('EmiPayment', { loanId })} leftAccessory={<Ionicons name="cash-outline" size={18} color={theme.colors.white} />} />
|
||||
</View>
|
||||
<View style={styles.actionCol}>
|
||||
<FeatureGate feature={FeatureKey.LOANS_FORECLOSURE}>
|
||||
<Button title="Foreclosure" variant="danger" onPress={() => setShowForeclosure(true)} leftAccessory={<Ionicons name="close-circle-outline" size={18} color={theme.colors.white} />} />
|
||||
</FeatureGate>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</Card>
|
||||
|
||||
{/* Foreclosure Section */}
|
||||
{showForeclosure && foreclosureQuote && (
|
||||
{showForeclosure && foreclosureQuote && isFeatureEnabled(FeatureKey.LOANS_FORECLOSURE) && (
|
||||
<ForeclosureSheet
|
||||
quote={foreclosureQuote}
|
||||
onConfirm={() => setShowForeclosure(false)}
|
||||
@@ -123,14 +127,14 @@ export default function ActiveLoanDetailsScreen({ navigation, route }: Props) {
|
||||
<View style={styles.autoDebitRow}>
|
||||
<View style={styles.autoDebitCopy}>
|
||||
<Text style={[styles.sectionTitle, { color: theme.colors.textPrimary }]}>Auto-Debit</Text>
|
||||
<Text style={[styles.autoDebitStatus, { color: loan.autoDebitEnabled ? '#10B981' : theme.colors.textMuted }]}>
|
||||
<Text style={[styles.autoDebitStatus, { color: loan.autoDebitEnabled ? theme.colors.success : theme.colors.textMuted }]}>
|
||||
{loan.autoDebitEnabled ? 'Enabled' : 'Disabled'} · {loan.accountNumber}
|
||||
</Text>
|
||||
</View>
|
||||
<Ionicons
|
||||
name={loan.autoDebitEnabled ? 'toggle' : 'toggle-outline'}
|
||||
size={36}
|
||||
color={loan.autoDebitEnabled ? '#10B981' : theme.colors.textMuted}
|
||||
color={loan.autoDebitEnabled ? theme.colors.success : theme.colors.textMuted}
|
||||
/>
|
||||
</View>
|
||||
</Card>
|
||||
@@ -152,8 +156,8 @@ function InfoItem({ label, value, theme }: { label: string; value: string; theme
|
||||
|
||||
const infoStyles = StyleSheet.create({
|
||||
item: { width: '48%', gap: 4, marginBottom: 12 },
|
||||
label: { fontSize: 10, fontWeight: '700', textTransform: 'uppercase', letterSpacing: 0.5 },
|
||||
value: { fontSize: 15, fontWeight: '700' },
|
||||
label: { fontSize: 10, fontFamily: fontFamily.bold, textTransform: 'uppercase', letterSpacing: 0.5 },
|
||||
value: { fontSize: 15, fontFamily: fontFamily.bold },
|
||||
});
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
@@ -161,27 +165,27 @@ const styles = StyleSheet.create({
|
||||
infoCard: { gap: 8 },
|
||||
infoGrid: { flexDirection: 'row', flexWrap: 'wrap' },
|
||||
progressCard: { gap: 12 },
|
||||
sectionTitle: { fontSize: 16, fontWeight: '800' },
|
||||
sectionTitle: { fontSize: 16, fontFamily: fontFamily.bold },
|
||||
progressHeader: { flexDirection: 'row', justifyContent: 'space-between' },
|
||||
progressLabel: { fontSize: 13, fontWeight: '600' },
|
||||
progressPercent: { fontSize: 13, fontWeight: '800' },
|
||||
progressLabel: { fontSize: 13, fontFamily: fontFamily.semibold },
|
||||
progressPercent: { fontSize: 13, fontFamily: fontFamily.bold },
|
||||
progressTrack: { height: 8, borderRadius: 4, overflow: 'hidden' },
|
||||
progressFill: { height: '100%', borderRadius: 4 },
|
||||
emiDetails: { flexDirection: 'row', gap: 12 },
|
||||
emiDetailItem: { flex: 1, gap: 4 },
|
||||
emiDetailLabel: { fontSize: 10, fontWeight: '700', textTransform: 'uppercase', letterSpacing: 0.5 },
|
||||
emiDetailValue: { fontSize: 14, fontWeight: '800' },
|
||||
emiDetailLabel: { fontSize: 10, fontFamily: fontFamily.bold, textTransform: 'uppercase', letterSpacing: 0.5 },
|
||||
emiDetailValue: { fontSize: 14, fontFamily: fontFamily.bold },
|
||||
actionsCard: { gap: 12 },
|
||||
actionGrid: { gap: 12 },
|
||||
actionRow: { flexDirection: 'row', gap: 12 },
|
||||
actionCol: { flex: 1 },
|
||||
scheduleCard: { gap: 12 },
|
||||
scheduleHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' },
|
||||
toggleText: { fontSize: 13, fontWeight: '700' },
|
||||
moreText: { textAlign: 'center', paddingVertical: 12, fontSize: 12, fontWeight: '600' },
|
||||
toggleText: { fontSize: 13, fontFamily: fontFamily.bold },
|
||||
moreText: { textAlign: 'center', paddingVertical: 12, fontSize: 12, fontFamily: fontFamily.semibold },
|
||||
autoDebitCard: {},
|
||||
autoDebitRow: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between' },
|
||||
autoDebitCopy: { gap: 4 },
|
||||
autoDebitStatus: { fontSize: 13, fontWeight: '600' },
|
||||
autoDebitStatus: { fontSize: 13, fontFamily: fontFamily.semibold },
|
||||
spacer: { height: 60 },
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@ import Ionicons from '@react-native-vector-icons/ionicons';
|
||||
import type { LoanStackParamList } from '../../../navigation/types';
|
||||
import type { EmploymentType } from '../../../types/app';
|
||||
import { Button, Card, Input, ScreenShell } from '../../../components';
|
||||
import { useTheme } from '../../../theme';
|
||||
import { useTheme, fontFamily } from '../../../theme';
|
||||
import { useLoanApplication } from '../hooks/useLoanApplication';
|
||||
|
||||
type Props = NativeStackScreenProps<LoanStackParamList, 'ApplyLoan'>;
|
||||
@@ -68,7 +68,7 @@ export default function ApplyLoanScreen({ navigation, route }: Props) {
|
||||
return (
|
||||
<ScreenShell title="Application Submitted" scrollable={false}>
|
||||
<View style={styles.successContainer}>
|
||||
<View style={[styles.successIcon, { backgroundColor: '#10B98114' }]}>
|
||||
<View style={[styles.successIcon, { backgroundColor: theme.colors.successSurface }]}>
|
||||
<Ionicons name="checkmark-circle" size={64} color="#10B981" />
|
||||
</View>
|
||||
<Text style={[styles.successTitle, { color: theme.colors.textPrimary }]}>Application Submitted!</Text>
|
||||
@@ -190,8 +190,8 @@ function ReviewRow({ label, value, theme }: { label: string; value: string; them
|
||||
|
||||
const reviewStyles = StyleSheet.create({
|
||||
row: { flexDirection: 'row', justifyContent: 'space-between', paddingVertical: 8 },
|
||||
label: { fontSize: 13, fontWeight: '600' },
|
||||
value: { fontSize: 14, fontWeight: '700' },
|
||||
label: { fontSize: 13, fontFamily: fontFamily.semibold },
|
||||
value: { fontSize: 14, fontFamily: fontFamily.bold },
|
||||
});
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
@@ -199,25 +199,25 @@ const styles = StyleSheet.create({
|
||||
progressSection: { alignItems: 'center', gap: 6 },
|
||||
progressRow: { flexDirection: 'row', gap: 8 },
|
||||
progressDot: { width: 40, height: 4, borderRadius: 2 },
|
||||
stepIndicator: { fontSize: 12, fontWeight: '600' },
|
||||
stepIndicator: { fontSize: 12, fontFamily: fontFamily.semibold },
|
||||
formCard: { gap: 14 },
|
||||
cardTitle: { fontSize: 18, fontWeight: '800' },
|
||||
cardTitle: { fontSize: 18, fontFamily: fontFamily.bold },
|
||||
fieldGroup: { gap: 8 },
|
||||
fieldLabel: { fontSize: 11, fontWeight: '700', letterSpacing: 0.5, marginLeft: 4 },
|
||||
fieldLabel: { fontSize: 11, fontFamily: fontFamily.bold, letterSpacing: 0.5, marginLeft: 4 },
|
||||
chipRow: { flexDirection: 'row', flexWrap: 'wrap', gap: 8 },
|
||||
chip: { paddingHorizontal: 14, paddingVertical: 8, borderRadius: 999, borderWidth: 1 },
|
||||
chipText: { fontSize: 13, fontWeight: '700' },
|
||||
errorText: { fontSize: 12, fontWeight: '500', marginLeft: 4 },
|
||||
chipText: { fontSize: 13, fontFamily: fontFamily.bold },
|
||||
errorText: { fontSize: 12, fontFamily: fontFamily.medium, marginLeft: 4 },
|
||||
docInfo: { fontSize: 13, lineHeight: 20 },
|
||||
docRow: { flexDirection: 'row', alignItems: 'center', gap: 12, padding: 14, borderRadius: 14, borderWidth: 1 },
|
||||
docLabel: { flex: 1, fontSize: 14, fontWeight: '600' },
|
||||
docAction: { fontSize: 13, fontWeight: '700' },
|
||||
docLabel: { flex: 1, fontSize: 14, fontFamily: fontFamily.semibold },
|
||||
docAction: { fontSize: 13, fontFamily: fontFamily.bold },
|
||||
reviewGrid: { borderRadius: 14, padding: 14, gap: 4 },
|
||||
navRow: { flexDirection: 'row', gap: 12 },
|
||||
navBtn: { flex: 1 },
|
||||
successContainer: { flex: 1, alignItems: 'center', justifyContent: 'center', gap: 16, padding: 20 },
|
||||
successIcon: { width: 96, height: 96, borderRadius: 48, alignItems: 'center', justifyContent: 'center' },
|
||||
successTitle: { fontSize: 24, fontWeight: '900' },
|
||||
successTitle: { fontSize: 24, fontFamily: fontFamily.bold },
|
||||
successSubtitle: { fontSize: 14, textAlign: 'center', lineHeight: 22 },
|
||||
successActions: { gap: 10, width: '100%' },
|
||||
spacer: { height: 40 },
|
||||
|
||||
@@ -6,7 +6,7 @@ import Ionicons from '@react-native-vector-icons/ionicons';
|
||||
import type { LoanStackParamList } from '../../../navigation/types';
|
||||
import type { LoanPaymentMethod } from '../../../types/app';
|
||||
import { Button, Card, Loader, ScreenShell } from '../../../components';
|
||||
import { useTheme } from '../../../theme';
|
||||
import { useTheme, fontFamily } from '../../../theme';
|
||||
import { formatCurrency, formatDate } from '../../../utils/formatters';
|
||||
import { useGetLoanDetailQuery, usePayEmiMutation, useGetLoanHistoryQuery } from '../services/loanApi';
|
||||
import { PaymentMethodTile } from '../components/PaymentMethodTile';
|
||||
@@ -45,8 +45,8 @@ export default function EmiPaymentScreen({ navigation, route }: Props) {
|
||||
return (
|
||||
<ScreenShell title="Payment Result" scrollable={false}>
|
||||
<View style={styles.resultContainer}>
|
||||
<View style={[styles.resultIcon, { backgroundColor: paymentResult.success ? '#10B98114' : '#EF444414' }]}>
|
||||
<Ionicons name={paymentResult.success ? 'checkmark-circle' : 'close-circle'} size={64} color={paymentResult.success ? '#10B981' : '#EF4444'} />
|
||||
<View style={[styles.resultIcon, { backgroundColor: paymentResult.success ? theme.colors.successSurface : theme.colors.dangerSurface }]}>
|
||||
<Ionicons name={paymentResult.success ? 'checkmark-circle' : 'close-circle'} size={64} color={paymentResult.success ? theme.colors.success : theme.colors.danger} />
|
||||
</View>
|
||||
<Text style={[styles.resultTitle, { color: theme.colors.textPrimary }]}>
|
||||
{paymentResult.success ? 'Payment Successful!' : 'Payment Failed'}
|
||||
@@ -101,7 +101,7 @@ export default function EmiPaymentScreen({ navigation, route }: Props) {
|
||||
{loanHistory.map((record) => (
|
||||
<View key={record.id} style={[styles.historyRow, { borderBottomColor: theme.colors.cardBorder }]}>
|
||||
<View style={styles.historyLeft}>
|
||||
<Ionicons name={record.status === 'success' ? 'checkmark-circle' : 'close-circle'} size={18} color={record.status === 'success' ? '#10B981' : '#EF4444'} />
|
||||
<Ionicons name={record.status === 'success' ? 'checkmark-circle' : 'close-circle'} size={18} color={record.status === 'success' ? theme.colors.success : theme.colors.danger} />
|
||||
<View style={styles.historyCopy}>
|
||||
<Text style={[styles.historyAmount, { color: theme.colors.textPrimary }]}>{formatCurrency(record.amount)}</Text>
|
||||
<Text style={[styles.historyMeta, { color: theme.colors.textMuted }]}>{record.method} · {formatDate(record.date)}</Text>
|
||||
@@ -123,20 +123,20 @@ const styles = StyleSheet.create({
|
||||
summaryCard: {},
|
||||
summaryRow: { flexDirection: 'row', gap: 16 },
|
||||
summaryItem: { flex: 1, gap: 4 },
|
||||
summaryLabel: { fontSize: 10, fontWeight: '700', textTransform: 'uppercase', letterSpacing: 0.5 },
|
||||
summaryValue: { fontSize: 20, fontWeight: '900' },
|
||||
summaryLabel: { fontSize: 10, fontFamily: fontFamily.bold, textTransform: 'uppercase', letterSpacing: 0.5 },
|
||||
summaryValue: { fontSize: 20, fontFamily: fontFamily.bold },
|
||||
section: { gap: 12 },
|
||||
sectionTitle: { fontSize: 16, fontWeight: '800' },
|
||||
sectionTitle: { fontSize: 16, fontFamily: fontFamily.bold },
|
||||
methodList: { gap: 10 },
|
||||
historyCard: { gap: 12 },
|
||||
historyRow: { flexDirection: 'row', alignItems: 'center', paddingVertical: 10, borderBottomWidth: 1 },
|
||||
historyLeft: { flexDirection: 'row', alignItems: 'center', gap: 10 },
|
||||
historyCopy: { gap: 2 },
|
||||
historyAmount: { fontSize: 14, fontWeight: '700' },
|
||||
historyAmount: { fontSize: 14, fontFamily: fontFamily.bold },
|
||||
historyMeta: { fontSize: 12 },
|
||||
resultContainer: { flex: 1, alignItems: 'center', justifyContent: 'center', gap: 16, padding: 20 },
|
||||
resultIcon: { width: 96, height: 96, borderRadius: 48, alignItems: 'center', justifyContent: 'center' },
|
||||
resultTitle: { fontSize: 24, fontWeight: '900' },
|
||||
resultTitle: { fontSize: 24, fontFamily: fontFamily.bold },
|
||||
resultSubtitle: { fontSize: 14, textAlign: 'center', lineHeight: 22 },
|
||||
resultActions: { gap: 10, width: '100%' },
|
||||
spacer: { height: 40 },
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { NativeStackScreenProps } from '@react-navigation/native-stack';
|
||||
|
||||
import type { LoanStackParamList } from '../../../navigation/types';
|
||||
import { Card, Input, ScreenShell } from '../../../components';
|
||||
import { useTheme } from '../../../theme';
|
||||
import { useTheme, fontFamily } from '../../../theme';
|
||||
import { formatCurrency } from '../../../utils/formatters';
|
||||
import { useAppDispatch } from '../../../app/hooks';
|
||||
import { loanActions } from '../store/loanSlice';
|
||||
@@ -149,8 +149,8 @@ const styles = StyleSheet.create({
|
||||
scroll: { gap: 16, paddingBottom: 24 },
|
||||
inputCard: { gap: 14 },
|
||||
resultCard: { gap: 12, alignItems: 'center' },
|
||||
resultLabel: { fontSize: 12, fontWeight: '700', textTransform: 'uppercase', letterSpacing: 0.8 },
|
||||
resultValue: { fontSize: 34, fontWeight: '900', letterSpacing: -1 },
|
||||
resultLabel: { fontSize: 12, fontFamily: fontFamily.bold, textTransform: 'uppercase', letterSpacing: 0.8 },
|
||||
resultValue: { fontSize: 34, fontFamily: fontFamily.bold, letterSpacing: -1 },
|
||||
breakdownBar: {
|
||||
flexDirection: 'row',
|
||||
width: '100%',
|
||||
@@ -164,8 +164,8 @@ const styles = StyleSheet.create({
|
||||
metricsRow: { flexDirection: 'row', gap: 12, width: '100%' },
|
||||
metricCard: { flex: 1, borderRadius: 14, padding: 12, gap: 4 },
|
||||
metricDot: { width: 10, height: 10, borderRadius: 5 },
|
||||
metricLabel: { fontSize: 11, fontWeight: '700', textTransform: 'uppercase', letterSpacing: 0.5 },
|
||||
metricValue: { fontSize: 16, fontWeight: '800' },
|
||||
metricLabel: { fontSize: 11, fontFamily: fontFamily.bold, textTransform: 'uppercase', letterSpacing: 0.5 },
|
||||
metricValue: { fontSize: 16, fontFamily: fontFamily.bold },
|
||||
totalRow: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
@@ -174,13 +174,13 @@ const styles = StyleSheet.create({
|
||||
paddingTop: 12,
|
||||
borderTopWidth: 1,
|
||||
},
|
||||
totalLabel: { fontSize: 13, fontWeight: '600' },
|
||||
totalValue: { fontSize: 18, fontWeight: '900' },
|
||||
totalLabel: { fontSize: 13, fontFamily: fontFamily.semibold },
|
||||
totalValue: { fontSize: 18, fontFamily: fontFamily.bold },
|
||||
scheduleCard: { gap: 12 },
|
||||
scheduleHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' },
|
||||
sectionTitle: { fontSize: 16, fontWeight: '800' },
|
||||
toggleText: { fontSize: 13, fontWeight: '700' },
|
||||
sectionTitle: { fontSize: 16, fontFamily: fontFamily.bold },
|
||||
toggleText: { fontSize: 13, fontFamily: fontFamily.bold },
|
||||
scheduleTable: { gap: 0 },
|
||||
moreText: { textAlign: 'center', paddingVertical: 12, fontSize: 12, fontWeight: '600' },
|
||||
moreText: { textAlign: 'center', paddingVertical: 12, fontSize: 12, fontFamily: fontFamily.semibold },
|
||||
spacer: { height: 40 },
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@ import Ionicons from '@react-native-vector-icons/ionicons';
|
||||
|
||||
import type { LoanStackParamList } from '../../../navigation/types';
|
||||
import { Button, Card, EmptyState, Loader, ScreenShell } from '../../../components';
|
||||
import { useTheme } from '../../../theme';
|
||||
import { useTheme, fontFamily } from '../../../theme';
|
||||
import { formatCurrency, formatDate, formatCompactCurrency } from '../../../utils/formatters';
|
||||
import { useLoanDashboard } from '../hooks/useLoanDashboard';
|
||||
import { LoanSummaryHero } from '../components/LoanSummaryHero';
|
||||
@@ -189,8 +189,8 @@ export default function LoanDashboardScreen({ navigation }: Props) {
|
||||
style={[
|
||||
styles.appStatusBadge,
|
||||
{
|
||||
backgroundColor: app.status === 'Approved' ? '#10B98114' :
|
||||
app.status === 'Rejected' ? '#EF444414' : `${theme.colors.primary}14`,
|
||||
backgroundColor: app.status === 'Approved' ? theme.colors.successSurface :
|
||||
app.status === 'Rejected' ? theme.colors.dangerSurface : `${theme.colors.primary}14`,
|
||||
},
|
||||
]}
|
||||
>
|
||||
@@ -198,8 +198,8 @@ export default function LoanDashboardScreen({ navigation }: Props) {
|
||||
style={[
|
||||
styles.appStatusText,
|
||||
{
|
||||
color: app.status === 'Approved' ? '#10B981' :
|
||||
app.status === 'Rejected' ? '#EF4444' : theme.colors.primary,
|
||||
color: app.status === 'Approved' ? theme.colors.success :
|
||||
app.status === 'Rejected' ? theme.colors.danger : theme.colors.primary,
|
||||
},
|
||||
]}
|
||||
>
|
||||
@@ -222,7 +222,7 @@ const styles = StyleSheet.create({
|
||||
scrollContent: { gap: 18, paddingBottom: 24 },
|
||||
actionCard: { gap: 16 },
|
||||
sectionHeader: { gap: 4 },
|
||||
sectionTitle: { fontSize: 18, fontWeight: '800' },
|
||||
sectionTitle: { fontSize: 18, fontFamily: fontFamily.bold },
|
||||
sectionSubtitle: { fontSize: 13, lineHeight: 18 },
|
||||
actionGrid: { gap: 12 },
|
||||
actionRow: { flexDirection: 'row', gap: 12 },
|
||||
@@ -240,15 +240,15 @@ const styles = StyleSheet.create({
|
||||
unreadCount: {
|
||||
color: '#FFF',
|
||||
fontSize: 12,
|
||||
fontWeight: '800',
|
||||
fontFamily: fontFamily.bold,
|
||||
},
|
||||
notificationCard: { padding: 4, gap: 0 },
|
||||
divider: { height: 1, marginHorizontal: 12 },
|
||||
appHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' },
|
||||
appHeaderLeft: { gap: 2 },
|
||||
appType: { fontSize: 15, fontWeight: '700' },
|
||||
appAmount: { fontSize: 12, fontWeight: '500' },
|
||||
appType: { fontSize: 15, fontFamily: fontFamily.bold },
|
||||
appAmount: { fontSize: 12, fontFamily: fontFamily.medium },
|
||||
appStatusBadge: { paddingHorizontal: 10, paddingVertical: 5, borderRadius: 999 },
|
||||
appStatusText: { fontSize: 12, fontWeight: '700' },
|
||||
appStatusText: { fontSize: 12, fontFamily: fontFamily.bold },
|
||||
bottomSpacer: { height: 60 },
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@ import Ionicons from '@react-native-vector-icons/ionicons';
|
||||
|
||||
import type { LoanStackParamList } from '../../../navigation/types';
|
||||
import { Button, Card, EmptyState, Loader, ScreenShell } from '../../../components';
|
||||
import { useTheme } from '../../../theme';
|
||||
import { useTheme, fontFamily } from '../../../theme';
|
||||
import { useGetLoanDocumentsQuery } from '../services/loanApi';
|
||||
import { DocumentItem } from '../components/DocumentItem';
|
||||
|
||||
@@ -25,16 +25,16 @@ export default function LoanDocumentsScreen(_props: Props) {
|
||||
{/* Summary */}
|
||||
<Card style={styles.summaryCard}>
|
||||
<View style={styles.summaryRow}>
|
||||
<View style={[styles.summaryBadge, { backgroundColor: '#10B98114' }]}>
|
||||
<Text style={[styles.summaryBadgeValue, { color: '#10B981' }]}>{verified}</Text>
|
||||
<View style={[styles.summaryBadge, { backgroundColor: theme.colors.successSurface }]}>
|
||||
<Text style={[styles.summaryBadgeValue, { color: theme.colors.success }]}>{verified}</Text>
|
||||
<Text style={[styles.summaryBadgeLabel, { color: theme.colors.textSecondary }]}>Verified</Text>
|
||||
</View>
|
||||
<View style={[styles.summaryBadge, { backgroundColor: '#3B82F614' }]}>
|
||||
<Text style={[styles.summaryBadgeValue, { color: '#3B82F6' }]}>{pending}</Text>
|
||||
<View style={[styles.summaryBadge, { backgroundColor: theme.colors.infoSurface }]}>
|
||||
<Text style={[styles.summaryBadgeValue, { color: theme.colors.info }]}>{pending}</Text>
|
||||
<Text style={[styles.summaryBadgeLabel, { color: theme.colors.textSecondary }]}>Processing</Text>
|
||||
</View>
|
||||
<View style={[styles.summaryBadge, { backgroundColor: '#EF444414' }]}>
|
||||
<Text style={[styles.summaryBadgeValue, { color: '#EF4444' }]}>{rejected}</Text>
|
||||
<View style={[styles.summaryBadge, { backgroundColor: theme.colors.dangerSurface }]}>
|
||||
<Text style={[styles.summaryBadgeValue, { color: theme.colors.danger }]}>{rejected}</Text>
|
||||
<Text style={[styles.summaryBadgeLabel, { color: theme.colors.textSecondary }]}>Rejected</Text>
|
||||
</View>
|
||||
</View>
|
||||
@@ -85,9 +85,9 @@ const styles = StyleSheet.create({
|
||||
summaryCard: {},
|
||||
summaryRow: { flexDirection: 'row', gap: 12 },
|
||||
summaryBadge: { flex: 1, borderRadius: 16, alignItems: 'center', paddingVertical: 14, gap: 4 },
|
||||
summaryBadgeValue: { fontSize: 24, fontWeight: '900' },
|
||||
summaryBadgeLabel: { fontSize: 11, fontWeight: '700', textTransform: 'uppercase', letterSpacing: 0.5 },
|
||||
summaryBadgeValue: { fontSize: 24, fontFamily: fontFamily.bold },
|
||||
summaryBadgeLabel: { fontSize: 11, fontFamily: fontFamily.bold, textTransform: 'uppercase', letterSpacing: 0.5 },
|
||||
docList: { gap: 10 },
|
||||
sectionTitle: { fontSize: 16, fontWeight: '800' },
|
||||
sectionTitle: { fontSize: 16, fontFamily: fontFamily.bold },
|
||||
spacer: { height: 60 },
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@ import Ionicons from '@react-native-vector-icons/ionicons';
|
||||
import type { LoanStackParamList } from '../../../navigation/types';
|
||||
import type { EmploymentType } from '../../../types/app';
|
||||
import { Button, Card, Input, Loader, ScreenShell } from '../../../components';
|
||||
import { useTheme } from '../../../theme';
|
||||
import { useTheme, fontFamily } from '../../../theme';
|
||||
import { useLoanEligibility } from '../hooks/useLoanEligibility';
|
||||
import { EligibilityResultCard } from '../components/EligibilityResultCard';
|
||||
|
||||
@@ -160,14 +160,14 @@ const styles = StyleSheet.create({
|
||||
scroll: { gap: 16, paddingBottom: 24 },
|
||||
formCard: { gap: 16 },
|
||||
sectionHeader: { gap: 4 },
|
||||
sectionTitle: { fontSize: 18, fontWeight: '800' },
|
||||
sectionTitle: { fontSize: 18, fontFamily: fontFamily.bold },
|
||||
sectionSubtitle: { fontSize: 13, lineHeight: 18 },
|
||||
fieldGroup: { gap: 8 },
|
||||
fieldLabel: { fontSize: 11, fontWeight: '700', letterSpacing: 0.5, marginLeft: 4 },
|
||||
fieldLabel: { fontSize: 11, fontFamily: fontFamily.bold, letterSpacing: 0.5, marginLeft: 4 },
|
||||
chipRow: { flexDirection: 'row', flexWrap: 'wrap', gap: 8 },
|
||||
chip: { paddingHorizontal: 14, paddingVertical: 8, borderRadius: 999, borderWidth: 1 },
|
||||
chipText: { fontSize: 13, fontWeight: '700' },
|
||||
errorText: { fontSize: 12, fontWeight: '500', marginLeft: 4 },
|
||||
chipText: { fontSize: 13, fontFamily: fontFamily.bold },
|
||||
errorText: { fontSize: 12, fontFamily: fontFamily.medium, marginLeft: 4 },
|
||||
resultActions: { gap: 10 },
|
||||
spacer: { height: 40 },
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@ import Ionicons from '@react-native-vector-icons/ionicons';
|
||||
|
||||
import type { LoanStackParamList } from '../../../navigation/types';
|
||||
import { Card, EmptyState, Loader, ScreenShell } from '../../../components';
|
||||
import { useTheme } from '../../../theme';
|
||||
import { useTheme, fontFamily } from '../../../theme';
|
||||
import { formatCurrency, formatDate } from '../../../utils/formatters';
|
||||
import { useGetLoanHistoryQuery } from '../services/loanApi';
|
||||
import { LoanFilterChip } from '../components/LoanFilterChip';
|
||||
@@ -79,11 +79,11 @@ export default function LoanHistoryScreen(_props: Props) {
|
||||
index < filtered.length - 1 && { borderBottomWidth: 1, borderBottomColor: theme.colors.cardBorder },
|
||||
]}
|
||||
>
|
||||
<View style={[styles.recordIcon, { backgroundColor: record.status === 'success' ? '#10B98114' : '#EF444414' }]}>
|
||||
<View style={[styles.recordIcon, { backgroundColor: record.status === 'success' ? theme.colors.successSurface : theme.colors.dangerSurface }]}>
|
||||
<Ionicons
|
||||
name={record.status === 'success' ? 'checkmark-circle' : 'close-circle'}
|
||||
size={20}
|
||||
color={record.status === 'success' ? '#10B981' : '#EF4444'}
|
||||
color={record.status === 'success' ? theme.colors.success : theme.colors.danger}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.recordCopy}>
|
||||
@@ -100,7 +100,7 @@ export default function LoanHistoryScreen(_props: Props) {
|
||||
<Text
|
||||
style={[
|
||||
styles.recordStatus,
|
||||
{ color: record.status === 'success' ? '#10B981' : '#EF4444' },
|
||||
{ color: record.status === 'success' ? theme.colors.success : theme.colors.danger },
|
||||
]}
|
||||
>
|
||||
{record.status === 'success' ? 'Paid' : 'Failed'}
|
||||
@@ -122,18 +122,18 @@ const styles = StyleSheet.create({
|
||||
summaryCard: {},
|
||||
summaryRow: { flexDirection: 'row', gap: 16 },
|
||||
summaryItem: { flex: 1, gap: 4 },
|
||||
summaryLabel: { fontSize: 10, fontWeight: '700', textTransform: 'uppercase', letterSpacing: 0.5 },
|
||||
summaryValue: { fontSize: 22, fontWeight: '900' },
|
||||
summaryLabel: { fontSize: 10, fontFamily: fontFamily.bold, textTransform: 'uppercase', letterSpacing: 0.5 },
|
||||
summaryValue: { fontSize: 22, fontFamily: fontFamily.bold },
|
||||
filterRow: { flexDirection: 'row', flexWrap: 'wrap', gap: 8 },
|
||||
listCard: { gap: 0, padding: 0 },
|
||||
recordRow: { flexDirection: 'row', alignItems: 'center', gap: 12, paddingHorizontal: 16, paddingVertical: 14 },
|
||||
recordIcon: { width: 40, height: 40, borderRadius: 12, alignItems: 'center', justifyContent: 'center' },
|
||||
recordCopy: { flex: 1, gap: 2 },
|
||||
recordType: { fontSize: 14, fontWeight: '700' },
|
||||
recordType: { fontSize: 14, fontFamily: fontFamily.bold },
|
||||
recordMeta: { fontSize: 12 },
|
||||
recordRef: { fontSize: 10 },
|
||||
recordRight: { alignItems: 'flex-end', gap: 4 },
|
||||
recordAmount: { fontSize: 15, fontWeight: '800' },
|
||||
recordStatus: { fontSize: 11, fontWeight: '700' },
|
||||
recordAmount: { fontSize: 15, fontFamily: fontFamily.bold },
|
||||
recordStatus: { fontSize: 11, fontFamily: fontFamily.bold },
|
||||
spacer: { height: 60 },
|
||||
});
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { NativeStackScreenProps } from '@react-navigation/native-stack';
|
||||
|
||||
import type { LoanStackParamList } from '../../../navigation/types';
|
||||
import { Card, EmptyState, Loader, ScreenShell } from '../../../components';
|
||||
import { useTheme } from '../../../theme';
|
||||
import { useTheme, fontFamily } from '../../../theme';
|
||||
import { formatCurrency, formatDate } from '../../../utils/formatters';
|
||||
import { useGetLoanApplicationsQuery } from '../services/loanApi';
|
||||
import { LoanTimelineCard } from '../components/LoanTimelineCard';
|
||||
@@ -73,7 +73,7 @@ export default function LoanTrackingScreen({ navigation }: Props) {
|
||||
<Card style={styles.approvedCard}>
|
||||
<View style={styles.approvedRow}>
|
||||
<Text style={[styles.approvedLabel, { color: theme.colors.textSecondary }]}>Approved Amount</Text>
|
||||
<Text style={[styles.approvedValue, { color: '#10B981' }]}>{formatCurrency(app.approvedAmount)}</Text>
|
||||
<Text style={[styles.approvedValue, { color: theme.colors.success }]}>{formatCurrency(app.approvedAmount)}</Text>
|
||||
</View>
|
||||
</Card>
|
||||
)}
|
||||
@@ -92,7 +92,7 @@ const styles = StyleSheet.create({
|
||||
filterRow: { flexDirection: 'row', flexWrap: 'wrap', gap: 8 },
|
||||
approvedCard: { marginTop: -6 },
|
||||
approvedRow: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' },
|
||||
approvedLabel: { fontSize: 13, fontWeight: '600' },
|
||||
approvedValue: { fontSize: 18, fontWeight: '900' },
|
||||
approvedLabel: { fontSize: 13, fontFamily: fontFamily.semibold },
|
||||
approvedValue: { fontSize: 18, fontFamily: fontFamily.bold },
|
||||
spacer: { height: 60 },
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user