Fix form keyboard issues and sticky footers in agent screens
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
import React from 'react';
|
||||
import { StyleSheet, Text, View, Pressable } from 'react-native';
|
||||
import { useTheme } from '../../../theme';
|
||||
|
||||
interface HomeSectionHeaderProps {
|
||||
title: string;
|
||||
onSeeAll?: () => void;
|
||||
}
|
||||
|
||||
export const HomeSectionHeader = ({ title, onSeeAll }: HomeSectionHeaderProps) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={[styles.title, { color: theme.colors.textPrimary }]}>{title}</Text>
|
||||
{onSeeAll && (
|
||||
<Pressable onPress={onSeeAll}>
|
||||
<Text style={[styles.seeAll, { color: theme.colors.primary }]}>See All</Text>
|
||||
</Pressable>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: 16,
|
||||
paddingHorizontal: 4,
|
||||
},
|
||||
title: {
|
||||
fontSize: 18,
|
||||
fontWeight: '800',
|
||||
letterSpacing: -0.5,
|
||||
},
|
||||
seeAll: {
|
||||
fontSize: 14,
|
||||
fontWeight: '700',
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,113 @@
|
||||
import React from 'react';
|
||||
import { StyleSheet, Text, View, ScrollView, Pressable } from 'react-native';
|
||||
import Ionicons from '@react-native-vector-icons/ionicons';
|
||||
import { useTheme } from '../../../theme';
|
||||
|
||||
interface Category {
|
||||
id: string;
|
||||
name: string;
|
||||
icon: string;
|
||||
}
|
||||
|
||||
interface HorizontalCategoriesProps {
|
||||
onCategoryPress?: (categoryId: string) => void;
|
||||
}
|
||||
|
||||
const CATEGORIES: Category[] = [
|
||||
{ id: 'cards', name: 'Cards', icon: 'card-outline' },
|
||||
{ id: 'deposits', name: 'Deposits', icon: 'wallet-outline' },
|
||||
{ id: 'loans', name: 'Loans', icon: 'business-outline' },
|
||||
{ id: 'insurance', name: 'Insurance', icon: 'shield-outline' },
|
||||
];
|
||||
|
||||
export const HorizontalCategories = ({ onCategoryPress }: HorizontalCategoriesProps) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<ScrollView
|
||||
horizontal
|
||||
showsHorizontalScrollIndicator={false}
|
||||
contentContainerStyle={styles.container}
|
||||
>
|
||||
{CATEGORIES.map((cat) => {
|
||||
return (
|
||||
<Pressable
|
||||
key={cat.id}
|
||||
onPress={() => onCategoryPress?.(cat.id)}
|
||||
style={({ pressed }) => [
|
||||
styles.pill,
|
||||
{
|
||||
backgroundColor: pressed ? theme.colors.surfaceMuted : theme.colors.surface,
|
||||
borderColor: theme.colors.cardBorder,
|
||||
borderRadius: 16,
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 4 },
|
||||
shadowOpacity: pressed ? 0.08 : 0.05,
|
||||
shadowRadius: pressed ? 10 : 8,
|
||||
elevation: pressed ? 4 : 2,
|
||||
opacity: pressed ? 0.96 : 1,
|
||||
transform: [{ scale: pressed ? 0.97 : 1 }],
|
||||
},
|
||||
]}
|
||||
>
|
||||
{({ pressed }) => (
|
||||
<>
|
||||
<View
|
||||
style={[
|
||||
styles.iconBox,
|
||||
{
|
||||
backgroundColor: pressed
|
||||
? 'rgba(0, 0, 0, 0.08)'
|
||||
: 'rgba(0, 0, 0, 0.05)',
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Ionicons
|
||||
name={cat.icon as any}
|
||||
size={18}
|
||||
color={theme.colors.textSecondary}
|
||||
/>
|
||||
</View>
|
||||
<Text
|
||||
style={[
|
||||
styles.name,
|
||||
{ color: theme.colors.textPrimary },
|
||||
]}
|
||||
>
|
||||
{cat.name}
|
||||
</Text>
|
||||
</>
|
||||
)}
|
||||
</Pressable>
|
||||
);
|
||||
})}
|
||||
</ScrollView>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
paddingHorizontal: 6,
|
||||
gap: 12,
|
||||
paddingVertical: 12,
|
||||
},
|
||||
pill: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: 12,
|
||||
paddingVertical: 10,
|
||||
gap: 10,
|
||||
borderWidth: 1,
|
||||
},
|
||||
iconBox: {
|
||||
width: 32,
|
||||
height: 32,
|
||||
borderRadius: 8,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
name: {
|
||||
fontSize: 14,
|
||||
fontWeight: '700',
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,107 @@
|
||||
import React, { memo } from 'react';
|
||||
import {
|
||||
StyleSheet,
|
||||
Text,
|
||||
View,
|
||||
} from 'react-native';
|
||||
|
||||
import type { InsightMetric, SpendingBreakdown } from '../../../types/app';
|
||||
import { useTheme } from '../../../theme';
|
||||
import { formatCompactCurrency } from '../../../utils/formatters';
|
||||
import { Card } from '../../../components';
|
||||
|
||||
interface InsightsCardProps {
|
||||
insights: InsightMetric[];
|
||||
spending: SpendingBreakdown[];
|
||||
}
|
||||
|
||||
const InsightsCardComponent = ({ insights, spending }: InsightsCardProps) => {
|
||||
const theme = useTheme();
|
||||
const totalSpend = spending.reduce((sum, item) => sum + item.amount, 0);
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<Text style={[styles.heading, { color: theme.colors.textPrimary }]}>Smart insights</Text>
|
||||
<View style={styles.metricRow}>
|
||||
{insights.map((metric) => (
|
||||
<View key={metric.id} style={styles.metricCell}>
|
||||
<Text style={[styles.metricLabel, { color: theme.colors.textSecondary }]}>
|
||||
{metric.label}
|
||||
</Text>
|
||||
<Text style={[styles.metricValue, { color: theme.colors.textPrimary }]}>
|
||||
{formatCompactCurrency(metric.amount)}
|
||||
</Text>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
<Text style={[styles.subheading, { color: theme.colors.textSecondary }]}>
|
||||
Monthly spend mix · {formatCompactCurrency(totalSpend)}
|
||||
</Text>
|
||||
<View style={styles.barRow}>
|
||||
{spending.map((item) => (
|
||||
<View key={item.id} style={styles.barCell}>
|
||||
<View
|
||||
style={[
|
||||
styles.bar,
|
||||
{
|
||||
backgroundColor: item.color,
|
||||
height: Math.max(24, item.amount / 500),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<Text style={[styles.barLabel, { color: theme.colors.textSecondary }]}>{item.label}</Text>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
heading: {
|
||||
fontSize: 18,
|
||||
fontWeight: '700',
|
||||
},
|
||||
metricRow: {
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
gap: 12,
|
||||
marginTop: 14,
|
||||
},
|
||||
metricCell: {
|
||||
minWidth: '30%',
|
||||
gap: 6,
|
||||
},
|
||||
metricLabel: {
|
||||
fontSize: 12,
|
||||
},
|
||||
metricValue: {
|
||||
fontSize: 15,
|
||||
fontWeight: '700',
|
||||
},
|
||||
subheading: {
|
||||
fontSize: 12,
|
||||
marginTop: 18,
|
||||
},
|
||||
barRow: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'flex-end',
|
||||
justifyContent: 'space-between',
|
||||
gap: 12,
|
||||
marginTop: 14,
|
||||
},
|
||||
barCell: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
gap: 8,
|
||||
},
|
||||
bar: {
|
||||
width: '100%',
|
||||
borderRadius: 999,
|
||||
},
|
||||
barLabel: {
|
||||
fontSize: 11,
|
||||
},
|
||||
});
|
||||
|
||||
export const InsightsCard = memo(InsightsCardComponent);
|
||||
@@ -0,0 +1,135 @@
|
||||
import React, { memo } from 'react';
|
||||
import { StyleSheet, Text, View, Pressable, ImageBackground } from 'react-native';
|
||||
import LinearGradient from 'react-native-linear-gradient';
|
||||
import { useTheme } from '../../../theme';
|
||||
|
||||
interface PromoBannerProps {
|
||||
title: string;
|
||||
subtitle: string;
|
||||
badge?: string;
|
||||
interestRate?: string;
|
||||
onPress?: () => void;
|
||||
colors?: [string, string, string];
|
||||
}
|
||||
|
||||
const PromoBannerComponent = ({
|
||||
title,
|
||||
subtitle,
|
||||
badge,
|
||||
interestRate,
|
||||
onPress,
|
||||
colors = ['#3B82F6', '#2563EB', '#1D4ED8'],
|
||||
}: PromoBannerProps) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<Pressable onPress={onPress}>
|
||||
<LinearGradient
|
||||
colors={colors}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
style={[styles.container, { borderRadius: 28, overflow: 'hidden' }]}
|
||||
>
|
||||
<View style={styles.topRow}>
|
||||
{badge && (
|
||||
<View style={[styles.badge, { backgroundColor: 'rgba(255, 255, 255, 0.2)' }]}>
|
||||
<Text style={styles.badgeText}>{badge.toUpperCase()}</Text>
|
||||
</View>
|
||||
)}
|
||||
{interestRate && (
|
||||
<Text style={styles.rateText}>{interestRate} p.a.</Text>
|
||||
)}
|
||||
</View>
|
||||
|
||||
<View style={styles.content}>
|
||||
<Text style={styles.title}>{title}</Text>
|
||||
<Text style={styles.subtitle} numberOfLines={2}>{subtitle}</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.footer}>
|
||||
<Text style={styles.ctaText}>Apply Now</Text>
|
||||
<View style={[styles.arrowCircle, { backgroundColor: 'white' }]}>
|
||||
<Text style={{ color: colors[1], fontSize: 14 }}>→</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Decorative Circles */}
|
||||
<View style={[styles.circle, { top: -40, right: -40, width: 120, height: 120, opacity: 0.1 }]} />
|
||||
<View style={[styles.circle, { bottom: -60, left: -20, width: 150, height: 150, opacity: 0.15 }]} />
|
||||
</LinearGradient>
|
||||
</Pressable>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
padding: 24,
|
||||
gap: 16,
|
||||
position: 'relative',
|
||||
minHeight: 180,
|
||||
},
|
||||
topRow: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
},
|
||||
badge: {
|
||||
paddingHorizontal: 12,
|
||||
paddingVertical: 6,
|
||||
borderRadius: 8,
|
||||
},
|
||||
badgeText: {
|
||||
color: 'white',
|
||||
fontSize: 10,
|
||||
fontWeight: '800',
|
||||
letterSpacing: 1,
|
||||
},
|
||||
rateText: {
|
||||
color: 'rgba(255, 255, 255, 0.8)',
|
||||
fontSize: 13,
|
||||
fontWeight: '700',
|
||||
},
|
||||
content: {
|
||||
gap: 6,
|
||||
zIndex: 1,
|
||||
},
|
||||
title: {
|
||||
color: 'white',
|
||||
fontSize: 24,
|
||||
fontWeight: '900',
|
||||
letterSpacing: -0.5,
|
||||
},
|
||||
subtitle: {
|
||||
color: 'rgba(255, 255, 255, 0.7)',
|
||||
fontSize: 14,
|
||||
fontWeight: '500',
|
||||
lineHeight: 20,
|
||||
maxWidth: '80%',
|
||||
},
|
||||
footer: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 8,
|
||||
marginTop: 8,
|
||||
zIndex: 1,
|
||||
},
|
||||
ctaText: {
|
||||
color: 'white',
|
||||
fontSize: 15,
|
||||
fontWeight: '700',
|
||||
},
|
||||
arrowCircle: {
|
||||
width: 24,
|
||||
height: 24,
|
||||
borderRadius: 12,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
circle: {
|
||||
position: 'absolute',
|
||||
borderRadius: 100,
|
||||
backgroundColor: 'white',
|
||||
},
|
||||
});
|
||||
|
||||
export const PromoBanner = memo(PromoBannerComponent);
|
||||
@@ -0,0 +1,97 @@
|
||||
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 { Card } from '../../../components';
|
||||
|
||||
const CBS_ACTIONS = [
|
||||
{ id: 'transfer', title: 'Transfer', subtitle: 'Send Funds', icon: 'send', color: '#1E40AF', route: 'Payments' },
|
||||
{ id: 'payments', title: 'Pay Bills', subtitle: 'Utilities', icon: 'receipt', color: '#10B981', route: 'Payments' },
|
||||
{ id: 'airtime', title: 'Airtime', subtitle: 'Recharge', icon: 'phone-portrait', color: '#8B5CF6', route: 'Payments' },
|
||||
{ id: 'loans', title: 'Loans', subtitle: 'Manage', icon: 'cash', color: '#F59E0B', route: 'LoanFlow' },
|
||||
{ id: 'cards', title: 'Cards', subtitle: 'Security', icon: 'card', color: '#EC4899', route: 'Cards' },
|
||||
{ id: 'services', title: 'Stats', subtitle: 'Summary', icon: 'stats-chart', color: '#0EA5E9', route: 'Home' },
|
||||
];
|
||||
|
||||
interface QuickActionsProps {
|
||||
onPressRoute: (route: string) => void;
|
||||
}
|
||||
|
||||
const QuickActionsComponent = ({ onPressRoute }: QuickActionsProps) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<View style={styles.grid}>
|
||||
{CBS_ACTIONS.map((action) => (
|
||||
<Card
|
||||
key={action.id}
|
||||
style={styles.card}
|
||||
>
|
||||
<Pressable
|
||||
onPress={() => onPressRoute(action.route)}
|
||||
style={styles.pressable}
|
||||
>
|
||||
<View style={[styles.iconContainer, { backgroundColor: `${action.color}15` }]}>
|
||||
<Ionicons name={action.icon as any} size={22} color={action.color} />
|
||||
</View>
|
||||
<View>
|
||||
<Text style={[styles.title, { color: theme.colors.textPrimary }]}>{action.title}</Text>
|
||||
<Text style={[styles.subtitle, { color: theme.colors.textSecondary }]}>
|
||||
{action.subtitle}
|
||||
</Text>
|
||||
</View>
|
||||
</Pressable>
|
||||
</Card>
|
||||
))}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
grid: {
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
gap: 12,
|
||||
},
|
||||
card: {
|
||||
width: '31%', // Three columns for a more dense, premium feel
|
||||
padding: 0,
|
||||
borderRadius: 20,
|
||||
overflow: 'hidden',
|
||||
},
|
||||
pressable: {
|
||||
padding: 16,
|
||||
gap: 10,
|
||||
alignItems: 'center',
|
||||
},
|
||||
iconContainer: {
|
||||
width: 48,
|
||||
height: 48,
|
||||
borderRadius: 14,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
title: {
|
||||
fontSize: 13,
|
||||
fontWeight: '800',
|
||||
textAlign: 'center',
|
||||
letterSpacing: -0.2,
|
||||
},
|
||||
subtitle: {
|
||||
fontSize: 9,
|
||||
marginTop: 2,
|
||||
fontWeight: '600',
|
||||
textAlign: 'center',
|
||||
opacity: 0.6,
|
||||
textTransform: 'uppercase',
|
||||
},
|
||||
});
|
||||
|
||||
export const QuickActions = memo(QuickActionsComponent);
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
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';
|
||||
|
||||
interface ServiceGridItemProps {
|
||||
id: string;
|
||||
title: string;
|
||||
icon: string;
|
||||
iconColor?: string;
|
||||
onPress?: () => void;
|
||||
fullWidth?: boolean;
|
||||
}
|
||||
|
||||
const ServiceGridItemComponent = ({
|
||||
title,
|
||||
icon,
|
||||
iconColor,
|
||||
onPress,
|
||||
fullWidth = false,
|
||||
}: ServiceGridItemProps) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<Pressable
|
||||
onPress={onPress}
|
||||
style={({ pressed }) => [
|
||||
styles.container,
|
||||
{
|
||||
backgroundColor: theme.colors.surface,
|
||||
borderColor: theme.colors.cardBorder,
|
||||
borderRadius: 20,
|
||||
width: fullWidth ? '100%' : '48%',
|
||||
shadowColor: '#0F172A',
|
||||
shadowOffset: { width: 0, height: pressed ? 2 : 6 },
|
||||
shadowOpacity: pressed ? 0.025 : 0.055,
|
||||
shadowRadius: pressed ? 8 : 14,
|
||||
elevation: pressed ? 1 : 2,
|
||||
opacity: pressed ? 0.98 : 1,
|
||||
transform: [{ scale: pressed ? 0.992 : 1 }, { translateY: pressed ? 1 : 0 }],
|
||||
},
|
||||
]}
|
||||
>
|
||||
<View
|
||||
style={[
|
||||
styles.iconFrame,
|
||||
{
|
||||
backgroundColor: `${iconColor || theme.colors.primary}12`,
|
||||
borderColor: `${iconColor || theme.colors.primary}18`,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Ionicons name={icon as any} size={22} color={iconColor || theme.colors.primary} />
|
||||
</View>
|
||||
<Text style={[styles.title, { color: theme.colors.textPrimary }]} numberOfLines={2}>
|
||||
{title}
|
||||
</Text>
|
||||
</Pressable>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
minHeight: 112,
|
||||
justifyContent: 'space-between',
|
||||
borderWidth: 1,
|
||||
padding: 15,
|
||||
gap: 10,
|
||||
marginBottom: 14,
|
||||
},
|
||||
iconFrame: {
|
||||
width: 44,
|
||||
height: 44,
|
||||
borderRadius: 14,
|
||||
borderWidth: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
title: {
|
||||
fontSize: 13,
|
||||
fontWeight: '700',
|
||||
letterSpacing: -0.2,
|
||||
lineHeight: 17,
|
||||
},
|
||||
});
|
||||
|
||||
export const ServiceGridItem = memo(ServiceGridItemComponent);
|
||||
@@ -0,0 +1,118 @@
|
||||
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 { Card } from '../../../components';
|
||||
|
||||
interface SummaryCardProps {
|
||||
branch: string;
|
||||
user: string;
|
||||
tenant: string;
|
||||
}
|
||||
|
||||
const SummaryCardComponent = ({ branch, user, tenant }: SummaryCardProps) => {
|
||||
const theme = useTheme();
|
||||
const today = new Date().toLocaleDateString('en-IN', {
|
||||
day: '2-digit',
|
||||
month: 'short',
|
||||
year: 'numeric',
|
||||
});
|
||||
|
||||
return (
|
||||
<Card style={styles.container}>
|
||||
<View style={styles.header}>
|
||||
<View style={[styles.iconFrame, { backgroundColor: `${theme.colors.primary}10` }]}>
|
||||
<Ionicons name="information-circle" size={18} color={theme.colors.primary} />
|
||||
</View>
|
||||
<View>
|
||||
<Text style={[styles.title, { color: theme.colors.textPrimary }]}>Account Details</Text>
|
||||
<Text style={[styles.date, { color: theme.colors.textSecondary }]}>{today}</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.grid}>
|
||||
<View style={styles.item}>
|
||||
<Text style={[styles.label, { color: theme.colors.textSecondary }]}>Branch Name</Text>
|
||||
<Text style={[styles.value, { color: theme.colors.textPrimary }]}>{branch}</Text>
|
||||
</View>
|
||||
<View style={styles.item}>
|
||||
<Text style={[styles.label, { color: theme.colors.textSecondary }]}>Account ID</Text>
|
||||
<Text style={[styles.value, { color: theme.colors.textPrimary }]}>{user}</Text>
|
||||
</View>
|
||||
<View style={styles.item}>
|
||||
<Text style={[styles.label, { color: theme.colors.textSecondary }]}>Server Node</Text>
|
||||
<Text style={[styles.value, { color: theme.colors.textPrimary }]}>{tenant}</Text>
|
||||
</View>
|
||||
<View style={styles.item}>
|
||||
<Text style={[styles.label, { color: theme.colors.textSecondary }]}>System Status</Text>
|
||||
<View style={styles.row}>
|
||||
<View style={[styles.dot, { backgroundColor: theme.colors.success }]} />
|
||||
<Text style={[styles.value, { color: theme.colors.success }]}>Online</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
gap: 20,
|
||||
padding: 20,
|
||||
borderRadius: 24,
|
||||
},
|
||||
header: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 12,
|
||||
},
|
||||
iconFrame: {
|
||||
width: 36,
|
||||
height: 36,
|
||||
borderRadius: 10,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
title: {
|
||||
fontSize: 16,
|
||||
fontWeight: '800',
|
||||
letterSpacing: -0.3,
|
||||
},
|
||||
date: {
|
||||
fontSize: 12,
|
||||
fontWeight: '500',
|
||||
marginTop: 1,
|
||||
},
|
||||
grid: {
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
rowGap: 16,
|
||||
},
|
||||
item: {
|
||||
width: '50%',
|
||||
gap: 4,
|
||||
},
|
||||
label: {
|
||||
fontSize: 10,
|
||||
fontWeight: '700',
|
||||
textTransform: 'uppercase',
|
||||
letterSpacing: 1,
|
||||
},
|
||||
value: {
|
||||
fontSize: 13,
|
||||
fontWeight: '700',
|
||||
},
|
||||
row: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 6,
|
||||
},
|
||||
dot: {
|
||||
width: 6,
|
||||
height: 6,
|
||||
borderRadius: 3,
|
||||
},
|
||||
});
|
||||
|
||||
export const SummaryCard = memo(SummaryCardComponent);
|
||||
|
||||
Reference in New Issue
Block a user