/* eslint-disable @typescript-eslint/no-explicit-any */ import Link from "next/link"; import { useCallback, useEffect, useRef, useState } from "react"; import { getGroupInvoices } from "../../../Api/OrderApi"; import moment from "moment-timezone"; import { amountFormatWithCurrency, getGroupInvoiceStatusInfo, truncateWithTooltip, } from "../../../lib/Helper"; import NoData from "../../NoDataContainer/NoData"; import Modal from "../../Modal/Modal"; import GroupInvoiceFilter from "../../Modal/Filters/GroupInvoiceFilter"; import Swal from "sweetalert2"; import { InvoicePaymentStatus } from "@/Constant/enums"; import { toast } from "react-toastify"; import HourGlassLoader from "../../Loader/Loader"; import axios from "axios"; import { N_A } from "@/Constant"; interface Invoice { invoice_number: string; status: string; total_orders: number; period_start: string; period_end: string; invoice_date: string; total_amount: number; } export default function NotificationsIndex() { const [activeTab, setActiveTab] = useState(1); const [invoices, setInvoices] = useState([]); const [loading, setLoading] = useState(false); const [filterModal, setFilterModal] = useState(false); const [filters, setFilters] = useState({ dateRange: { start: "", end: "", }, invoiceDateRange: { start: "", end: "", }, status: "", amountRange: { min: "", max: "", }, invoiceNumber: "", }); const [showDropdown, setShowDropdown] = useState(null); const dropdownContainerRefs = useRef>( {} ); useEffect(() => { const handleClickOutside = (event: MouseEvent) => { const isClickInside = Object.values(dropdownContainerRefs.current).some( (ref) => ref && ref.contains(event.target as Node) ); if (!isClickInside) { setShowDropdown(null); } }; // document.addEventListener("mousedown", handleClickOutside); return () => { document.removeEventListener("mousedown", handleClickOutside); }; }, []); const fetchInvoices = useCallback(async () => { try { setLoading(true); const params: any = { created_from: filters.dateRange.start || undefined, created_to: filters.dateRange.end || undefined, invoice_date_from: filters.invoiceDateRange.start || undefined, invoice_date_to: filters.invoiceDateRange.end || undefined, invoice_amount_from: filters.amountRange.min > 0 ? filters.amountRange.min : undefined, invoice_amount_to: filters.amountRange.max > 0 ? filters.amountRange.max : undefined, invoice_number: filters.invoiceNumber || undefined, }; // Payment status handling based on activeTab if (activeTab === InvoicePaymentStatus.Pending) { params.status = InvoicePaymentStatus.Pending; // unpaid } else if (activeTab === InvoicePaymentStatus.PartiallyPaid) { params.status = InvoicePaymentStatus.PartiallyPaid; } else if (activeTab === InvoicePaymentStatus.Success) { params.status = InvoicePaymentStatus.Success; // paid } const data = await getGroupInvoices(params); setInvoices(data || []); } catch (error) { console.error("Error fetching invoices:", error); } finally { setLoading(false); } }, [filters, activeTab]); useEffect(() => { fetchInvoices(); }, [fetchInvoices]); useEffect(() => { fetchInvoices(); }, [fetchInvoices]); // Keyboard shortcut for clearing all filters useEffect(() => { const handleKeyDown = (event: KeyboardEvent) => { // Ctrl+Shift+C to clear all filters if (event.ctrlKey && event.shiftKey && event.key === "C") { event.preventDefault(); handleClearAllFilters(); } }; window.addEventListener("keydown", handleKeyDown); return () => window.removeEventListener("keydown", handleKeyDown); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); useEffect(() => { const handleClickOutside = (event: MouseEvent) => { // Check if click is inside any of the dropdown containers const isClickInside = Object.values(dropdownContainerRefs.current).some( (ref) => ref && ref.contains(event.target as Node) ); if (!isClickInside) { setShowDropdown(null); // close dropdown } }; document.addEventListener("mousedown", handleClickOutside); return () => { document.removeEventListener("mousedown", handleClickOutside); }; }, []); useEffect(() => { const handleKeyDown = (event: KeyboardEvent) => { if (event.key === "Escape") { setShowDropdown(null); } }; window.addEventListener("keydown", handleKeyDown); return () => window.removeEventListener("keydown", handleKeyDown); }, []); const toggleFilter = () => setFilterModal(!filterModal); const onSaveFilter = (filter: any) => { setFilters(filter); toggleFilter(); }; // Filter handling functions const clearIndividualFilter = (filterType: string) => { setFilters((prev: any) => { const newFilters = { ...prev }; if (filterType === "invoiceNumber") { // Remove invoice number filter delete newFilters.invoiceNumber; } else if (filterType === "amount") { // Reset amount range newFilters.amountRange = { min: 0, max: 0 }; } else if (filterType === "dateRange") { // Reset created date range newFilters.dateRange = { start: "", end: "" }; } else if (filterType === "invoiceDateRange") { // Reset invoice date range newFilters.invoiceDateRange = { start: "", end: "" }; } else if (filterType === "status") { // Reset status newFilters.status = ""; } return newFilters; }); }; const clearAllFilters = () => { // Reset all filters to default values setFilters({ dateRange: { start: "", end: "", }, invoiceDateRange: { start: "", end: "", }, status: "", amountRange: { min: 0, max: 0, }, invoiceNumber: "", }); // Close filter modal if it's open if (filterModal) { setFilterModal(false); } // Reset active tab to default state setActiveTab(InvoicePaymentStatus?.Pending); // Optional: Show a brief success message // You can add a toast notification here if you have a notification system }; // Get applied filter badges const getFilterBadges = () => { const badges = []; if (filters.invoiceNumber) { badges.push({ type: "invoiceNumber", label: filters.invoiceNumber, color: "bg-blue-dark", }); } if (filters.amountRange.min > 0 || filters.amountRange.max > 0) { const amountLabel = filters.amountRange.min > 0 && filters.amountRange.max > 0 ? `Invoice Amount: ${amountFormatWithCurrency(filters.amountRange.min)} - ${amountFormatWithCurrency(filters.amountRange.max)}` : filters.amountRange.min > 0 ? `Min: ${filters.amountRange.min}` : `Max: ${filters.amountRange.max}`; badges.push({ type: "amount", label: amountLabel, color: "bg-blue-dark", }); } if (filters.dateRange.start || filters.dateRange.end) { const dateLabel = filters.dateRange.start && filters.dateRange.end ? `Created: ${moment(filters.dateRange.start).format("MMM DD, YYYY")} - ${moment(filters.dateRange.end).format("MMM DD, YYYY")}` : `Created: ${moment(filters.dateRange.start).format("MMM DD, YYYY") || moment(filters.dateRange.end).format("MMM DD, YYYY")}`; badges.push({ type: "dateRange", label: dateLabel, color: "bg-blue-dark", }); } if (filters.invoiceDateRange.start || filters.invoiceDateRange.end) { const invoiceDateLabel = filters.invoiceDateRange.start && filters.invoiceDateRange.end ? `Invoice: ${moment(filters.invoiceDateRange.start).format("MMM DD, YYYY")} - ${moment(filters.invoiceDateRange.end).format("MMM DD, YYYY")}` : `Invoice: ${moment(filters.invoiceDateRange.start).format("MMM DD, YYYY") || moment(filters.invoiceDateRange.end).format("MMM DD, YYYY")}`; badges.push({ type: "invoiceDateRange", label: invoiceDateLabel, color: "bg-green-dark", }); } return badges; }; // Enhanced clear all with SweetAlert const handleClearAllFilters = () => { // Check if SweetAlert is available if (typeof window !== "undefined" && (window as any).Swal) { Swal.fire({ title: "Clear All Filters?", text: "Are you sure you want to clear all applied filters?", icon: "warning", showCancelButton: true, reverseButtons: true, customClass: { confirmButton: "delybell-primary px-4", cancelButton: "delybell-dark", }, confirmButtonText: "Yes, clear all!", cancelButtonText: "Cancel", }).then((result: any) => { if (result.isConfirmed) { clearAllFilters(); Swal.fire({ title: "Cleared!", text: "All filters have been cleared successfully.", icon: "success", reverseButtons: true, customClass: { confirmButton: "delybell-primary px-4", cancelButton: "delybell-dark", }, }); } }); } else { // Fallback to regular confirm if SweetAlert is not available Swal.fire({ title: "Clear All Filters?", text: "Are you sure you want to clear all applied filters?", icon: "warning", showCancelButton: true, reverseButtons: true, customClass: { confirmButton: "delybell-primary px-4", cancelButton: "delybell-dark", }, confirmButtonText: "Yes, clear all!", cancelButtonText: "Cancel", }).then((result: any) => { if (result.isConfirmed) { clearAllFilters(); } }); } }; // Check if any filters are applied (excluding status) const hasActiveFilters = () => { return ( filters.dateRange.start || filters.dateRange.end || filters.invoiceDateRange.start || filters.invoiceDateRange.end || filters.amountRange.min > 0 || filters.amountRange.max > 0 || filters.invoiceNumber ); }; const toggleDropdown = (invoiceId: string) => { setShowDropdown((prev) => (prev === invoiceId ? null : invoiceId)); }; // const handleView = (invoice: any, type = "invoice") => { // const url = // type === "receipt" // ? `/receipt-view?id=${cryptoHandler(invoice?.id, "encrypt")}` // : `/invoice-view?id=${cryptoHandler(invoice?.id, "encrypt")}`; // window.open(url, "_blank"); // }; const handlePreview = async (invoice: any) => { try { setIsLoading(true); const response: any = await axios.get( `${process.env.NEXT_PUBLIC_API_BASE_URL}/customer/group_invoice/download/${invoice.id}`, { responseType: "blob", headers: { Authorization: `Bearer ${localStorage.getItem("AUTH_TOKEN")}`, }, } ); if (response?.status === 200 && response.data) { const blob = new Blob([response.data], { type: response.headers["content-type"] || "application/pdf", }); const url = window.URL.createObjectURL(blob); // ✅ Open in new tab window.open(url, "_blank"); } else { toast.error("No file received."); } } catch (error) { console.error("Invoice preview error:", error); toast.error("Failed to preview invoice."); } finally { setIsLoading(false); } }; const [isLoading, setIsLoading] = useState(false) const [downloadLoading, setDownloadLoading] = useState(false) const downloadGroupInvoice = async(id: number) => { // export const downloadInvoice = async (receiptId: any, selectedId: any) => { try { setIsLoading(true) setDownloadLoading(true) const response: any = await axios.get( `${process.env.NEXT_PUBLIC_API_BASE_URL}/customer/group_invoice/download/${id}`, { responseType: "blob", // ensure binary headers: { Authorization: `Bearer ${localStorage.getItem("AUTH_TOKEN")}`, }, } ); if (response?.status === 200 && response.data) { // ✅ Create a Blob from binary response const blob = new Blob([response.data], { type: response.headers["content-type"] || "application/pdf", }); const downloadUrl = URL.createObjectURL(blob); // ✅ Create a temporary to download const a = document.createElement("a"); a.href = downloadUrl; a.download = `Invoice_${id}-${id}.pdf`; document.body.appendChild(a); a.click(); // ✅ Clean up AFTER download setTimeout(() => { URL.revokeObjectURL(downloadUrl); a.remove(); }, 1000); toast.success("Invoice downloaded successfully!"); } else { toast.error("No file received."); } // eslint-disable-next-line @typescript-eslint/no-unused-vars } catch (error: any) { toast.error("Failed to download invoice."); } finally { setIsLoading(false) setDownloadLoading(false) } }; return ( <> {isLoading && }
{hasActiveFilters() && (
{getFilterBadges().map((badge, index) => (
{badge.label}  |  clearIndividualFilter(badge.type)} >
))}
 |  Clear All
)}
{loading ? (
) : (
{invoices?.length > 0 ? ( invoices.map((invoice: any, index) => (
{ dropdownContainerRefs.current[ invoice.id ] = el; }} >
{invoice?.generatedInvoiceId}
{getGroupInvoiceStatusInfo(invoice?.paymentStatus?.id, invoice)?.text} { e.preventDefault(); toggleDropdown(invoice.id); }} className="ms-auto" > {showDropdown === invoice.id && (
e.stopPropagation()} >
)}
{/* { invoice?.order ?.destinationCustomerName } */} {invoice?.payableAmount ? amountFormatWithCurrency( invoice?.payableAmount || 0 ) : ""}
{/* Calendar Icon */} {/* Due Date:{" "} */}