fristy/src/modules/contracts/screens/AddContractScreen.tsx

192 lines
9.9 KiB
TypeScript

import React, { useState } from 'react';
import { View, Text, StyleSheet, ScrollView, TouchableOpacity, TextInput, Switch, Platform } from 'react-native';
import { Contract, ContractCategory } from '../../../shared/types';
import { DatePickerInput } from '../../../shared/components/DatePickerInput';
interface AddContractScreenProps {
onClose: () => void;
onSave: (contract: Omit<Contract, 'id'>) => void;
}
export const AddContractScreen: React.FC<AddContractScreenProps> = ({ onClose, onSave }) => {
const [name, setName] = useState('');
const [provider, setProvider] = useState('');
const [category, setCategory] = useState<ContractCategory>('other');
const [amount, setAmount] = useState('0');
const [billingCycle, setBillingCycle] = useState<'monthly' | 'quarterly' | 'yearly'>('monthly');
const [startDate, setStartDate] = useState('');
const [endDate, setEndDate] = useState('');
const [autoRenewal, setAutoRenewal] = useState(true);
const [cancellationPeriod, setCancellationPeriod] = useState('');
const [notes, setNotes] = useState('');
const getCategoryIcon = (cat: string) => {
const icons: Record<string, string> = {
internet: '🌐',
mobile: '📱',
streaming: '📺',
utilities: '💡',
insurance: '🛡️',
other: '📄',
};
return icons[cat] || '📄';
};
const handleSave = () => {
if (!name.trim() || !provider.trim()) {
alert('Bitte fülle mindestens Name und Anbieter aus!');
return;
}
const newContract: Omit<Contract, 'id'> = {
name: name.trim(),
provider: provider.trim(),
category,
amount: parseFloat(amount) || 0,
currency: 'EUR',
billingCycle,
startDate: startDate || new Date().toISOString().split('T')[0],
endDate: endDate || undefined,
autoRenewal,
cancellationPeriod: cancellationPeriod || undefined,
notes: notes || undefined,
};
onSave(newContract);
};
return (
<View style={styles.container}>
<View style={styles.header}>
<TouchableOpacity onPress={onClose} style={styles.closeButton}>
<Text style={styles.closeIcon}></Text>
</TouchableOpacity>
<Text style={styles.headerTitle}>Neuer Vertrag</Text>
<View style={styles.placeholder} />
</View>
<ScrollView style={styles.content} contentContainerStyle={styles.scrollContent}>
<View style={styles.card}>
<Text style={styles.cardTitle}>Kategorie wählen</Text>
<View style={styles.categoryGrid}>
{(['internet', 'mobile', 'streaming', 'utilities', 'insurance', 'other'] as ContractCategory[]).map((cat) => (
<TouchableOpacity
key={cat}
style={[styles.categoryCard, category === cat && styles.categoryCardActive]}
onPress={() => setCategory(cat)}
>
<Text style={styles.categoryIcon}>{getCategoryIcon(cat)}</Text>
<Text style={styles.categoryLabel}>
{cat === 'internet' ? 'Internet' :
cat === 'mobile' ? 'Mobilfunk' :
cat === 'streaming' ? 'Streaming' :
cat === 'utilities' ? 'Versorgung' :
cat === 'insurance' ? 'Versicherung' : 'Sonstiges'}
</Text>
</TouchableOpacity>
))}
</View>
</View>
<View style={styles.card}>
<Text style={styles.cardTitle}>Grunddaten</Text>
<View style={styles.inputGroup}>
<Text style={styles.inputLabel}>Vertragsname *</Text>
<TextInput style={styles.textInput} value={name} onChangeText={setName} placeholder="z.B. Vodafone DSL" placeholderTextColor="#C7C7CC" />
</View>
<View style={styles.inputGroup}>
<Text style={styles.inputLabel}>Anbieter *</Text>
<TextInput style={styles.textInput} value={provider} onChangeText={setProvider} placeholder="z.B. Vodafone" placeholderTextColor="#C7C7CC" />
</View>
</View>
<View style={styles.card}>
<Text style={styles.cardTitle}>Kosten</Text>
<View style={styles.inputGroup}>
<Text style={styles.inputLabel}>Betrag (EUR)</Text>
<TextInput style={styles.textInput} value={amount} onChangeText={setAmount} placeholder="0.00" keyboardType="decimal-pad" placeholderTextColor="#C7C7CC" />
</View>
<View style={styles.inputGroup}>
<Text style={styles.inputLabel}>Zahlungsrhythmus</Text>
<View style={styles.cycleButtons}>
{[
{ value: 'monthly', label: 'Monatlich' },
{ value: 'quarterly', label: 'Vierteljährlich' },
{ value: 'yearly', label: 'Jährlich' }
].map((cycle) => (
<TouchableOpacity key={cycle.value} style={[styles.cycleButton, billingCycle === cycle.value && styles.cycleButtonActive]} onPress={() => setBillingCycle(cycle.value as any)}>
<Text style={[styles.cycleButtonText, billingCycle === cycle.value && styles.cycleButtonTextActive]}>{cycle.label}</Text>
</TouchableOpacity>
))}
</View>
</View>
</View>
<View style={styles.card}>
<Text style={styles.cardTitle}>Vertragslaufzeit</Text>
<View style={styles.inputGroup}>
<Text style={styles.inputLabel}>Startdatum</Text>
<DatePickerInput value={startDate} onChange={setStartDate} placeholder="Startdatum wählen" />
</View>
<View style={styles.inputGroup}>
<Text style={styles.inputLabel}>Enddatum (optional)</Text>
<DatePickerInput value={endDate} onChange={setEndDate} placeholder="Enddatum wählen (optional)" />
</View>
<View style={styles.switchRow}>
<Text style={styles.inputLabel}>Automatische Verlängerung</Text>
<Switch value={autoRenewal} onValueChange={setAutoRenewal} trackColor={{ false: '#D1D1D6', true: '#34C75980' }} thumbColor={autoRenewal ? '#34C759' : '#F4F3F4'} />
</View>
<View style={styles.inputGroup}>
<Text style={styles.inputLabel}>Kündigungsfrist (optional)</Text>
<TextInput style={styles.textInput} value={cancellationPeriod} onChangeText={setCancellationPeriod} placeholder="z.B. 3 Monate" placeholderTextColor="#C7C7CC" />
</View>
</View>
<View style={styles.card}>
<Text style={styles.cardTitle}>Notizen (optional)</Text>
<TextInput style={styles.notesInput} value={notes} onChangeText={setNotes} placeholder="Füge zusätzliche Informationen hinzu..." placeholderTextColor="#C7C7CC" multiline numberOfLines={4} />
</View>
<View style={styles.actionButtons}>
<TouchableOpacity style={styles.cancelButton} onPress={onClose}><Text style={styles.cancelButtonText}>Abbrechen</Text></TouchableOpacity>
<TouchableOpacity style={styles.saveButton} onPress={handleSave}><Text style={styles.saveButtonText}>Speichern</Text></TouchableOpacity>
</View>
<View style={{ height: 100 }} />
</ScrollView>
</View>
);
};
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: '#F2F2F7' },
header: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', paddingTop: 60, paddingHorizontal: 20, paddingBottom: 16, backgroundColor: '#F2F2F7' },
closeButton: { width: 40, height: 40, borderRadius: 20, backgroundColor: 'rgba(255, 255, 255, 0.7)', alignItems: 'center', justifyContent: 'center' },
closeIcon: { fontSize: 24, color: '#007AFF', fontWeight: '300' as any },
headerTitle: { fontSize: 17, fontWeight: '600' as any, color: '#000000' },
placeholder: { width: 40 },
content: { flex: 1 },
scrollContent: { paddingHorizontal: 20 },
card: { backgroundColor: Platform.OS === 'ios' ? 'rgba(255, 255, 255, 0.7)' : '#FFFFFF', borderRadius: 20, padding: 20, marginBottom: 16, borderWidth: 1, borderColor: 'rgba(255, 255, 255, 0.5)', shadowColor: '#000', shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.1, shadowRadius: 12, elevation: 4 },
cardTitle: { fontSize: 20, fontWeight: 'bold', color: '#000000', marginBottom: 16 },
categoryGrid: { flexDirection: 'row', flexWrap: 'wrap', gap: 12 },
categoryCard: { width: '30%', aspectRatio: 1, backgroundColor: '#F2F2F7', borderRadius: 16, alignItems: 'center', justifyContent: 'center', padding: 12 },
categoryCardActive: { backgroundColor: '#007AFF20', borderWidth: 2, borderColor: '#007AFF' },
categoryIcon: { fontSize: 36, marginBottom: 8 },
categoryLabel: { fontSize: 12, color: '#000000', textAlign: 'center', fontWeight: '600' as any },
inputGroup: { marginBottom: 16 },
inputLabel: { fontSize: 15, color: '#000000', marginBottom: 8, fontWeight: '600' as any },
textInput: { backgroundColor: '#F2F2F7', borderRadius: 12, padding: 14, fontSize: 17, color: '#000000', borderWidth: 1, borderColor: 'transparent' },
cycleButtons: { gap: 8 },
cycleButton: { backgroundColor: '#F2F2F7', padding: 14, borderRadius: 12, alignItems: 'center' },
cycleButtonActive: { backgroundColor: '#007AFF' },
cycleButtonText: { fontSize: 17, color: '#000000', fontWeight: '600' as any },
cycleButtonTextActive: { color: '#FFFFFF' },
switchRow: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 },
notesInput: { backgroundColor: '#F2F2F7', borderRadius: 12, padding: 14, fontSize: 15, color: '#000000', minHeight: 100, textAlignVertical: 'top' },
actionButtons: { flexDirection: 'row', gap: 12, marginTop: 8 },
cancelButton: { flex: 1, backgroundColor: '#F2F2F7', padding: 16, borderRadius: 12, alignItems: 'center' },
cancelButtonText: { fontSize: 17, fontWeight: '600' as any, color: '#000000' },
saveButton: { flex: 1, backgroundColor: '#007AFF', padding: 16, borderRadius: 12, alignItems: 'center' },
saveButtonText: { fontSize: 17, fontWeight: '600' as any, color: '#FFFFFF' },
});