115 lines
4.1 KiB
TypeScript
115 lines
4.1 KiB
TypeScript
import { FontAwesome } from '@expo/vector-icons';
|
|
import { useFocusEffect } from 'expo-router';
|
|
import { useCallback, useState } from 'react';
|
|
import { ScrollView, Text, View } from 'react-native';
|
|
import { PieChart } from 'react-native-gifted-charts';
|
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
import { getDB } from '../../db';
|
|
import { Asset } from '../../types';
|
|
|
|
export default function InvestmentsScreen() {
|
|
const insets = useSafeAreaInsets();
|
|
const [assets, setAssets] = useState<Asset[]>([]);
|
|
const [totalValue, setTotalValue] = useState(0);
|
|
const [pieData, setPieData] = useState<any[]>([]);
|
|
|
|
const fetchData = useCallback(async () => {
|
|
try {
|
|
const db = getDB();
|
|
const result = await db.getAllAsync<Asset>('SELECT * FROM assets ORDER BY value DESC');
|
|
setAssets(result);
|
|
|
|
const total = result.reduce((acc, asset) => acc + asset.value, 0);
|
|
setTotalValue(total);
|
|
|
|
// Prepare Pie Data
|
|
const colors = ['#9333EA', '#C084FC', '#A855F7', '#7E22CE', '#6B21A8'];
|
|
const data = result.map((asset, index) => ({
|
|
value: asset.value,
|
|
color: colors[index % colors.length],
|
|
text: `${Math.round((asset.value / total) * 100)}%`,
|
|
}));
|
|
setPieData(data);
|
|
|
|
} catch (error) {
|
|
console.error('Error fetching assets', error);
|
|
}
|
|
}, []);
|
|
|
|
useFocusEffect(
|
|
useCallback(() => {
|
|
fetchData();
|
|
}, [fetchData])
|
|
);
|
|
|
|
const getIconName = (type: string) => {
|
|
switch (type) {
|
|
case 'stock': return 'line-chart';
|
|
case 'crypto': return 'bitcoin';
|
|
case 'real_estate': return 'home';
|
|
case 'fund': return 'pie-chart';
|
|
default: return 'money';
|
|
}
|
|
};
|
|
|
|
return (
|
|
<View className="flex-1 bg-gray-100 dark:bg-gray-900" style={{ paddingTop: insets.top }}>
|
|
<ScrollView className="flex-1 px-6">
|
|
{/* Header */}
|
|
<View className="py-6">
|
|
<Text className="text-gray-500 text-sm">Total Portfolio Value</Text>
|
|
<Text className="text-4xl font-bold text-gray-900 dark:text-white">€{totalValue.toFixed(2)}</Text>
|
|
</View>
|
|
|
|
{/* Asset Distribution */}
|
|
<View className="bg-white dark:bg-gray-800 rounded-2xl p-6 mb-8 shadow-sm items-center">
|
|
<Text className="text-lg font-bold text-gray-900 dark:text-white mb-4 self-start">Asset Allocation</Text>
|
|
{pieData.length > 0 ? (
|
|
<PieChart
|
|
data={pieData}
|
|
donut
|
|
showText
|
|
textColor="white"
|
|
radius={100}
|
|
innerRadius={60}
|
|
textSize={12}
|
|
focusOnPress
|
|
/>
|
|
) : (
|
|
<Text className="text-gray-500">No assets to display.</Text>
|
|
)}
|
|
</View>
|
|
|
|
{/* Assets List */}
|
|
<Text className="text-xl font-bold text-gray-900 dark:text-white mb-4">Your Assets</Text>
|
|
|
|
{assets.length === 0 ? (
|
|
<View className="items-center py-10">
|
|
<Text className="text-gray-400">No assets added yet.</Text>
|
|
</View>
|
|
) : (
|
|
assets.map((item) => (
|
|
<View key={item.id} className="bg-white dark:bg-gray-800 p-4 mb-3 rounded-2xl shadow-sm flex-row items-center justify-between">
|
|
<View className="flex-row items-center">
|
|
<View className="w-10 h-10 rounded-full bg-purple-100 items-center justify-center mr-4">
|
|
<FontAwesome name={getIconName(item.type)} size={16} color="#9333EA" />
|
|
</View>
|
|
<View>
|
|
<Text className="font-bold text-gray-900 dark:text-white text-base">{item.name}</Text>
|
|
<Text className="text-gray-500 text-xs capitalize">{item.type.replace('_', ' ')}</Text>
|
|
</View>
|
|
</View>
|
|
<View className="items-end">
|
|
<Text className="font-bold text-base text-gray-900 dark:text-white">€{item.value.toFixed(2)}</Text>
|
|
{item.quantity && (
|
|
<Text className="text-gray-400 text-xs">{item.quantity} units</Text>
|
|
)}
|
|
</View>
|
|
</View>
|
|
))
|
|
)}
|
|
</ScrollView>
|
|
</View>
|
|
);
|
|
}
|