160 lines
4.7 KiB
TypeScript
160 lines
4.7 KiB
TypeScript
import React from 'react';
|
|
import { View, Text, Pressable, StyleSheet } from 'react-native';
|
|
import { useRouter } from 'expo-router';
|
|
import { LinearGradient } from 'expo-linear-gradient';
|
|
import { Colors, Fonts, FontSize, BorderRadius, Shadows, Spacing } from '@/constants/theme';
|
|
import { positions } from '@/constants/mockData';
|
|
import { formatPrice, formatPercent, formatCurrency } from '@/utils/format';
|
|
import Sparkline from '@/components/Sparkline';
|
|
import AnimatedCard from '@/components/AnimatedCard';
|
|
|
|
export default function QuickPositions() {
|
|
const router = useRouter();
|
|
const preview = positions.slice(0, 2);
|
|
|
|
return (
|
|
<View style={styles.container}>
|
|
<View style={styles.header}>
|
|
<Text style={styles.title}>ACTIVE POSITIONS</Text>
|
|
<Pressable onPress={() => router.push('/positions' as any)}>
|
|
<Text style={styles.seeAll}>See All →</Text>
|
|
</Pressable>
|
|
</View>
|
|
|
|
{preview.map((pos, index) => {
|
|
const isPositive = pos.unrealizedPnl >= 0;
|
|
const color = isPositive ? Colors.accent.green : Colors.accent.red;
|
|
return (
|
|
<AnimatedCard key={pos.id} index={index + 5} style={[styles.cardWrapper, Shadows.card]}>
|
|
<LinearGradient
|
|
colors={['rgba(20,21,26,0.9)', 'rgba(14,15,18,0.95)']}
|
|
start={{ x: 0, y: 0 }}
|
|
end={{ x: 1, y: 1 }}
|
|
style={styles.card}
|
|
>
|
|
<View style={[styles.accentLine, { backgroundColor: pos.side === 'BUY' ? Colors.accent.green : Colors.accent.red }]} />
|
|
<View style={styles.topRow}>
|
|
<Text style={styles.symbol}>{pos.symbol}</Text>
|
|
<View style={[styles.sideBadge, { backgroundColor: pos.side === 'BUY' ? 'rgba(0,255,136,0.15)' : 'rgba(255,51,102,0.15)' }]}>
|
|
<Text style={[styles.sideText, { color }]}>{pos.side === 'BUY' ? 'LONG' : 'SHORT'}</Text>
|
|
</View>
|
|
<Text style={styles.profileName}>{pos.profileName}</Text>
|
|
</View>
|
|
<View style={styles.priceRow}>
|
|
<View>
|
|
<Text style={styles.currentPrice}>{formatPrice(pos.currentPrice)}</Text>
|
|
<Text style={styles.entryPrice}>Entry {formatPrice(pos.entryPrice)}</Text>
|
|
</View>
|
|
<View style={styles.pnlContainer}>
|
|
<Text style={[styles.pnl, { color }]}>
|
|
{formatCurrency(pos.unrealizedPnl)} ({formatPercent(pos.unrealizedPnlPercent)})
|
|
</Text>
|
|
</View>
|
|
</View>
|
|
<Sparkline
|
|
data={pos.sparkData}
|
|
width={280}
|
|
height={32}
|
|
color={color}
|
|
/>
|
|
</LinearGradient>
|
|
</AnimatedCard>
|
|
);
|
|
})}
|
|
</View>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
gap: 10,
|
|
},
|
|
header: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
justifyContent: 'space-between',
|
|
marginBottom: 4,
|
|
},
|
|
title: {
|
|
fontFamily: Fonts.inter.black,
|
|
fontSize: FontSize.micro,
|
|
color: Colors.text.secondary,
|
|
letterSpacing: 3,
|
|
},
|
|
seeAll: {
|
|
fontFamily: Fonts.inter.semiBold,
|
|
fontSize: FontSize.bodySmall,
|
|
color: Colors.accent.green,
|
|
},
|
|
cardWrapper: {
|
|
borderRadius: BorderRadius.large,
|
|
},
|
|
card: {
|
|
borderRadius: BorderRadius.large,
|
|
padding: Spacing.cardPadding,
|
|
borderWidth: 1,
|
|
borderColor: Colors.border.default,
|
|
overflow: 'hidden',
|
|
},
|
|
accentLine: {
|
|
position: 'absolute',
|
|
top: 0,
|
|
left: 0,
|
|
right: 0,
|
|
height: 2,
|
|
opacity: 0.6,
|
|
},
|
|
topRow: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
gap: 8,
|
|
marginBottom: 12,
|
|
},
|
|
symbol: {
|
|
fontFamily: Fonts.inter.black,
|
|
fontSize: FontSize.subheading,
|
|
color: Colors.text.primary,
|
|
letterSpacing: -0.3,
|
|
},
|
|
sideBadge: {
|
|
paddingHorizontal: 8,
|
|
paddingVertical: 3,
|
|
borderRadius: 6,
|
|
},
|
|
sideText: {
|
|
fontFamily: Fonts.inter.black,
|
|
fontSize: FontSize.micro,
|
|
letterSpacing: 1,
|
|
},
|
|
profileName: {
|
|
fontFamily: Fonts.inter.medium,
|
|
fontSize: FontSize.badge,
|
|
color: Colors.text.secondary,
|
|
marginLeft: 'auto',
|
|
},
|
|
priceRow: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
alignItems: 'flex-end',
|
|
marginBottom: 12,
|
|
},
|
|
currentPrice: {
|
|
fontFamily: Fonts.mono.bold,
|
|
fontSize: FontSize.heading,
|
|
color: Colors.text.primary,
|
|
},
|
|
entryPrice: {
|
|
fontFamily: Fonts.mono.regular,
|
|
fontSize: FontSize.badge,
|
|
color: Colors.text.secondary,
|
|
marginTop: 2,
|
|
},
|
|
pnlContainer: {
|
|
alignItems: 'flex-end',
|
|
},
|
|
pnl: {
|
|
fontFamily: Fonts.mono.bold,
|
|
fontSize: FontSize.bodyLarge,
|
|
},
|
|
});
|