import React, { useEffect, useMemo, useState } from "react"; import { ActivityIndicator, Pressable, TextInput, StyleSheet, View, } from "react-native"; import { useSirouRouter } from "@sirou/react-native"; import { useColorScheme } from "nativewind"; import { useLocalSearchParams } from "expo-router"; import { api } from "@/lib/api"; import { AppRoutes } from "@/lib/routes"; import { toast } from "@/lib/toast-store"; import { ScreenWrapper } from "@/components/ScreenWrapper"; import { FormFlow } from "@/components/FormFlow"; import { PickerModal, SelectOption } from "@/components/PickerModal"; import { CalendarGrid } from "@/components/CalendarGrid"; import { CustomerPicker } from "@/components/CustomerPicker"; import { Text } from "@/components/ui/text"; import { ChevronDown, Plus, Trash2 } from "@/lib/icons"; type Item = { id: number; description: string; quantity: string; unitPrice: string }; const S = StyleSheet.create({ input: { paddingHorizontal: 12, paddingVertical: 12, fontSize: 12, fontWeight: "500", borderRadius: 6, borderWidth: 1, textAlignVertical: "center", }, inputCenter: { paddingHorizontal: 12, paddingVertical: 10, fontSize: 14, fontWeight: "500", borderRadius: 6, borderWidth: 1, textAlign: "center", textAlignVertical: "center", }, }); function useInputColors() { const { colorScheme } = useColorScheme(); const dark = colorScheme === "dark"; return { bg: dark ? "rgba(30,30,30,0.8)" : "rgba(241,245,249,0.2)", border: dark ? "rgba(255,255,255,0.08)" : "rgba(203,213,225,0.6)", text: dark ? "#f1f5f9" : "#0f172a", placeholder: "rgba(100,116,139,0.45)", }; } function Field({ label, value, onChangeText, placeholder, numeric = false, center = false, flex, multiline = false, keyboardType, }: { label: string; value: string; onChangeText: (v: string) => void; placeholder: string; numeric?: boolean; center?: boolean; flex?: number; multiline?: boolean; keyboardType?: "default" | "numeric" | "email-address" | "phone-pad"; }) { const c = useInputColors(); return ( {label} ); } function PickerField({ label, value, onPress, }: { label: string; value: string; onPress: () => void; }) { const c = useInputColors(); return ( {label} {value} ); } const CURRENCIES = ["ETB", "USD", "EUR", "GBP", "KES", "ZAR"]; const CHANNELS = ["EMAIL", "PHONE"]; const STEPS = [ { key: "details", label: "Details" }, { key: "customer", label: "Customer" }, { key: "schedule", label: "Schedule" }, { key: "items", label: "Items" }, { key: "paymentMethod", label: "Payment" }, { key: "summary", label: "Summary" }, ]; function formatDate(d: string | null | undefined): string { if (!d) return ""; try { return new Date(d).toISOString().split("T")[0]; } catch { return ""; } } export default function EditPaymentRequestScreen() { const nav = useSirouRouter(); const { id } = useLocalSearchParams<{ id: string }>(); const [step, setStep] = useState(0); const [submitting, setSubmitting] = useState(false); const [loadingData, setLoadingData] = useState(true); const [paymentRequestNumber, setPaymentRequestNumber] = useState(""); const [description, setDescription] = useState(""); const [customerName, setCustomerName] = useState(""); const [customerEmail, setCustomerEmail] = useState(""); const [customerId, setCustomerId] = useState(""); const [channel, setChannel] = useState("EMAIL"); const [recipient, setRecipient] = useState(""); const [amount, setAmount] = useState(""); const [currency, setCurrency] = useState("ETB"); const [issueDate, setIssueDate] = useState( new Date().toISOString().split("T")[0], ); const [dueDate, setDueDate] = useState(""); const [companyPaymentMethodId, setCompanyPaymentMethodId] = useState(""); const [paymentMethods, setPaymentMethods] = useState([]); const [loadingPaymentMethods, setLoadingPaymentMethods] = useState(false); const [items, setItems] = useState([ { id: 1, description: "", quantity: "1", unitPrice: "" }, ]); const c = useInputColors(); const [showCurrency, setShowCurrency] = useState(false); const [showIssueDate, setShowIssueDate] = useState(false); const [showDueDate, setShowDueDate] = useState(false); const [showChannel, setShowChannel] = useState(false); const [showPaymentMethod, setShowPaymentMethod] = useState(false); useEffect(() => { (async () => { try { setLoadingData(true); const reqId = Array.isArray(id) ? id[0] : id; if (!reqId) return; const data = await api.paymentRequests.getById({ params: { id: reqId } }); setPaymentRequestNumber(data.paymentRequestNumber || ""); setDescription(data.description || ""); setCustomerName(data.customerName || ""); setCustomerEmail(data.customerEmail || ""); setCustomerId(data.customerId || ""); setChannel(data.channel || "EMAIL"); setRecipient(data.recipient || data.customerEmail || ""); setAmount(data.amount != null ? String(data.amount) : ""); setCurrency(data.currency || "ETB"); setIssueDate(formatDate(data.issueDate) || new Date().toISOString().split("T")[0]); setDueDate(formatDate(data.dueDate)); setCompanyPaymentMethodId(data.companyPaymentMethodId || ""); if (data.items?.length) { setItems( data.items.map((it: any, idx: number) => ({ id: idx + 1, description: it.description || "", quantity: String(it.quantity ?? 1), unitPrice: String(it.unitPrice ?? ""), })), ); } } catch { toast.error("Error", "Failed to load payment request"); } finally { setLoadingData(false); } })(); }, [id]); useEffect(() => { (async () => { setLoadingPaymentMethods(true); try { const res = await api.company.paymentMethods(); const list = Array.isArray(res) ? res : res?.data || []; setPaymentMethods(list); } catch { setPaymentMethods([]); } finally { setLoadingPaymentMethods(false); } })(); }, []); useEffect(() => { if (channel === "EMAIL" && customerEmail && !recipient) { setRecipient(customerEmail); } }, [channel, customerEmail]); const updateItem = (id: number, field: keyof Item, value: string) => setItems((prev) => prev.map((it) => (it.id === id ? { ...it, [field]: value } : it)), ); const addItem = () => setItems((prev) => [ ...prev, { id: Date.now(), description: "", quantity: "1", unitPrice: "" }, ]); const removeItem = (id: number) => { if (items.length > 1) setItems((prev) => prev.filter((it) => it.id !== id)); }; const subtotal = useMemo( () => items.reduce( (sum, item) => sum + (parseFloat(item.quantity) || 0) * (parseFloat(item.unitPrice) || 0), 0, ), [items], ); const handleNext = () => { if (step === 0 && !paymentRequestNumber.trim()) { toast.error("Validation", "Payment request number is required"); return; } if (step === 1 && !customerName.trim()) { toast.error("Validation", "Customer name is required"); return; } setStep(step + 1); }; const handleSubmit = async () => { if (!customerName) { toast.error("Validation", "Please select a customer"); return; } const body = { paymentRequestNumber, customerName, customerEmail: customerEmail || undefined, channel, recipient, amount: amount ? Number(amount) : Number(subtotal.toFixed(2)), currency, issueDate: new Date(issueDate).toISOString(), dueDate: dueDate ? new Date(dueDate).toISOString() : undefined, companyPaymentMethodId: companyPaymentMethodId || undefined, customerId: customerId || undefined, ...(description ? { description } : {}), items: items.map((i) => ({ description: i.description || "Item", quantity: parseFloat(i.quantity) || 0, unitPrice: parseFloat(i.unitPrice) || 0, total: Number( ((parseFloat(i.quantity) || 0) * (parseFloat(i.unitPrice) || 0)).toFixed(2), ), })), }; try { setSubmitting(true); const reqId = Array.isArray(id) ? id[0] : id; await api.paymentRequests.update({ params: { id: reqId }, body, headers: { "Content-Type": "application/json" }, }); toast.success("Success", "Payment request updated successfully!"); nav.back(); } catch (err: any) { console.error("[PaymentRequestEdit] Error:", err); toast.error("Error", err?.message || "Failed to update payment request"); } finally { setSubmitting(false); } }; const paymentMethodLabel = companyPaymentMethodId ? paymentMethods.find((pm: any) => pm.id === companyPaymentMethodId) ?.label || paymentMethods.find((pm: any) => pm.id === companyPaymentMethodId) ?.providerName || "Selected" : "Select"; if (loadingData) { return ( ); } return ( setStep(step - 1)} onComplete={handleSubmit} loading={submitting} completeLabel="Update Request" > {step === 0 && ( Request Details )} {step === 1 && ( Customer Information Customer { setCustomerId(ids[0] || ""); setCustomerName(customers[0]?.name || ""); setCustomerEmail(customers[0]?.email || ""); }} placeholder="Select a customer" /> setShowChannel(true)} /> )} {step === 2 && ( Schedule & Currency setShowIssueDate(true)} /> setShowDueDate(true)} /> setShowCurrency(true)} /> 0 ? `${currency} ${subtotal.toFixed(2)}` : "Enter amount"} numeric /> )} {step === 3 && ( Items Add {items.map((item, index) => ( Item {index + 1} removeItem(item.id)} hitSlop={8}> updateItem(item.id, "description", v)} /> updateItem(item.id, "quantity", v)} flex={1} /> updateItem(item.id, "unitPrice", v)} flex={3} /> {parseFloat(item.quantity) > 0 && parseFloat(item.unitPrice) > 0 && ( = {currency}{" "} {( (parseFloat(item.quantity) || 0) * (parseFloat(item.unitPrice) || 0) ).toFixed(2)} )} ))} {subtotal > 0 && ( Subtotal {currency} {subtotal.toFixed(2)} )} )} {step === 4 && ( Payment Method Company Payment Method { if (paymentMethods.length > 0) { setShowPaymentMethod(true); } else { toast.error( "No Methods", "No payment methods available. Please configure one in company settings.", ); } }} className="h-11 px-3 border border-border rounded-[6px] flex-row items-center justify-between" style={{ backgroundColor: c.bg, borderColor: c.border }} > {loadingPaymentMethods ? ( ) : ( <> {paymentMethodLabel} )} )} {step === 5 && ( Summary {description ? ( ) : null} {items.length > 0 && ( Items ({items.length}) {items.map((item, i) => ( {item.description || `Item ${i + 1}`} {item.quantity} × {currency}{" "} {parseFloat(item.unitPrice || "0").toFixed(2)} ))} )} {paymentMethodLabel !== "Select" && ( )} Total Amount {currency}{" "} {(amount ? Number(amount) : subtotal).toLocaleString( "en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 }, )} )} setShowCurrency(false)} title="Select Currency" > {CURRENCIES.map((curr) => ( { setCurrency(v); setShowCurrency(false); }} /> ))} setShowChannel(false)} title="Invite Channel" > {CHANNELS.map((ch) => ( { setChannel(v); setShowChannel(false); }} /> ))} setShowPaymentMethod(false)} title="Payment Method" > {paymentMethods.map((pm: any) => ( { setCompanyPaymentMethodId(v); setShowPaymentMethod(false); }} /> ))} setShowIssueDate(false)} title="Select Issue Date" > { setIssueDate(v); setShowIssueDate(false); }} /> setShowDueDate(false)} title="Select Due Date" > { setDueDate(v); setShowDueDate(false); }} /> ); } function SummaryRow({ label, value, multiline, }: { label: string; value: string; multiline?: boolean; }) { return ( {label} {value} ); }