import React, { useState, useEffect } from "react"; import { View, Pressable, TextInput, StyleSheet, Platform } from "react-native"; import { Text } from "@/components/ui/text"; import { Trash2, Plus, ChevronDown, Info, Check } from "@/lib/icons"; import { ScreenWrapper } from "@/components/ScreenWrapper"; import { useSirouRouter } from "@sirou/react-native"; import { AppRoutes } from "@/lib/routes"; import { useColorScheme } from "nativewind"; import { api } from "@/lib/api"; import { toast } from "@/lib/toast-store"; import { PickerModal, SelectOption } from "@/components/PickerModal"; import { CalendarGrid } from "@/components/CalendarGrid"; import { FormFlow } from "@/components/FormFlow"; import { CustomerPicker } from "@/components/CustomerPicker"; type Item = { id: number; description: string; qty: string; price: 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, }: { label: string; value: string; onChangeText: (v: string) => void; placeholder: string; numeric?: boolean; center?: boolean; flex?: number; multiline?: boolean; }) { const c = useInputColors(); return ( {label} ); } function PickerField({ label, value, onPress, }: { label: string; value: string; onPress: () => void; }) { const c = useInputColors(); return ( {label} {value} ); } const CURRENCIES = ["USD", "ETB", "EUR", "GBP", "KES", "ZAR"]; const STEPS = [ { key: "customer", label: "Customer" }, { key: "details", label: "Details" }, { key: "items", label: "Items" }, { key: "tax", label: "Tax" }, { key: "notes", label: "Notes" }, { key: "summary", label: "Summary" }, ]; export default function CreateProformaScreen() { const nav = useSirouRouter(); const [loading, setLoading] = useState(false); const [step, setStep] = useState(0); // Fields const [proformaNumber, setProformaNumber] = useState(""); const [customerName, setCustomerName] = useState(""); const [customerEmail, setCustomerEmail] = useState(""); const [customerPhone, setCustomerPhone] = useState(""); const [description, setDescription] = useState(""); const [currency, setCurrency] = useState("ETB"); const [taxAmount, setTaxAmount] = useState("0"); const [discountAmount, setDiscountAmount] = useState("0"); const [notes, setNotes] = useState(""); const [sendEmail, setSendEmail] = useState(false); const [sendSms, setSendSms] = useState(false); const [showSendOptions, setShowSendOptions] = useState(false); const [tooltipItemId, setTooltipItemId] = useState(null); // Dates const [issueDate, setIssueDate] = useState( new Date().toISOString().split("T")[0], ); const [dueDate, setDueDate] = useState(""); const [items, setItems] = useState([ { id: 1, description: "", qty: "1", price: "" }, ]); const c = useInputColors(); // Modal States const [showCurrency, setShowCurrency] = useState(false); const [showIssueDate, setShowIssueDate] = useState(false); const [showDueDate, setShowDueDate] = useState(false); // Auto-generate Proforma Number and set default dates on mount useEffect(() => { const year = new Date().getFullYear(); const random = Math.floor(1000 + Math.random() * 9000); setProformaNumber(`PROF-${year}-${random}`); // Default Due Date: 30 days from now const d = new Date(); d.setDate(d.getDate() + 30); setDueDate(d.toISOString().split("T")[0]); }, []); const updateField = (id: number, field: keyof Item, value: string) => setItems((prev) => prev.map((item) => (item.id === id ? { ...item, [field]: value } : item)), ); const addItem = () => setItems((prev) => [ ...prev, { id: Date.now(), description: "", qty: "1", price: "" }, ]); const removeItem = (id: number) => { if (items.length > 1) setItems((prev) => prev.filter((item) => item.id !== id)); }; const subtotal = items.reduce( (sum, item) => sum + (parseFloat(item.qty) || 0) * (parseFloat(item.price) || 0), 0, ); const total = subtotal + (parseFloat(taxAmount) || 0) - (parseFloat(discountAmount) || 0); const handleSubmit = async () => { if (!customerName) { toast.error("Validation Error", "Please enter a customer name"); return; } try { setLoading(true); const formattedPhone = customerPhone ? `+251${customerPhone}` : ""; const payload = { proformaNumber, customerName, customerEmail, customerPhone: formattedPhone, amount: Number(total.toFixed(2)), currency, issueDate: new Date(issueDate).toISOString(), dueDate: new Date(dueDate).toISOString(), description: description || `Proforma for ${customerName}`, notes, taxAmount: parseFloat(taxAmount) || 0, discountAmount: parseFloat(discountAmount) || 0, sendEmail, sendSms, items: items.map((i) => ({ description: i.description || "Item", quantity: parseFloat(i.qty) || 0, unitPrice: parseFloat(i.price) || 0, total: Number( ((parseFloat(i.qty) || 0) * (parseFloat(i.price) || 0)).toFixed(2), ), })), }; await api.proforma.create({ body: payload }); toast.success("Success", "Proforma created successfully!"); nav.back(); } catch (err: any) { console.error("[ProformaCreate] Error:", err); toast.error("Error", err.message || "Failed to create proforma"); } finally { setLoading(false); } }; const handleNext = () => { switch (step) { case 0: if (!customerName.trim()) { toast.error("Validation Error", "Please enter a customer name"); return; } break; case 1: break; case 2: if (items.length === 0) { toast.error("Validation Error", "Please add at least one item"); return; } break; case 3: break; case 4: break; } setStep((s) => s + 1); }; return ( setStep((s) => s - 1)} onComplete={handleSubmit} loading={loading} > {step === 0 && ( Customer Information Customer Name { setCustomerName(c.name); setCustomerEmail(c.email); setCustomerPhone(c.phone.replace("+251", "")); }} placeholder="Select or search for a customer" /> Phone +251 )} {step === 1 && ( General Information Schedule & Currency setShowIssueDate(true)} /> setShowDueDate(true)} /> setShowCurrency(true)} /> )} {step === 2 && ( Billable Items Add {items.map((item, index) => ( Item {index + 1} {items.length > 1 && ( removeItem(item.id)} hitSlop={8} > )} updateField(item.id, "description", v)} /> updateField(item.id, "qty", v)} flex={1} /> Price setTooltipItemId( tooltipItemId === item.id ? null : item.id, ) } className="h-2 w-2 rounded-full items-center justify-center" > updateField(item.id, "price", v)} keyboardType="numeric" autoCorrect={false} autoCapitalize="none" returnKeyType="next" /> {tooltipItemId === item.id && ( before tax )} ))} )} {step === 3 && ( Tax & Discount Subtotal {currency}{" "} {subtotal.toLocaleString("en-US", { minimumFractionDigits: 2, })} Tax +{currency}{" "} {(parseFloat(taxAmount) || 0).toLocaleString("en-US", { minimumFractionDigits: 2, })} Discount -{currency}{" "} {(parseFloat(discountAmount) || 0).toLocaleString("en-US", { minimumFractionDigits: 2, })} Total {currency}{" "} {total.toLocaleString("en-US", { minimumFractionDigits: 2 })} )} {step === 4 && ( setShowSendOptions(true)} className="flex-row items-center justify-between p-4" > Send automatically Email & SMS notifications {(sendEmail || sendSms) && ( {sendEmail && ( Email )} {sendSms && ( SMS )} )} )} {step === 5 && ( Summary Customer {customerName} {(customerEmail || customerPhone) && ( Contact {customerEmail || (customerPhone ? `+251${customerPhone}` : "")} )} Proforma # {proformaNumber} Items {items.filter((i) => i.description.trim()).length} items Description {description || "N/A"} {notes ? ( Notes {notes} ) : null} Currency {currency} Total {currency}{" "} {total.toLocaleString("en-US", { minimumFractionDigits: 2, })} )} {/* Currency Modal */} setShowCurrency(false)} title="Select Currency" > {CURRENCIES.map((curr) => ( { setCurrency(v); setShowCurrency(false); }} /> ))} {/* Issue Date Modal */} setShowIssueDate(false)} title="Select Issue Date" > { setIssueDate(v); setShowIssueDate(false); }} /> {/* Due Date Modal */} setShowDueDate(false)} title="Select Due Date" > { setDueDate(v); setShowDueDate(false); }} /> {/* Send Notification Options Modal */} setShowSendOptions(false)} title="Send automatically" > Choose how you want to notify the customer when this proforma is created. setSendEmail(!sendEmail)} className={`flex-row items-center justify-between p-4 mb-3 rounded-[6px] border ${ sendEmail ? "bg-primary/5 border-primary/20" : "bg-secondary/20 border-border/5" }`} > Email notification {sendEmail && } setSendSms(!sendSms)} className={`flex-row items-center justify-between p-4 mb-3 rounded-[6px] border ${ sendSms ? "bg-primary/5 border-primary/20" : "bg-secondary/20 border-border/5" }`} > SMS notification {sendSms && } ); }