import React, { useState } from 'react'; import { View, Text, TextInput, ScrollView, TouchableOpacity, Image, ActivityIndicator, StyleSheet, Alert, } from 'react-native'; import * as ImagePicker from 'expo-image-picker'; import { SafeAreaView } from 'react-native-safe-area-context'; import { router, useLocalSearchParams } from 'expo-router'; import { MaterialIcons } from '@expo/vector-icons'; import { DatePickerModal } from '../../src/components/ui/DatePicker'; import { useHouseholdStore } from '../../src/hooks/useHousehold'; import { updateItem, deleteItem, updateItemQuantity } from '../../src/services/items'; import { QuantityControl } from '../../src/components/ui/QuantityControl'; import { COLORS, CATEGORY_LABELS, STORAGE_LOCATIONS } from '../../src/constants'; import { ChipSelectInput } from '../../src/components/ui/ChipSelectInput'; import { useCustomOptions } from '../../src/hooks/useCustomOptions'; import { formatDate, isExpired, isExpiringSoon } from '../../src/utils'; import Toast from 'react-native-toast-message'; export default function ItemDetailModal() { const { itemId } = useLocalSearchParams<{ itemId: string }>(); const household = useHouseholdStore((s) => s.household); const items = useHouseholdStore((s) => s.items); const item = items.find((i) => i.id === itemId); const [editing, setEditing] = useState(false); const [saving, setSaving] = useState(false); const [newPhotoUri, setNewPhotoUri] = useState(null); const [showDatePicker, setShowDatePicker] = useState(false); const [name, setName] = useState(item?.name ?? ''); const [description, setDescription] = useState(item?.description ?? ''); const [storageLocation, setStorageLocation] = useState(item?.storageLocation ?? ''); const [shoppingLocation, setShoppingLocation] = useState(item?.shoppingLocation ?? ''); const [price, setPrice] = useState(item?.price != null ? String(item.price) : ''); const [minStock, setMinStock] = useState(String(item?.minStockThreshold ?? 0)); const [expiryDate, setExpiryDate] = useState(item?.expiryDate ?? null); const { options: locationOptions, customOptions: customLocations, addOption: addLocation, removeOption: removeLocation } = useCustomOptions( 'houseorg_custom_locations', STORAGE_LOCATIONS ); if (!item || !household) { return ( Artikel nicht gefunden. ); } const pickPhoto = () => { Alert.alert('Foto', '', [ { text: 'Kamera', onPress: async () => { const result = await ImagePicker.launchCameraAsync({ quality: 0.8, allowsEditing: true, aspect: [4, 3] }); if (!result.canceled) setNewPhotoUri(result.assets[0].uri); }, }, { text: 'Galerie', onPress: async () => { const result = await ImagePicker.launchImageLibraryAsync({ quality: 0.8, allowsEditing: true, aspect: [4, 3] }); if (!result.canceled) setNewPhotoUri(result.assets[0].uri); }, }, { text: 'Abbrechen', style: 'cancel' }, ]); }; const handleSave = async () => { setSaving(true); try { await updateItem(household.id, item.id, { name: name.trim(), description: description.trim(), storageLocation: storageLocation.trim(), shoppingLocation: shoppingLocation.trim(), price: price ? parseFloat(price) : null, minStockThreshold: parseFloat(minStock) || 0, expiryDate, ...(newPhotoUri ? { photoUri: newPhotoUri } : {}), }); setNewPhotoUri(null); setEditing(false); Toast.show({ type: 'success', text1: 'Gespeichert' }); } catch { Toast.show({ type: 'error', text1: 'Fehler beim Speichern' }); } finally { setSaving(false); } }; const handleDelete = () => { Alert.alert('Artikel löschen', `Möchtest du "${item.name}" wirklich löschen?`, [ { text: 'Abbrechen', style: 'cancel' }, { text: 'Löschen', style: 'destructive', onPress: async () => { try { await deleteItem(household.id, item.id); router.back(); } catch { Toast.show({ type: 'error', text1: 'Fehler beim Löschen' }); } }, }, ]); }; const handleQuantityChange = async (qty: number) => { try { await updateItemQuantity(household.id, item.id, qty); } catch { Toast.show({ type: 'error', text1: 'Fehler beim Speichern' }); } }; const expired = isExpired(item.expiryDate); const expiringSoon = isExpiringSoon(item.expiryDate); return ( <> {editing ? ( {(newPhotoUri ?? item.photoUrl) ? ( <> Foto ändern ) : ( Foto hinzufügen )} ) : ( item.photoUrl && )} {editing ? ( ) : ( {item.name} )} {CATEGORY_LABELS[item.category]} (editing ? handleSave() : setEditing(true))} disabled={saving}> {saving ? ( ) : ( )} Bestand {item.onShoppingList && ( Auf der Einkaufsliste )} {(expiringSoon || expired) && ( {expired ? 'Abgelaufen!' : `MHD läuft in ≤ 3 Tagen ab`} )} {editing && ( )} {editing && ( )} {editing && ( )} {editing && ( )} {editing && ( )} {editing && ( setShowDatePicker(true)} style={styles.datePicker}> {formatDate(expiryDate) || 'Datum wählen'} )} {showDatePicker && ( setShowDatePicker(false)} /> )} Artikel löschen ); } function DetailRow({ label, value, children, last, }: { label: string; value?: string; children?: React.ReactNode; last?: boolean; }) { return ( {label} {children ?? {value}} ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: COLORS.white }, content: { paddingBottom: 48 }, center: { flex: 1, justifyContent: 'center', alignItems: 'center' }, photo: { width: '100%', height: 220, resizeMode: 'cover' }, photoEditContainer: { width: '100%', height: 220 }, photoEditOverlay: { position: 'absolute', bottom: 0, left: 0, right: 0, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: 6, backgroundColor: 'rgba(0,0,0,0.45)', paddingVertical: 10, }, photoEditText: { color: COLORS.white, fontSize: 14, fontWeight: '600' }, photoPlaceholder: { width: '100%', height: 220, backgroundColor: COLORS.surface, justifyContent: 'center', alignItems: 'center', gap: 8, }, photoPlaceholderText: { color: COLORS.primary, fontSize: 14, fontWeight: '600' }, headerRow: { flexDirection: 'row', alignItems: 'flex-start', padding: 20, gap: 12 }, headerInfo: { flex: 1 }, title: { fontSize: 24, fontWeight: '700', color: COLORS.text }, titleInput: { fontSize: 24, fontWeight: '700', color: COLORS.text, borderBottomWidth: 2, borderBottomColor: COLORS.primary }, category: { fontSize: 14, color: COLORS.textSecondary, marginTop: 4 }, quantitySection: { paddingHorizontal: 20, paddingBottom: 16, gap: 8 }, sectionLabel: { fontSize: 12, fontWeight: '600', color: COLORS.textSecondary, textTransform: 'uppercase', letterSpacing: 0.4 }, onListHint: { fontSize: 12, color: COLORS.warning, fontWeight: '500' }, mhdAlert: { flexDirection: 'row', alignItems: 'center', gap: 8, marginHorizontal: 20, marginBottom: 12, padding: 12, borderRadius: 10 }, mhdAlertWarn: { backgroundColor: '#FFF3CD' }, mhdAlertExpired: { backgroundColor: '#F8D7DA' }, mhdAlertText: { fontSize: 14, fontWeight: '500', color: COLORS.text }, detailsCard: { marginHorizontal: 16, borderRadius: 14, overflow: 'hidden', borderWidth: 1, borderColor: COLORS.border }, detailRow: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', padding: 14, gap: 12 }, detailRowBorder: { borderBottomWidth: 1, borderBottomColor: COLORS.border }, detailLabel: { fontSize: 14, color: COLORS.textSecondary, fontWeight: '500', minWidth: 100 }, detailValue: { fontSize: 14, color: COLORS.text, flex: 1, textAlign: 'right' }, editInput: { fontSize: 14, color: COLORS.text, flex: 1, textAlign: 'right', borderBottomWidth: 1, borderBottomColor: COLORS.primary }, datePicker: { flexDirection: 'row', alignItems: 'center', gap: 6 }, datePickerText: { fontSize: 14, color: COLORS.primary }, deleteBtn: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: 8, marginTop: 32, marginHorizontal: 16, padding: 14, borderRadius: 12, borderWidth: 1.5, borderColor: COLORS.danger }, deleteBtnText: { color: COLORS.danger, fontSize: 15, fontWeight: '600' }, });