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 { createCustomer, Customer, fetchCustomers } from '@/src/lib/api'; import { useAuth } from '@/src/providers/auth-provider'; const PRIMARY = '#69c350'; export default function CustomersScreen() { const { token } = useAuth(); const router = useRouter(); 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 [numberInput, setNumberInput] = useState(''); const [notesInput, setNotesInput] = useState(''); const filtered = useMemo(() => { const terms = search.trim().toLowerCase().split(/\s+/).filter(Boolean); return customers.filter((customer) => { if (!showArchived && customer.archived) return false; if (terms.length === 0) return true; const haystack = [customer.name, customer.customerNumber, customer.notes] .map((value) => String(value || '').toLowerCase()) .join(' '); return terms.every((term) => haystack.includes(term)); }); }, [customers, search, showArchived]); const load = useCallback(async (showSpinner = true) => { if (!token) return; if (showSpinner) setLoading(true); setError(null); try { const rows = await fetchCustomers(token, true); setCustomers(rows); } catch (err) { setError(err instanceof Error ? err.message : 'Kunden 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(''); setNumberInput(''); setNotesInput(''); } async function onCreateCustomer() { if (!token) return; const name = nameInput.trim(); if (!name) { setCreateError('Bitte einen Namen eingeben.'); return; } setSaving(true); setCreateError(null); try { await createCustomer(token, { name, customerNumber: numberInput.trim() || null, notes: notesInput.trim() || null, }); closeCreateModal(); await load(false); } catch (err) { setCreateError(err instanceof Error ? err.message : 'Kunde konnte nicht erstellt werden.'); } finally { setSaving(false); } } return ( setShowArchived((prev) => !prev)}> Abgeschlossene anzeigen }> {error ? {error} : null} {loading ? ( Kunden werden geladen... ) : null} {!loading && filtered.length === 0 ? Keine Kunden gefunden. : null} {!loading && filtered.map((customer) => ( [styles.row, pressed ? styles.rowPressed : null]} onPress={() => router.push(`/more/customer/${customer.id}`)}> {customer.name} {customer.archived ? Abgeschlossen : null} {customer.customerNumber ? ( Nr.: {customer.customerNumber} ) : null} {customer.notes ? {String(customer.notes)} : null} ))} setCreateOpen(true)}> + Neuer Kunde {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', }, 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, }, });