import { useCallback, useEffect, useMemo, useState } from 'react'; import { ActivityIndicator, KeyboardAvoidingView, Modal, Platform, Pressable, RefreshControl, ScrollView, StyleSheet, Text, TextInput, View, } from 'react-native'; import { useRouter } from 'expo-router'; import { createPlant, Customer, fetchCustomers, fetchPlants, Plant } from '@/src/lib/api'; import { useAuth } from '@/src/providers/auth-provider'; const PRIMARY = '#69c350'; function getCustomerName(raw: Plant['customer']): string | null { if (!raw) return null; if (typeof raw === 'object') return raw.name ? String(raw.name) : null; return String(raw); } export default function PlantsScreen() { const { token } = useAuth(); const router = useRouter(); const [plants, setPlants] = useState([]); const [customers, setCustomers] = useState([]); const [search, setSearch] = useState(''); const [showArchived, setShowArchived] = useState(false); const [loading, setLoading] = useState(true); const [refreshing, setRefreshing] = useState(false); const [error, setError] = useState(null); const [createOpen, setCreateOpen] = useState(false); const [saving, setSaving] = useState(false); const [createError, setCreateError] = useState(null); const [nameInput, setNameInput] = useState(''); const [descriptionInput, setDescriptionInput] = useState(''); const [selectedCustomerId, setSelectedCustomerId] = useState(null); const [pickerMode, setPickerMode] = useState<'customer' | null>(null); const [customerSearch, setCustomerSearch] = useState(''); const filtered = useMemo(() => { const terms = search.trim().toLowerCase().split(/\s+/).filter(Boolean); return plants.filter((plant) => { if (!showArchived && plant.archived) return false; if (terms.length === 0) return true; const haystack = [plant.name, plant.description, getCustomerName(plant.customer)] .map((value) => String(value || '').toLowerCase()) .join(' '); return terms.every((term) => haystack.includes(term)); }); }, [plants, search, showArchived]); const filteredCustomerOptions = useMemo(() => { const terms = customerSearch.trim().toLowerCase().split(/\s+/).filter(Boolean); return customers .filter((customer) => !customer.archived) .filter((customer) => { if (terms.length === 0) return true; const haystack = [customer.name, customer.customerNumber] .map((value) => String(value || '').toLowerCase()) .join(' '); return terms.every((term) => haystack.includes(term)); }); }, [customerSearch, customers]); const selectedCustomerLabel = useMemo(() => { if (!selectedCustomerId) return 'Kunde auswählen (optional)'; const customer = customers.find((item) => Number(item.id) === selectedCustomerId); return customer ? `${customer.name}${customer.customerNumber ? ` · ${customer.customerNumber}` : ''}` : `ID ${selectedCustomerId}`; }, [customers, selectedCustomerId]); const load = useCallback(async (showSpinner = true) => { if (!token) return; if (showSpinner) setLoading(true); setError(null); try { const [plantRows, customerRows] = await Promise.all([fetchPlants(token, true), fetchCustomers(token, true)]); setPlants(plantRows); setCustomers(customerRows); } catch (err) { setError(err instanceof Error ? err.message : 'Objekte konnten nicht geladen werden.'); } finally { setLoading(false); setRefreshing(false); } }, [token]); useEffect(() => { if (!token) return; void load(true); }, [load, token]); async function onRefresh() { setRefreshing(true); await load(false); } function closeCreateModal() { setCreateOpen(false); setCreateError(null); setNameInput(''); setDescriptionInput(''); setSelectedCustomerId(null); setCustomerSearch(''); setPickerMode(null); } async function onCreatePlant() { if (!token) return; const name = nameInput.trim(); if (!name) { setCreateError('Bitte einen Namen eingeben.'); return; } setSaving(true); setCreateError(null); try { await createPlant(token, { name, customer: selectedCustomerId, description: descriptionInput.trim() || null, }); closeCreateModal(); await load(false); } catch (err) { setCreateError(err instanceof Error ? err.message : 'Objekt konnte nicht erstellt werden.'); } finally { setSaving(false); } } return ( setShowArchived((prev) => !prev)}> Abgeschlossene anzeigen }> {error ? {error} : null} {loading ? ( Objekte werden geladen... ) : null} {!loading && filtered.length === 0 ? Keine Objekte gefunden. : null} {!loading && filtered.map((plant) => ( [styles.row, pressed ? styles.rowPressed : null]} onPress={() => router.push(`/more/plant/${plant.id}`)}> {plant.name} {plant.archived ? Abgeschlossen : null} {getCustomerName(plant.customer) ? ( Kunde: {getCustomerName(plant.customer)} ) : null} {plant.description ? {String(plant.description)} : null} ))} setCreateOpen(true)}> + Neues Objekt setPickerMode('customer')}> {selectedCustomerLabel} {pickerMode === 'customer' ? ( Kunde auswählen { setSelectedCustomerId(null); setPickerMode(null); }}> Keine Auswahl {filteredCustomerOptions.map((customer) => ( { setSelectedCustomerId(Number(customer.id)); setPickerMode(null); }}> {customer.name} {customer.customerNumber ? `Nr. ${customer.customerNumber}` : `ID ${customer.id}`} ))} ) : null} {createError ? {createError} : null} Abbrechen {saving ? 'Speichere...' : 'Anlegen'} ); } const styles = StyleSheet.create({ screen: { flex: 1, backgroundColor: '#ffffff' }, searchWrap: { paddingHorizontal: 16, paddingTop: 12, paddingBottom: 10, borderBottomWidth: 1, borderBottomColor: '#e5e7eb', backgroundColor: '#ffffff', gap: 8, }, searchInput: { borderWidth: 1, borderColor: '#d1d5db', borderRadius: 10, paddingHorizontal: 12, paddingVertical: 10, fontSize: 15, color: '#111827', backgroundColor: '#ffffff', }, list: { flex: 1, backgroundColor: '#ffffff' }, listContent: { paddingBottom: 96 }, row: { paddingHorizontal: 16, paddingVertical: 14, borderBottomWidth: 1, borderBottomColor: '#e5e7eb', backgroundColor: '#ffffff', }, rowPressed: { backgroundColor: '#f3f4f6' }, rowHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', gap: 8, }, rowTitle: { flex: 1, color: '#111827', fontSize: 15, fontWeight: '600' }, rowSubtitle: { color: '#6b7280', fontSize: 13, marginTop: 2 }, badge: { color: '#3d7a30', fontSize: 11, fontWeight: '600', backgroundColor: '#eff9ea', borderRadius: 999, paddingHorizontal: 8, paddingVertical: 3, overflow: 'hidden', }, toggleButton: { alignSelf: 'flex-start', borderWidth: 1, borderColor: '#d1d5db', borderRadius: 999, paddingHorizontal: 10, paddingVertical: 6, backgroundColor: '#ffffff', }, toggleButtonActive: { borderColor: PRIMARY, backgroundColor: '#eff9ea' }, toggleButtonText: { color: '#374151', fontSize: 12, fontWeight: '600' }, toggleButtonTextActive: { color: '#3d7a30' }, loadingBox: { paddingVertical: 20, alignItems: 'center', gap: 8 }, loadingText: { color: '#6b7280' }, empty: { color: '#6b7280', textAlign: 'center', paddingVertical: 20 }, error: { color: '#dc2626', fontSize: 13, paddingHorizontal: 16, paddingTop: 10 }, fab: { position: 'absolute', right: 18, bottom: 20, width: 56, height: 56, borderRadius: 28, backgroundColor: PRIMARY, alignItems: 'center', justifyContent: 'center', shadowColor: '#111827', shadowOpacity: 0.25, shadowRadius: 8, shadowOffset: { width: 0, height: 4 }, elevation: 5, }, fabText: { color: '#ffffff', fontSize: 30, lineHeight: 30, marginTop: -2 }, modalOverlay: { flex: 1, backgroundColor: 'rgba(17, 24, 39, 0.45)', justifyContent: 'center', padding: 20, }, modalKeyboardWrap: { width: '100%' }, modalCard: { backgroundColor: '#ffffff', borderRadius: 14, padding: 16, gap: 10 }, modalTitle: { color: '#111827', fontSize: 18, fontWeight: '700' }, multilineInput: { minHeight: 92, textAlignVertical: 'top' }, selectButton: { borderWidth: 1, borderColor: '#d1d5db', borderRadius: 10, paddingHorizontal: 12, paddingVertical: 10, backgroundColor: '#ffffff', }, selectButtonText: { color: '#111827', fontSize: 15 }, inlinePickerBox: { borderWidth: 1, borderColor: '#e5e7eb', borderRadius: 10, padding: 10, gap: 8, backgroundColor: '#fafafa', }, inlinePickerTitle: { color: '#111827', fontSize: 14, fontWeight: '700' }, pickerList: { maxHeight: 220 }, pickerRow: { borderWidth: 1, borderColor: '#e5e7eb', borderRadius: 10, paddingHorizontal: 12, paddingVertical: 10, marginBottom: 8, backgroundColor: '#ffffff', }, pickerRowTitle: { color: '#111827', fontSize: 14, fontWeight: '600' }, pickerRowMeta: { color: '#6b7280', fontSize: 12, marginTop: 2 }, modalActions: { flexDirection: 'row', justifyContent: 'flex-end', gap: 8, marginTop: 4 }, secondaryButton: { borderWidth: 1, borderColor: '#d1d5db', borderRadius: 10, minHeight: 40, paddingHorizontal: 14, alignItems: 'center', justifyContent: 'center', }, secondaryButtonText: { color: '#374151', fontWeight: '600' }, primaryButton: { borderRadius: 10, minHeight: 40, paddingHorizontal: 14, alignItems: 'center', justifyContent: 'center', backgroundColor: PRIMARY, }, primaryButtonText: { color: '#ffffff', fontWeight: '700' }, buttonDisabled: { opacity: 0.6 }, });