import { useState, useRef } from "react";
import jsPDF from "jspdf";
import html2canvas from "html2canvas";
export default function QuoteApp() {
const baseSetupFee = 997;
const [buildCost, setBuildCost] = useState(0);
const [discount, setDiscount] = useState(0);
const [annual, setAnnual] = useState(false);
const [notes, setNotes] = useState("");
const [selectedPlan, setSelectedPlan] = useState(null);
const [includeOrb, setIncludeOrb] = useState(false);
const [taxRate, setTaxRate] = useState(0);
const [shippingCost, setShippingCost] = useState(0);
const [clientName, setClientName] = useState("");
const [signature, setSignature] = useState("");
const [signedDate, setSignedDate] = useState("");
const quoteRef = useRef();
const plans = [
{
name: "Essentials Plan",
price: 297
},
{
name: "Pro Plan",
price: 497
},
{
name: "Elite Plan",
price: 697
}
];
const orbAddOn = {
name: "Orb Add-On",
price: 497
};
const handleDiscountChange = (e) => {
const value = e.target.value;
setDiscount(parseFloat(value));
};
const totalBuildCost = buildCost - buildCost * (discount / 100);
const annualMultiplier = annual ? 10 : 1;
const selectedPlanCost = selectedPlan !== null ? plans[selectedPlan].price * annualMultiplier : 0;
const totalOrbCost = includeOrb ? orbAddOn.price : 0;
const taxAmount = (totalBuildCost + totalOrbCost + baseSetupFee + shippingCost + selectedPlanCost) * (taxRate / 100);
const grandTotal = totalBuildCost + totalOrbCost + baseSetupFee + selectedPlanCost + shippingCost + taxAmount;
const downloadPDF = () => {
const input = quoteRef.current;
html2canvas(input).then((canvas) => {
const imgData = canvas.toDataURL("image/png");
const pdf = new jsPDF();
const imgProps = pdf.getImageProperties(imgData);
const pdfWidth = pdf.internal.pageSize.getWidth();
const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width;
pdf.addImage(imgData, "PNG", 0, 0, pdfWidth, pdfHeight);
pdf.save("Visionary_Flow_Quote.pdf");
});
const quoteData = {
clientName,
signature,
signedDate,
total: grandTotal,
plan: selectedPlan !== null ? plans[selectedPlan].name : "None",
includeOrb,
taxRate,
shippingCost,
notes,
};
// Save to internal dashboard (mocked for now)
fetch("/api/save-quote", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(quoteData),
})
.then((res) => res.json())
.then((data) => console.log("Quote saved to admin dashboard:", data))
.catch((err) => console.error("Save error:", err));
// GHL webhook/API push
fetch("https://hooks.highlevel.com/your-ghl-endpoint", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(quoteData),
})
.then((res) => res.json())
.then((data) => console.log("GHL Response:", data))
.catch((err) => console.error("GHL Error:", err));
// Email confirmation (mocked for now)
fetch("/api/send-confirmation-email", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
to: clientName,
subject: "Your Visionary Flow Solutions Quote",
message: `Hello ${clientName},\n\nThank you for reviewing and signing your quote.\n\nTotal: $${grandTotal.toFixed(2)}\nPlan: ${selectedPlan !== null ? plans[selectedPlan].name : "None"}\n\nVisionary Flow Solutions Team`,
}),
})
.then((res) => res.json())
.then((data) => console.log("Email confirmation sent:", data))
.catch((err) => console.error("Email Error:", err));
// Stripe redirect (example usage - needs server-side setup)
fetch("/create-stripe-session", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ amount: grandTotal, clientName }),
})
.then((res) => res.json())
.then((session) => {
if (session?.url) {
window.location.href = session.url;
}
})
.catch((err) => console.error("Stripe Error:", err));
};
return (
{/* UI stays the same */}
);
}