144 lines
6.0 KiB
TypeScript
144 lines
6.0 KiB
TypeScript
import { router } from 'expo-router';
|
|
import { StatusBar } from 'expo-status-bar';
|
|
import { useState } from 'react';
|
|
import { KeyboardAvoidingView, Platform, ScrollView, Text, TextInput, TouchableOpacity, View } from 'react-native';
|
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
import { getDB } from '../db';
|
|
|
|
export default function AddTransactionScreen() {
|
|
const insets = useSafeAreaInsets();
|
|
const [amount, setAmount] = useState('');
|
|
const [category, setCategory] = useState('');
|
|
const [description, setDescription] = useState('');
|
|
const [type, setType] = useState<'income' | 'expense'>('expense');
|
|
const [date, setDate] = useState(new Date().toISOString().split('T')[0]); // YYYY-MM-DD
|
|
|
|
const handleSave = async () => {
|
|
if (!amount || !category) {
|
|
alert('Please fill in amount and category');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const db = getDB();
|
|
await db.runAsync(
|
|
'INSERT INTO transactions (amount, category, date, description, type) VALUES (?, ?, ?, ?, ?)',
|
|
[parseFloat(amount), category, date, description, type]
|
|
);
|
|
router.back();
|
|
} catch (error) {
|
|
console.error(error);
|
|
alert('Failed to save transaction');
|
|
}
|
|
};
|
|
|
|
return (
|
|
<View className="flex-1 bg-gray-100 dark:bg-gray-900">
|
|
<StatusBar style={Platform.OS === 'ios' ? 'light' : 'auto'} />
|
|
|
|
{/* Header */}
|
|
<View className="bg-blue-600 pt-4 pb-6 px-6 rounded-b-3xl shadow-lg">
|
|
<Text className="text-white text-2xl font-bold mt-8 text-center">New Transaction</Text>
|
|
</View>
|
|
|
|
<KeyboardAvoidingView
|
|
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
|
className="flex-1"
|
|
>
|
|
<ScrollView className="flex-1 px-6 pt-6">
|
|
|
|
{/* Type Selector */}
|
|
<View className="flex-row bg-white dark:bg-gray-800 rounded-xl p-1 mb-6 shadow-sm">
|
|
<TouchableOpacity
|
|
className={`flex-1 py-3 rounded-lg ${type === 'expense' ? 'bg-red-500' : 'bg-transparent'}`}
|
|
onPress={() => setType('expense')}
|
|
>
|
|
<Text className={`text-center font-semibold ${type === 'expense' ? 'text-white' : 'text-gray-500'}`}>Expense</Text>
|
|
</TouchableOpacity>
|
|
<TouchableOpacity
|
|
className={`flex-1 py-3 rounded-lg ${type === 'income' ? 'bg-green-500' : 'bg-transparent'}`}
|
|
onPress={() => setType('income')}
|
|
>
|
|
<Text className={`text-center font-semibold ${type === 'income' ? 'text-white' : 'text-gray-500'}`}>Income</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
|
|
{/* Amount Input */}
|
|
<View className="bg-white dark:bg-gray-800 rounded-2xl p-6 mb-4 shadow-sm">
|
|
<Text className="text-gray-500 text-sm mb-2">Amount</Text>
|
|
<View className="flex-row items-center">
|
|
<Text className="text-3xl font-bold text-gray-900 dark:text-white mr-2">€</Text>
|
|
<TextInput
|
|
className="flex-1 text-4xl font-bold text-gray-900 dark:text-white"
|
|
placeholder="0.00"
|
|
keyboardType="numeric"
|
|
value={amount}
|
|
onChangeText={setAmount}
|
|
placeholderTextColor="#9CA3AF"
|
|
/>
|
|
</View>
|
|
</View>
|
|
|
|
{/* Details Form */}
|
|
<View className="bg-white dark:bg-gray-800 rounded-2xl p-6 shadow-sm space-y-4">
|
|
<View>
|
|
<Text className="text-gray-500 text-sm mb-2">Category</Text>
|
|
<ScrollView horizontal showsHorizontalScrollIndicator={false} className="flex-row space-x-2 mb-2">
|
|
{['Food', 'Transport', 'Shopping', 'Entertainment', 'Bills', 'Health', 'Salary', 'Investment', 'Other'].map((cat) => (
|
|
<TouchableOpacity
|
|
key={cat}
|
|
onPress={() => setCategory(cat)}
|
|
className={`px-4 py-2 rounded-full border ${category === cat ? 'bg-blue-600 border-blue-600' : 'bg-gray-50 border-gray-200 dark:bg-gray-700 dark:border-gray-600'}`}
|
|
>
|
|
<Text className={`${category === cat ? 'text-white' : 'text-gray-900 dark:text-gray-300'}`}>{cat}</Text>
|
|
</TouchableOpacity>
|
|
))}
|
|
</ScrollView>
|
|
<TextInput
|
|
className="w-full bg-gray-50 dark:bg-gray-700 p-4 rounded-xl text-gray-900 dark:text-white"
|
|
placeholder="Or type custom category..."
|
|
value={category}
|
|
onChangeText={setCategory}
|
|
placeholderTextColor="#9CA3AF"
|
|
/>
|
|
</View>
|
|
|
|
<View className="mt-4">
|
|
<Text className="text-gray-500 text-sm mb-2">Date</Text>
|
|
<TextInput
|
|
className="w-full bg-gray-50 dark:bg-gray-700 p-4 rounded-xl text-gray-900 dark:text-white"
|
|
placeholder="YYYY-MM-DD"
|
|
value={date}
|
|
onChangeText={setDate}
|
|
placeholderTextColor="#9CA3AF"
|
|
/>
|
|
</View>
|
|
|
|
<View className="mt-4">
|
|
<Text className="text-gray-500 text-sm mb-2">Description (Optional)</Text>
|
|
<TextInput
|
|
className="w-full bg-gray-50 dark:bg-gray-700 p-4 rounded-xl text-gray-900 dark:text-white"
|
|
placeholder="Add a note..."
|
|
value={description}
|
|
onChangeText={setDescription}
|
|
placeholderTextColor="#9CA3AF"
|
|
/>
|
|
</View>
|
|
</View>
|
|
|
|
</ScrollView>
|
|
|
|
{/* Save Button */}
|
|
<View className="p-6 bg-white dark:bg-gray-900 border-t border-gray-100 dark:border-gray-800" style={{ paddingBottom: Math.max(insets.bottom, 24) }}>
|
|
<TouchableOpacity
|
|
className="w-full bg-blue-600 py-4 rounded-2xl shadow-lg active:bg-blue-700"
|
|
onPress={handleSave}
|
|
>
|
|
<Text className="text-white text-center font-bold text-lg">Save Transaction</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
</KeyboardAvoidingView>
|
|
</View>
|
|
);
|
|
}
|