82 lines
3.7 KiB
TypeScript
82 lines
3.7 KiB
TypeScript
import { useFocusEffect } from 'expo-router';
|
|
import { useCallback, useState } from 'react';
|
|
import { ScrollView, Text, View } from 'react-native';
|
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
import { getDB } from '../../db';
|
|
import { Goal } from '../../types';
|
|
|
|
export default function GoalsScreen() {
|
|
const insets = useSafeAreaInsets();
|
|
const [goals, setGoals] = useState<Goal[]>([]);
|
|
|
|
const fetchData = useCallback(async () => {
|
|
try {
|
|
const db = getDB();
|
|
const result = await db.getAllAsync<Goal>('SELECT * FROM goals ORDER BY deadline ASC');
|
|
setGoals(result);
|
|
} catch (error) {
|
|
console.error('Error fetching goals', error);
|
|
}
|
|
}, []);
|
|
|
|
useFocusEffect(
|
|
useCallback(() => {
|
|
fetchData();
|
|
}, [fetchData])
|
|
);
|
|
|
|
const calculateProgress = (current: number, target: number) => {
|
|
if (target === 0) return 0;
|
|
return Math.min((current / target) * 100, 100);
|
|
};
|
|
|
|
return (
|
|
<View className="flex-1 bg-gray-100 dark:bg-gray-900" style={{ paddingTop: insets.top }}>
|
|
<ScrollView className="flex-1 px-6">
|
|
<View className="py-6">
|
|
<Text className="text-3xl font-bold text-gray-900 dark:text-white">Financial Goals</Text>
|
|
<Text className="text-gray-500 mt-1">Stay disciplined and reach your targets.</Text>
|
|
</View>
|
|
|
|
{goals.length === 0 ? (
|
|
<View className="items-center py-10">
|
|
<Text className="text-gray-400">No goals set yet.</Text>
|
|
</View>
|
|
) : (
|
|
goals.map((item) => {
|
|
const progress = calculateProgress(item.current_amount, item.target_amount);
|
|
return (
|
|
<View key={item.id} className="bg-white dark:bg-gray-800 p-6 mb-4 rounded-2xl shadow-sm">
|
|
<View className="flex-row justify-between items-start mb-4">
|
|
<View>
|
|
<Text className="text-xl font-bold text-gray-900 dark:text-white">{item.name}</Text>
|
|
{item.deadline && (
|
|
<Text className="text-gray-500 text-xs">Deadline: {item.deadline}</Text>
|
|
)}
|
|
</View>
|
|
<View className="bg-blue-100 px-3 py-1 rounded-full">
|
|
<Text className="text-blue-600 font-bold text-xs">{progress.toFixed(0)}%</Text>
|
|
</View>
|
|
</View>
|
|
|
|
<View className="flex-row justify-between mb-2">
|
|
<Text className="text-gray-500 text-sm">€{item.current_amount.toFixed(2)} saved</Text>
|
|
<Text className="text-gray-900 dark:text-white font-bold text-sm">Target: €{item.target_amount.toFixed(2)}</Text>
|
|
</View>
|
|
|
|
{/* Progress Bar */}
|
|
<View className="h-3 bg-gray-100 dark:bg-gray-700 rounded-full overflow-hidden">
|
|
<View
|
|
className="h-full bg-blue-600 rounded-full"
|
|
style={{ width: `${progress}%` }}
|
|
/>
|
|
</View>
|
|
</View>
|
|
);
|
|
})
|
|
)}
|
|
</ScrollView>
|
|
</View>
|
|
);
|
|
}
|