2026-02-21 19:04:54 +00:00

313 lines
14 KiB
TypeScript

"use client";
import React, { useEffect, useState } from "react";
import { useParams, useRouter } from "next/navigation";
import axios from "axios";
import { ApiServerBaseUrl } from "@/utils/baseurl.utils";
const InvoiceDetail: React.FC = () => {
const params = useParams();
const router = useRouter();
const invoiceId = params?.id;
const [paymentData, setPaymentData] = useState<any>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const fetchPaymentData = async () => {
try {
// Check if it's a trial invoice
if (invoiceId === "trial-inv") {
setPaymentData({
createdAt: new Date().toISOString(),
endDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(),
status: "active",
email: "user@example.com", // You could fetch meaningful user email if stored in localStorage
planId: "Free Trial",
amount: 0
});
setLoading(false);
return;
}
const sessionId = localStorage.getItem("payment_session");
if (!sessionId) {
setError("No payment session found");
setLoading(false);
return;
}
const res: any = await axios.get(`${ApiServerBaseUrl}/payment/details`, {
params: { session_id: sessionId },
});
setPaymentData(res.data.data);
} catch (err: any) {
setError(err.response?.data?.error || "Failed to fetch payment details");
} finally {
setLoading(false);
}
};
fetchPaymentData();
}, [invoiceId]);
const invoice = paymentData
? {
number: `#${invoiceId}`,
issueDate: paymentData.createdAt
? new Date(paymentData.createdAt).toLocaleDateString()
: "N/A",
validTill: paymentData.endDate
? new Date(paymentData.endDate).toLocaleDateString()
: "N/A",
status: paymentData.status || "pending",
issuedFor: paymentData.email || "",
customerId: "",
plan: paymentData.planId || "N/A",
bankName: "Bank of Canada",
accountNo: "1234567890",
country: "Canada",
items: [
{
sno: 1,
plan: paymentData.planId || "N/A",
qty: 1,
price: paymentData.amount,
amount: paymentData.amount,
},
],
subtotal: paymentData.amount,
tax: 0,
grandTotal: paymentData.amount,
createdAt: paymentData.createdAt,
}
: null;
const handlePrint = () => window.print();
if (loading) {
return (
<div className="flex items-center justify-center min-h-screen text-gray-400">
Loading invoice details...
</div>
);
}
if (error || !invoice) {
return (
<div className="flex flex-col items-center justify-center min-h-screen text-center px-4">
<p className="text-red-500 mb-4">{error || "Invoice not found"}</p>
<button
onClick={() => router.back()}
className="mt-4 px-6 py-3 rounded-xl font-bold bg-gradient-to-r from-[#4361ee] to-[#c026d3] text-white"
>
Go Back
</button>
</div>
);
}
return (
<div className="relative min-h-screen px-4 py-10 overflow-hidden bg-[#111111]">
{/* ===================== PRICING-PAGE BACKGROUND GLOWS ===================== */}
<div className="absolute top-[180px] left-52 w-[100px] h-[100px]
bg-[#1d8be0] rounded-full blur-2xl opacity-[1.5] animate-zoomslow"></div>
<div className="absolute top-10 left-0 w-[60px] h-[60px]
bg-[#6cb655] rounded-full blur-2xl opacity-[1.5] animate-zoomslower"></div>
<div className="absolute -left-[80px] bottom-[140px] w-[100px] h-[200px]
bg-[#db21d9] blur-3xl opacity-1 animate-zoomslow"></div>
<div className="absolute bottom-20 left-[440px] w-[60px] h-[60px]
bg-[#db21d9] rounded-full blur-xl opacity-80 -translate-x-1/2 translate-y-1/2"></div>
<div className="absolute top-[100px] right-[260px] w-[100px] h-[100px]
bg-[#f28f50] rounded-full blur-2xl opacity-80 animate-zoomfast"></div>
<div className="absolute top-10 right-0 w-[60px] h-[60px]
bg-[#6cb655] rounded-full blur-2xl opacity-[1.5] animate-zoomslower"></div>
<div className="absolute bottom-20 right-[180px] w-[80px] h-[80px]
bg-[#783e8d] rounded-full blur-2xl opacity-80 animate-zoomslow"></div>
<div className="absolute top-[280px] -right-[20px] w-[160px] h-[160px]
bg-[#f1b74d] rounded-full blur-2xl opacity-1 animate-zoomslower"></div>
{/* ===================== PAGE CONTENT ===================== */}
<div className="relative z-10 max-w-5xl mx-auto">
{/* Back Button */}
<button
onClick={() => router.back()}
className="mb-6 flex items-center gap-2 text-gray-400 hover:text-white transition-colors"
>
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
</svg>
Back to Account Settings
</button>
{/* Invoice Card */}
<div className="glass-card rounded-2xl p-8 lg:p-12">
<div className="flex justify-between items-start mb-12">
<div>
<h1 className="text-3xl font-extrabold text-white mb-2">INVOICE</h1>
<div className="flex items-center gap-3 mb-2">
<h3 className="text-sm font-semibold text-gray-400">Invoice No:</h3>
<p className="text-white font-bold text-lg">{invoice.number}</p>
</div>
</div>
<div className="text-right">
<div className="flex items-center gap-2 mb-4">
<div className="w-12 h-12">
<img src="/assets/images/logo_sb.png" alt="logo" className="inline w-12" />
</div>
<div>
<h2 className="text-xl font-bold text-white">SOCIAL BUDDY</h2>
<p className="text-xs text-gray-400 uppercase tracking-wider">Social Media Manager</p>
</div>
</div>
<p className="text-sm text-gray-400">Social Buddy</p>
<p className="text-sm text-gray-400">support@socialbuddy.com</p>
<p className="text-sm text-gray-400">+1-555-SOCIAL-1</p>
</div>
</div>
{/* Invoice info */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 mb-12">
<div className="space-y-4">
<div>
<div className="flex items-center gap-3 mb-2">
<h3 className="text-sm font-semibold text-gray-400">Issue For:</h3>
<p className="text-white">{invoice.createdAt}</p>
</div>
<p className="text-gray-400 text-sm">Customer ID: N/A</p>
<p className="text-gray-400 text-sm">Plan: {invoice.plan}</p>
</div>
</div>
<div className="space-y-4 md:text-right">
<div className="flex items-center gap-3">
<h3 className="text-sm font-semibold text-gray-400">Issue Date:</h3>
<p className="text-white">{invoice.issueDate}</p>
</div>
<div className="flex items-center gap-3">
<h3 className="text-sm font-semibold text-gray-400">Valid Till:</h3>
<p className="text-white">{invoice.validTill}</p>
</div>
<div className="flex items-center gap-3">
<h3 className="text-sm font-semibold text-gray-400">Status:</h3>
<span className="px-4 py-1 rounded-full bg-yellow-500/20 text-yellow-400 text-sm font-semibold">
{invoice.status}
</span>
</div>
</div>
</div>
{/* Table */}
<div className="mb-12 overflow-x-auto">
<table className="w-full">
<thead>
<tr className="border-b border-white/10">
<th className="py-4 px-4 text-gray-400 text-sm">S.NO</th>
<th className="py-4 px-4 text-gray-400 text-sm">PLAN</th>
<th className="py-4 px-4 text-gray-400 text-sm text-center">QTY</th>
<th className="py-4 px-4 text-gray-400 text-sm text-right">PRICE</th>
<th className="py-4 px-4 text-gray-400 text-sm text-right">AMOUNT</th>
</tr>
</thead>
<tbody>
{invoice.items.map((item) => (
<tr key={item.sno} className="border-b border-white/5">
<td className="py-4 px-4 text-white">{item.sno}</td>
<td className="py-4 px-4 text-white">{item.plan}</td>
<td className="py-4 px-4 text-center text-white">{item.qty}</td>
<td className="py-4 px-4 text-right text-white">${item.price.toFixed(2)}</td>
<td className="py-4 px-4 text-right text-white font-semibold">
${item.amount.toFixed(2)}
</td>
</tr>
))}
</tbody>
</table>
</div>
{/* Totals */}
<div className="flex justify-end mb-12">
<div className="w-full md:w-1/2 lg:w-1/3 space-y-3">
<div className="flex justify-between py-2 border-b border-white/10">
<span className="text-gray-400">Subtotal:</span>
<span className="text-white font-semibold">${invoice.subtotal.toFixed(2)}</span>
</div>
<div className="flex justify-between py-2 border-b border-white/10">
<span className="text-gray-400">Tax:</span>
<span className="text-white font-semibold">${invoice.tax.toFixed(2)}</span>
</div>
<div className="flex justify-between py-3 border-t border-white/20">
<span className="text-white font-bold text-lg">Grand Total:</span>
<span className="text-white font-bold text-xl">
${invoice.grandTotal.toFixed(2)}
</span>
</div>
</div>
</div>
{/* Print Button */}
<div className="flex justify-end">
<button
onClick={handlePrint}
className="px-6 py-3 rounded-xl font-bold bg-gradient-to-r from-[#4361ee] to-[#c026d3] text-white flex items-center gap-2"
>
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2}
d="M17 17h2a2 2 0 002-2v-4a2 2 0 00-2-2H5a2 2 0 00-2 2v4a2 2 0 002 2h2m2 4h6a2 2 0 002-2v-4a2 2 0 00-2-2H9a2 2 0 00-2 2v4a2 2 0 002 2zm8-12V5a2 2 0 00-2-2H9a2 2 0 00-2 2v4h10z"
/>
</svg>
Print
</button>
</div>
</div>
</div>
{/* Print Styles */}
<style jsx global>{`
@media print {
body {
background: white !important;
}
.glass-card {
background: white !important;
border: 1px solid #e5e7eb !important;
box-shadow: none !important;
}
button {
display: none !important;
}
.text-white {
color: black !important;
}
.text-gray-400 {
color: #6b7280 !important;
}
}
`}</style>
</div>
);
};
export default InvoiceDetail;