import { useState, useEffect } from 'react'; import { View, Text, TextInput, TouchableOpacity, ScrollView, Alert, ActivityIndicator, FlatList, Modal } from 'react-native'; import { router, useLocalSearchParams } from 'expo-router'; import { useQuery, useQueryClient } from '@tanstack/react-query'; import { api } from '../../../services/api'; const METHODS = ['CASH', 'GCASH', 'MAYA', 'BANK']; export default function RecordPaymentScreen() { const params = useLocalSearchParams<{ prefillClientId?: string; prefillName?: string; prefillAccountNumber?: string }>(); const qc = useQueryClient(); const [search, setSearch] = useState(''); const [showPicker, setShowPicker] = useState(false); const [client, setClient] = useState( params.prefillClientId ? { id: params.prefillClientId, firstName: params.prefillName?.split(' ')[0], lastName: params.prefillName?.split(' ').slice(1).join(' '), accountNumber: params.prefillAccountNumber } : null ); const [amount, setAmount] = useState(''); const [method, setMethod] = useState('CASH'); const [reference, setReference] = useState(''); const [notes, setNotes] = useState(''); const [loading, setLoading] = useState(false); // Debounced client search const [debouncedSearch, setDebouncedSearch] = useState(''); useEffect(() => { const t = setTimeout(() => setDebouncedSearch(search), 400); return () => clearTimeout(t); }, [search]); const { data: searchResults, isFetching: searching } = useQuery({ queryKey: ['client-search', debouncedSearch], queryFn: () => api.get(`/api/v1/clients?search=${debouncedSearch}&limit=8`).then(r => r.data?.data ?? r.data ?? []), enabled: debouncedSearch.trim().length >= 2, }); const submit = async () => { if (!client) return Alert.alert('Required', 'Select a client first.'); if (!amount || isNaN(Number(amount)) || Number(amount) <= 0) return Alert.alert('Required', 'Enter a valid amount.'); setLoading(true); try { await api.post('/api/v1/payments', { clientId: client.id, amount: Number(amount), paymentMethod: method, referenceNumber: reference || undefined, notes: notes || undefined, paymentDate: new Date().toISOString(), }); // Invalidate relevant queries qc.invalidateQueries({ queryKey: ['payments'] }); qc.invalidateQueries({ queryKey: ['client-payments', client.id] }); qc.invalidateQueries({ queryKey: ['dashboard'] }); Alert.alert('✅ Payment Recorded', `₱${Number(amount).toLocaleString()} from ${client.firstName} ${client.lastName}`, [ { text: 'Done', onPress: () => router.back() }, { text: 'Record Another', onPress: () => { setClient(null); setAmount(''); setReference(''); setNotes(''); setSearch(''); } }, ]); } catch (e: any) { Alert.alert('Error', e?.response?.data?.message ?? 'Payment failed. Try again.'); } finally { setLoading(false); } }; return ( router.back()} className="mr-3 p-1"> Record Payment {/* Client selector */} Client * {client ? ( {client.firstName} {client.lastName} {client.accountNumber} { setClient(null); setSearch(''); }} className="p-2"> Change ) : ( {searching && } {debouncedSearch.trim().length >= 2 && ( {(searchResults ?? []).length === 0 && !searching && ( No clients found )} {(searchResults ?? []).map((c: any) => ( { setClient(c); setSearch(''); }} > {c.firstName} {c.lastName} {c.accountNumber} ))} )} )} {/* Amount */} Amount (₱) * {/* Payment method */} Payment Method * {METHODS.map(m => ( setMethod(m)} className={`rounded-xl px-5 py-2.5 mr-2 mb-2 border ${method === m ? 'bg-primary border-primary' : 'bg-white border-gray-200'}`} > {m} ))} {/* Reference (for non-cash) */} {method !== 'CASH' && ( <> Reference # * )} {/* Notes */} Notes (optional) {/* Submit */} {loading ? : Submit Payment {amount ? `· ₱${Number(amount || 0).toLocaleString()}` : ''} } ); }