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
Error: {error?.message || apiError.message}
; if (!isLoggedIn || sessionData?.user_type !== 'admin') { returnYou are not authorized to view this page. Click Here to go to the homepage.
; } return (| 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)} |
|
| No records found | ||||||||