import React, { useEffect, useState, useMemo } from "react"; import { useIsLoggedIn } from '../../lib/isLoggedIn'; import Loader from "../../components/ui/loader"; import { PDFDownloadLink } from '@react-pdf/renderer'; import InvoicePDF from "../../lib/InvoicePDF"; import { Eye, Pencil, Trash2, Download, ChevronUp, ChevronDown, Search, ArrowLeft, FileText, ArrowRight } from "lucide-react"; import { Button } from "../ui/button"; import { Input } from "../ui/input"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "../ui/dialog"; import * as XLSX from 'xlsx'; export default function AllSellingList() { const [isDropdownOpen, setIsDropdownOpen] = useState(false); const { isLoggedIn, loading, error, sessionData } = useIsLoggedIn(); const [billingData, setBillingData] = useState([]); const [usersData, setUsersData] = useState([]); const [dataLoading, setDataLoading] = useState(true); const [apiError, setApiError] = useState(null); const [selectedItem, setSelectedItem] = useState(null); const [dialogOpen, setDialogOpen] = useState(false); const [editMode, setEditMode] = useState(false); const [formData, setFormData] = useState({ service: '', serviceId: 'service-1', cycle: 'monthly', amount: '', user: '', siliconId: '', name: '', status: 'pending', remarks: '' }); const [currentStep, setCurrentStep] = useState(1); const [selectedCustomer, setSelectedCustomer] = useState(null); const [customerSearchTerm, setCustomerSearchTerm] = useState(''); // Sorting state const [sortConfig, setSortConfig] = useState({ key: 'created_at', direction: 'desc' }); // Filtering state const [filters, setFilters] = useState({ status: '', cycle: '', service: '' }); // Search state const [searchTerm, setSearchTerm] = useState(''); // Pagination state const [currentPage, setCurrentPage] = useState(1); const [itemsPerPage] = useState(10); const INVOICE_API_URL = 'https://host-api-sxashuasysagibx.siliconpin.com/v1/users/'; useEffect(() => { if (isLoggedIn && sessionData?.user_type === 'admin') { fetchBillingData(); fetchUsersData(); } }, [isLoggedIn, sessionData]); const fetchBillingData = async () => { try { setDataLoading(true); const res = await fetch(`${INVOICE_API_URL}?query=all-selling-list`, { method: 'GET', credentials: 'include', headers: { 'Content-Type': 'application/json' } }); if (!res.ok) throw new Error(`HTTP error! status: ${res.status}`); const data = await res.json(); setBillingData(data.data || []); } catch (err) { setApiError(err.message); } finally { setDataLoading(false); } }; const fetchUsersData = async () => { try { const res = await fetch(`${INVOICE_API_URL}?query=get-all-users`, { method: 'GET', credentials: 'include', headers: { 'Content-Type': 'application/json' } }); if (!res.ok) throw new Error(`HTTP error! status: ${res.status}`); const data = await res.json(); setUsersData(data.data || []); } catch (err) { setApiError(err.message); } }; // Filter customers based on search term const filteredCustomers = useMemo(() => { return usersData.filter(user => user.name.toLowerCase().includes(customerSearchTerm.toLowerCase()) || user.email.toLowerCase().includes(customerSearchTerm.toLowerCase()) || user.siliconId.toLowerCase().includes(customerSearchTerm.toLowerCase()) ); }, [usersData, customerSearchTerm]); const handleViewItem = (item) => { setSelectedItem(item); setEditMode(false); setDialogOpen(true); }; const handleEditItem = (item) => { setSelectedItem(item); setFormData({ service: item.service, serviceId: item.serviceId, cycle: item.cycle, amount: item.amount, user: item.user, siliconId: item.siliconId, name: item.name, status: item.status, remarks: item.remarks, billing_date: item.billing_date }); setEditMode(true); setDialogOpen(true); }; const handleDeleteItem = async (billingId, serviceType) => { if (!window.confirm('Are you sure you want to delete this billing record?')) return; try { const res = await fetch(`${INVOICE_API_URL}?query=delete-billing&billingId=${billingId}&serviceType=${serviceType}`, { method: 'DELETE', credentials: 'include', headers: { 'Content-Type': 'application/json' } }); if (!res.ok) throw new Error(`HTTP error! status: ${res.status}`); fetchBillingData(); } catch (err) { setApiError(err.message); } }; const handleCreateNew = () => { setSelectedItem(null); setFormData({ service: '', serviceId: 'service-2', cycle: 'monthly', amount: '', user: '', siliconId: '', name: '', status: 'pending', remarks: '', billing_date: new Date().toISOString().split('T')[0] }); setEditMode(true); setCurrentStep(1); setSelectedCustomer(null); setCustomerSearchTerm(''); setDialogOpen(true); }; const handleSubmit = async (e) => { e.preventDefault(); try { const url = selectedItem ? `${INVOICE_API_URL}?query=update-billing&id=${selectedItem.id}` : `${INVOICE_API_URL}?query=create-billing`; const method = selectedItem ? 'PUT' : 'POST'; const res = await fetch(url, { method, credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(formData) }); if (!res.ok) throw new Error(`HTTP error! status: ${res.status}`); fetchBillingData(); setDialogOpen(false); setCurrentStep(1); } catch (err) { setApiError(err.message); } }; const handleInputChange = (e) => { const { name, value } = e.target; setFormData(prev => ({ ...prev, [name]: value })); }; const handleCustomerSelect = (customer) => { setSelectedCustomer(customer); setFormData(prev => ({ ...prev, user: customer.email, siliconId: customer.siliconId, name: customer.name })); setCurrentStep(2); }; const handleBackToCustomerSelect = () => { setCurrentStep(1); setSelectedCustomer(null); }; // Export to Excel function const exportToExcel = () => { const worksheet = XLSX.utils.json_to_sheet(filteredAndSortedData.map(item => ({ 'Billing ID': item.billing_id, 'Service': item.service, 'Customer Name': item.name, 'Customer Email': item.user, 'Silicon ID': item.siliconId, 'Amount': item.amount, 'cycle': item.cycle, 'Status': item.status, 'Service Status': item.service_status, 'Created At': formatDate(item.created_at), 'Remarks': item.remarks }))); const workbook = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(workbook, worksheet, "Billing Data"); XLSX.writeFile(workbook, `billing_data_${new Date().toISOString().slice(0, 10)}.xlsx`); }; // Sorting functionality const requestSort = (key) => { let direction = 'asc'; if (sortConfig.key === key && sortConfig.direction === 'asc') { direction = 'desc'; } setSortConfig({ key, direction }); setCurrentPage(1); }; // Filter and sort data const filteredAndSortedData = useMemo(() => { let filteredData = [...billingData]; if (searchTerm) { filteredData = filteredData.filter(item => Object.values(item).some( val => val && val.toString().toLowerCase().includes(searchTerm.toLowerCase()) ) ); } if (filters.status) { filteredData = filteredData.filter(item => item.status === filters.status); } if (filters.cycle) { filteredData = filteredData.filter(item => item.cycle === filters.cycle); } if (filters.service) { filteredData = filteredData.filter(item => item.service === filters.service); } if (sortConfig.key) { filteredData.sort((a, b) => { if (a[sortConfig.key] < b[sortConfig.key]) { return sortConfig.direction === 'asc' ? -1 : 1; } if (a[sortConfig.key] > b[sortConfig.key]) { return sortConfig.direction === 'asc' ? 1 : -1; } return 0; }); } return filteredData; }, [billingData, searchTerm, filters, sortConfig]); const currentItems = useMemo(() => { const indexOfLastItem = currentPage * itemsPerPage; const indexOfFirstItem = indexOfLastItem - itemsPerPage; return filteredAndSortedData.slice(indexOfFirstItem, indexOfLastItem); }, [currentPage, itemsPerPage, filteredAndSortedData]); const totalPages = Math.ceil(filteredAndSortedData.length / itemsPerPage); const paginate = (pageNumber) => { if (pageNumber > 0 && pageNumber <= totalPages) { setCurrentPage(pageNumber); } }; const getPaginationRange = () => { const range = []; const maxVisiblePages = 5; range.push(1); if (currentPage > 3) { range.push('...'); } let start = Math.max(2, currentPage - 1); let end = Math.min(totalPages - 1, currentPage + 1); if (currentPage <= 3) { end = Math.min(4, totalPages - 1); } else if (currentPage >= totalPages - 2) { start = Math.max(totalPages - 3, 2); } for (let i = start; i <= end; i++) { if (i > 1 && i < totalPages) { range.push(i); } } if (currentPage < totalPages - 2) { range.push('...'); } if (totalPages > 1) { range.push(totalPages); } return range; }; const uniqueServices = [...new Set(billingData.map(item => item.service))]; const uniqueStatuses = ['completed', 'pending', 'failed']; const uniquecycles = ['monthly', 'yearly', 'one-time']; const resetFilters = () => { setFilters({ status: '', cycle: '', service: '' }); setSearchTerm(''); setCurrentPage(1); }; const handleFilterChange = (e) => { const { name, value } = e.target; setFilters(prev => ({ ...prev, [name]: value })); setCurrentPage(1); }; const handleSearch = (e) => { setSearchTerm(e.target.value); setCurrentPage(1); }; const getStatusColor = (status) => { switch (status) { case 'completed': return 'bg-green-100 text-green-800'; case 'pending': return 'bg-yellow-100 text-yellow-800'; case 'failed': return 'bg-red-100 text-red-800'; default: return 'bg-gray-100 text-gray-800'; } }; const formatDate = (dateString) => { if (!dateString) return 'N/A'; const options = { year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }; return new Date(dateString).toLocaleDateString(undefined, options); }; const formatCurrency = (amount) => { if (!amount) return '$0.00'; return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(parseFloat(amount)); }; if (loading || (isLoggedIn && sessionData?.user_type === 'admin' && dataLoading)) { return ; } if (error || apiError) return

Error: {error?.message || apiError.message}

; if (!isLoggedIn || sessionData?.user_type !== 'admin') { return

You are not authorized to view this page. Click Here to go to the homepage.

; } return (

Billing Management

{isDropdownOpen && ( )}
{/* Search and Filter Section */}
Showing {currentItems.length} of {filteredAndSortedData.length} results
{(filters.status || filters.cycle || filters.service || searchTerm) && (
)}
{currentItems.length > 0 ? ( currentItems.map((item) => ( )) ) : ( )}
requestSort('billing_id')} >
Billing ID {sortConfig.key === 'billing_id' && ( sortConfig.direction === 'asc' ? : )}
requestSort('service')} >
Service {sortConfig.key === 'service' && ( sortConfig.direction === 'asc' ? : )}
requestSort('name')} >
Name {sortConfig.key === 'name' && ( sortConfig.direction === 'asc' ? : )}
requestSort('user')} >
User {sortConfig.key === 'user' && ( sortConfig.direction === 'asc' ? : )}
requestSort('amount')} >
Amount {sortConfig.key === 'amount' && ( sortConfig.direction === 'asc' ? : )}
requestSort('status')}>
Status {sortConfig.key === 'status' && ( sortConfig.direction === 'asc' ? : )}
requestSort('service_status')}>
Ser.. Status {sortConfig.key === 'service_status' && ( sortConfig.direction === 'asc' ? : )}
requestSort('created_at')}>
Created At {sortConfig.key === 'created_at' && ( sortConfig.direction === 'asc' ? : )}
Actions
{item.billing_id} {item.service} {item.name ?? item.name} {item.user} {formatCurrency(item.amount)} {item.status.charAt(0).toUpperCase() + item.status.slice(1)} {item.service_status == 1 ? 'Active' : item.service_status == 0 ? 'Deactivate' : ''} {formatDate(item.created_at)} } fileName={`invoice_${item.billing_id}.pdf`} className="text-[#6d9e37] hover:text-green-600" > {({ loading }) => (loading ? '...' : )}
No records found
{/* Pagination */} {filteredAndSortedData.length > itemsPerPage && (
Page {currentPage} of {totalPages}
{ currentPage > 1 ? ( <> ) : '' } { getPaginationRange().map((item, index) => { if (item === '...') { return ( ... ); } return ( ); }) }
)} {/* Dialog for View/Edit/Create */} { if (!open) { setCurrentStep(1); setSelectedCustomer(null); } setDialogOpen(open); }}> {editMode ? (selectedItem ? 'Edit Billing' : 'Create New Billing') : 'Billing Details'} {editMode && !selectedItem && currentStep === 1 ? (
setCustomerSearchTerm(e.target.value)} className="pl-10 w-full px-3 py-2 border border-gray-300 rounded-md outline-none" />

Select Customer

{filteredCustomers.length > 0 ? (
{filteredCustomers.map(user => (
handleCustomerSelect(user)} className="group p-3 mx-2 border rounded-md cursor-pointer hover:bg-gray-100 hover:border-[#6d9e37] transition-border duration-700" >

{user.name}

{user.email}

SiliconId: {user.siliconId}
))}
) : (

No customers found

)}
) : editMode ? (
{!selectedItem && selectedCustomer && (

Customer Information

Name: {selectedCustomer.name}

Email: {selectedCustomer.email}

Silicon ID: {selectedCustomer.siliconId}

{!selectedItem && ( )}
)}
) : ( <>

Billing ID

{selectedItem?.billing_id}

Service

{selectedItem?.service}

User

{selectedItem?.user}

Silicon ID

{selectedItem?.siliconId}

cycle

{selectedItem?.cycle}

Amount

{formatCurrency(selectedItem?.amount)}

Status

{selectedItem?.status.charAt(0).toUpperCase() + selectedItem?.status.slice(1)}

Created At

{formatDate(selectedItem?.created_at)}

Updated At

{formatDate(selectedItem?.updated_at)}

Remarks

{selectedItem?.remarks}

} fileName={`invoice_${selectedItem?.billing_id}.pdf`} className="px-4 py-2 bg-green-600 text-white rounded hover:bg-green-700" > {({ loading }) => (loading ? 'Preparing PDF...' : 'Download PDF')} )}
); }