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 && }
);
}