import React, { useState, useEffect } from "react"; import { View, ScrollView, Pressable, TextInput, StyleSheet, ActivityIndicator, } from "react-native"; import { Text } from "@/components/ui/text"; import { Button } from "@/components/ui/button"; import { ArrowLeft, ArrowRight, Trash2, Send, Plus, Calendar, ChevronDown, CalendarSearch, } from "@/lib/icons"; import { ScreenWrapper } from "@/components/ScreenWrapper"; import { useSirouRouter } from "@sirou/react-native"; import { AppRoutes } from "@/lib/routes"; import { Stack } from "expo-router"; import { colorScheme, useColorScheme } from "nativewind"; import { ShadowWrapper } from "@/components/ShadowWrapper"; import { api } from "@/lib/api"; import { toast } from "@/lib/toast-store"; import { PickerModal, SelectOption } from "@/components/PickerModal"; import { CalendarGrid } from "@/components/CalendarGrid"; import { StandardHeader } from "@/components/StandardHeader"; import { getPlaceholderColor } from "@/lib/colors"; type Item = { id: number; description: string; qty: string; price: string }; const S = StyleSheet.create({ input: { height: 44, paddingHorizontal: 12, fontSize: 12, fontWeight: "500", borderRadius: 6, borderWidth: 1, }, inputCenter: { height: 44, paddingHorizontal: 12, fontSize: 14, fontWeight: "500", borderRadius: 6, borderWidth: 1, textAlign: "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, }: { label: string; value: string; onChangeText: (v: string) => void; placeholder: string; numeric?: boolean; center?: boolean; flex?: number; }) { const c = useInputColors(); const isDark = colorScheme.get() === "dark"; return ( {label} ); } const CURRENCIES = ["USD", "ETB", "EUR", "GBP", "KES", "ZAR"]; export default function CreateProformaScreen() { const nav = useSirouRouter(); const [loading, setLoading] = useState(false); // 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("USD"); const [taxAmount, setTaxAmount] = useState("0"); const [discountAmount, setDiscountAmount] = useState("0"); const [notes, setNotes] = useState(""); // 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); // Handle Phone Formatting (Auto-prepend +251 if needed) const formattedPhone = customerPhone.startsWith("+") ? customerPhone : customerPhone.length > 0 ? `+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, 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 isDark = colorScheme.get() === "dark"; return ( {/* Header Info */} {/* Recipient */} {/* Schedule */} Issue Date setShowIssueDate(true)} className="h-11 px-3 border border-border rounded-[6px] flex-row items-center justify-between" style={{ backgroundColor: c.bg, borderColor: c.border }} > {issueDate} Due Date setShowDueDate(true)} className="h-11 px-3 border border-border rounded-[6px] flex-row items-center justify-between" style={{ backgroundColor: c.bg, borderColor: c.border }} > {dueDate || "Select Date"} Currency setShowCurrency(true)} className="h-11 px-3 border border-border rounded-[6px] flex-row items-center justify-between" style={{ backgroundColor: c.bg, borderColor: c.border }} > {currency} {/* Items */} Add Item {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} /> updateField(item.id, "price", v)} flex={2} /> Total {currency} {( (parseFloat(item.qty) || 0) * (parseFloat(item.price) || 0) ).toFixed(2)} ))} {/* Summary */} Subtotal {currency} {subtotal.toLocaleString()} {/* Notes */} {/* Footer */} Total Amount {currency}{" "} {total.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 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); }} /> ); } function Label({ children, noMargin, }: { children: string; noMargin?: boolean; }) { return ( {children} ); }