1032 lines
72 KiB
JavaScript
1032 lines
72 KiB
JavaScript
import React, { useState, useEffect } from 'react';
|
||
import {
|
||
TrendingUp,
|
||
CreditCard,
|
||
BarChart3,
|
||
Package,
|
||
ShoppingCart,
|
||
PieChart,
|
||
Users,
|
||
Bell,
|
||
DollarSign,
|
||
ArrowUpRight,
|
||
ArrowDownRight,
|
||
ArrowRight,
|
||
Search,
|
||
Download,
|
||
Filter,
|
||
Clock,
|
||
Shield,
|
||
Building,
|
||
AlertCircle
|
||
} from 'lucide-react';
|
||
|
||
export default function ReportIndex() {
|
||
const [activeTab, setActiveTab] = useState('Profit Report');
|
||
const [profitData, setProfitData] = useState(null);
|
||
const [expiryReminders, setExpiryReminders] = useState([]);
|
||
const [loading, setLoading] = useState(false);
|
||
const [searchQuery, setSearchQuery] = useState('');
|
||
const [selectedBranch, setSelectedBranch] = useState('');
|
||
const [startDate, setStartDate] = useState('');
|
||
const [endDate, setEndDate] = useState('');
|
||
const [branches, setBranches] = useState([]);
|
||
|
||
// Additional Report States
|
||
const [expenseData, setExpenseData] = useState([]);
|
||
const [collectionData, setCollectionData] = useState([]);
|
||
const [lowStockData, setLowStockData] = useState([]);
|
||
const [movementsData, setMovementsData] = useState([]);
|
||
const [salesData, setSalesData] = useState([]);
|
||
const [investmentData, setInvestmentData] = useState([]);
|
||
const [investmentSummary, setInvestmentSummary] = useState({ total_invested: 0, total_roi_returned: 0 });
|
||
const [salaryData, setSalaryData] = useState([]);
|
||
const [selectedItem, setSelectedItem] = useState(null);
|
||
|
||
const tabs = [
|
||
'Profit Report', 'Expense Report', 'Collection Report',
|
||
'Low Stock Report', 'Inventory Report', 'Product Sales',
|
||
'Investment Report', 'Salary Report', 'Expiry Reminders'
|
||
];
|
||
|
||
const isReceptionist = window.__APP_DATA__?.role === 'receptionist';
|
||
|
||
const buildQueryString = () => {
|
||
const params = new URLSearchParams();
|
||
if (selectedBranch && selectedBranch !== 'All Branches') params.append('branch_id', selectedBranch);
|
||
if (startDate) params.append('start_date', startDate);
|
||
if (endDate) params.append('end_date', endDate);
|
||
return params.toString();
|
||
};
|
||
|
||
useEffect(() => {
|
||
fetchMetadata();
|
||
}, []);
|
||
|
||
useEffect(() => {
|
||
if (activeTab === 'Profit Report') {
|
||
fetchProfitData();
|
||
} else if (activeTab === 'Expiry Reminders') {
|
||
fetchExpiryReminders();
|
||
} else if (activeTab === 'Expense Report') {
|
||
fetchExpenseReport();
|
||
} else if (activeTab === 'Collection Report') {
|
||
fetchCollectionReport();
|
||
} else if (activeTab === 'Low Stock Report') {
|
||
fetchLowStockReport();
|
||
} else if (activeTab === 'Inventory Report') {
|
||
fetchMovementsReport();
|
||
} else if (activeTab === 'Product Sales') {
|
||
fetchSalesData();
|
||
} else if (activeTab === 'Investment Report') {
|
||
fetchInvestmentReport();
|
||
} else if (activeTab === 'Salary Report') {
|
||
fetchSalaryReport();
|
||
}
|
||
}, [activeTab, selectedBranch, startDate, endDate]);
|
||
|
||
const fetchMetadata = async () => {
|
||
try {
|
||
const res = await fetch('/api/expense-branches');
|
||
const data = await res.json();
|
||
setBranches(data || []);
|
||
} catch (error) {
|
||
console.error('Error fetching branches:', error);
|
||
}
|
||
};
|
||
|
||
const fetchProfitData = async () => {
|
||
setLoading(true);
|
||
try {
|
||
const res = await fetch(`/api/reports/profit?${buildQueryString()}`);
|
||
const data = await res.json();
|
||
setProfitData(data);
|
||
} catch (error) {
|
||
console.error('Error fetching profit data:', error);
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
const fetchExpiryReminders = async () => {
|
||
setLoading(true);
|
||
try {
|
||
const res = await fetch(`/api/reports/expiry-reminders?${buildQueryString()}`);
|
||
const data = await res.json();
|
||
setExpiryReminders(data.reminders || []);
|
||
} catch (error) {
|
||
console.error('Error fetching expiry reminders:', error);
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
const fetchExpenseReport = async () => {
|
||
setLoading(true);
|
||
try {
|
||
const res = await fetch(`/api/expenses?${buildQueryString()}`);
|
||
const data = await res.json();
|
||
setExpenseData(data || []);
|
||
} catch (error) {
|
||
console.error('Error fetching expenses:', error);
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
const fetchCollectionReport = async () => {
|
||
setLoading(true);
|
||
try {
|
||
const res = await fetch(`/api/collections?${buildQueryString()}`);
|
||
const data = await res.json();
|
||
setCollectionData(data || []);
|
||
} catch (error) {
|
||
console.error('Error fetching collections:', error);
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
const fetchLowStockReport = async () => {
|
||
setLoading(true);
|
||
try {
|
||
const res = await fetch(`/api/inventory/products?${buildQueryString()}`);
|
||
const data = await res.json();
|
||
setLowStockData(data.filter(p => parseFloat(p.current_stock) <= parseFloat(p.reorder_level)) || []);
|
||
} catch (error) {
|
||
console.error('Error fetching low stock:', error);
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
const fetchMovementsReport = async () => {
|
||
setLoading(true);
|
||
try {
|
||
const res = await fetch(`/api/inventory/movements?${buildQueryString()}`);
|
||
const data = await res.json();
|
||
setMovementsData(data || []);
|
||
} catch (error) {
|
||
console.error('Error fetching movements:', error);
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
const fetchSalesData = async () => {
|
||
setLoading(true);
|
||
try {
|
||
const res = await fetch(`/api/inventory/sales?${buildQueryString()}`);
|
||
const data = await res.json();
|
||
setSalesData(data || []);
|
||
} catch (error) {
|
||
console.error('Error fetching sales:', error);
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
const fetchInvestmentReport = async () => {
|
||
setLoading(true);
|
||
try {
|
||
const res = await fetch(`/api/reports/investments?${buildQueryString()}`);
|
||
const data = await res.json();
|
||
console.log("INVESTMENT REPORT DATA:", data);
|
||
setInvestmentData(data.investors || []);
|
||
setInvestmentSummary({
|
||
total_invested: data.total_invested || 0,
|
||
total_roi_returned: data.total_roi_returned || 0
|
||
});
|
||
} catch (error) {
|
||
console.error('Error fetching investments:', error);
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
const fetchSalaryReport = async () => {
|
||
setLoading(true);
|
||
try {
|
||
const res = await fetch(`/api/expenses/salary-history?${buildQueryString()}`);
|
||
const data = await res.json();
|
||
setSalaryData(data || []);
|
||
} catch (error) {
|
||
console.error('Error fetching salary report:', error);
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
const comingSoon = (tabName) => (
|
||
<div className="flex flex-col items-center justify-center py-24 bg-white rounded-3xl border border-dashed border-gray-200 animate-in fade-in duration-500">
|
||
<div className="w-20 h-20 bg-gray-50 rounded-full flex items-center justify-center mb-6 text-gray-400">
|
||
<Clock size={40} />
|
||
</div>
|
||
<h3 className="text-2xl font-black text-gray-900 mb-2">{tabName}</h3>
|
||
<p className="text-gray-500 font-medium tracking-tight">This specialized reporting module is currently under development.</p>
|
||
</div>
|
||
);
|
||
|
||
return (
|
||
<>
|
||
<main className="max-w-[1700px] mx-auto p-4 md:p-10 space-y-10">
|
||
{/* Global Reports Title & Filters */}
|
||
<div className="flex flex-col md:flex-row md:items-end justify-between gap-6">
|
||
<div>
|
||
<h1 className="text-4xl font-black text-[#1B254B] tracking-tight">Global Reports</h1>
|
||
<p className="text-gray-500 font-bold mt-2">Comprehensive financial and operational oversight.</p>
|
||
</div>
|
||
|
||
<div className="flex flex-wrap items-center gap-4 bg-white p-3 rounded-2xl border border-[#E0E5F2] shadow-sm">
|
||
{!isReceptionist && (
|
||
<div className="min-w-[180px]">
|
||
<label className="block text-[9px] font-black text-[#A3AED0] uppercase tracking-widest mb-1.5 ml-1">Branch</label>
|
||
<select
|
||
className="w-full px-4 py-2.5 bg-[#F4F7FE] border-none rounded-xl text-sm font-bold text-[#1B254B] focus:ring-2 focus:ring-[#E31B1B]/20 outline-none appearance-none cursor-pointer"
|
||
value={selectedBranch}
|
||
onChange={(e) => setSelectedBranch(e.target.value)}
|
||
>
|
||
<option value="">All Branches</option>
|
||
{branches.map(b => (
|
||
<option key={b.id} value={b.id}>{b.name}</option>
|
||
))}
|
||
</select>
|
||
</div>
|
||
)}
|
||
<div className="min-w-[160px]">
|
||
<label className="block text-[9px] font-black text-[#A3AED0] uppercase tracking-widest mb-1.5 ml-1">From Date</label>
|
||
<input
|
||
type="date"
|
||
className="w-full px-4 py-2.5 bg-[#F4F7FE] border-none rounded-xl text-sm font-bold text-[#1B254B] focus:ring-2 focus:ring-[#E31B1B]/20 outline-none"
|
||
value={startDate}
|
||
onChange={(e) => setStartDate(e.target.value)}
|
||
/>
|
||
</div>
|
||
<div className="min-w-[160px]">
|
||
<label className="block text-[9px] font-black text-[#A3AED0] uppercase tracking-widest mb-1.5 ml-1">To Date</label>
|
||
<input
|
||
type="date"
|
||
className="w-full px-4 py-2.5 bg-[#F4F7FE] border-none rounded-xl text-sm font-bold text-[#1B254B] focus:ring-2 focus:ring-[#E31B1B]/20 outline-none"
|
||
value={endDate}
|
||
onChange={(e) => setEndDate(e.target.value)}
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Standard Tabs */}
|
||
<div className="flex items-center gap-8 border-b border-gray-200">
|
||
{tabs.map((tab) => {
|
||
const isActive = activeTab === tab;
|
||
return (
|
||
<button
|
||
key={tab}
|
||
onClick={() => setActiveTab(tab)}
|
||
className={`pb-4 text-sm font-bold transition-all relative ${
|
||
isActive
|
||
? 'text-[#E31B1B]'
|
||
: 'text-[#A3AED0] hover:text-[#1B254B]'
|
||
}`}
|
||
>
|
||
{tab}
|
||
{isActive && (
|
||
<div className="absolute bottom-0 left-0 w-full h-1 bg-[#E31B1B] rounded-t-full shadow-[0_-2px_10px_rgba(227,27,27,0.3)]" />
|
||
)}
|
||
</button>
|
||
);
|
||
})}
|
||
</div>
|
||
|
||
{activeTab === 'Profit Report' && (
|
||
<div className="space-y-10 animate-in slide-in-from-bottom-2 duration-500">
|
||
{/* Summary Cards */}
|
||
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||
<div className="bg-white p-8 rounded-[1.5rem] shadow-sm flex items-center justify-between group hover:shadow-lg transition-all border border-transparent hover:border-emerald-100">
|
||
<div>
|
||
<p className="text-sm font-bold text-[#A3AED0] mb-2 uppercase tracking-wider">Total Income</p>
|
||
<p className="text-2xl font-black text-[#1B254B] tracking-tight">{profitData?.total_credited?.toLocaleString() || '0.00'} AED</p>
|
||
<p className="text-xs font-bold text-[#A3AED0] mt-1">{profitData?.transactions?.filter(t => t.type === 'Income').length || 0} Records</p>
|
||
</div>
|
||
<div className="w-14 h-14 bg-emerald-50 rounded-full flex items-center justify-center text-emerald-500 group-hover:bg-emerald-500 group-hover:text-white transition-all shadow-sm">
|
||
<DollarSign size={24} />
|
||
</div>
|
||
</div>
|
||
<div className="bg-white p-8 rounded-[1.5rem] shadow-sm flex items-center justify-between group hover:shadow-lg transition-all border border-transparent hover:border-red-100">
|
||
<div>
|
||
<p className="text-sm font-bold text-[#A3AED0] mb-2 uppercase tracking-wider">Total Expenses</p>
|
||
<p className="text-2xl font-black text-[#1B254B] tracking-tight">{profitData?.total_expense?.toLocaleString() || '0.00'} AED</p>
|
||
<p className="text-xs font-bold text-[#A3AED0] mt-1">{profitData?.transactions?.filter(t => t.type === 'Expense').length || 0} Records</p>
|
||
</div>
|
||
<div className="w-14 h-14 bg-red-50 rounded-full flex items-center justify-center text-red-500 group-hover:bg-red-500 group-hover:text-white transition-all shadow-sm">
|
||
<ArrowDownRight size={24} />
|
||
</div>
|
||
</div>
|
||
<div className="bg-white p-8 rounded-[1.5rem] shadow-sm flex items-center justify-between group hover:shadow-lg transition-all border border-transparent hover:border-orange-100">
|
||
<div>
|
||
<p className="text-sm font-bold text-[#A3AED0] mb-2 uppercase tracking-wider">Net Profit</p>
|
||
<p className="text-2xl font-black text-[#1B254B] tracking-tight">{profitData?.net_profit?.toLocaleString() || '0.00'} AED</p>
|
||
</div>
|
||
<div className="w-14 h-14 bg-orange-50 rounded-full flex items-center justify-center text-orange-500 group-hover:bg-orange-500 group-hover:text-white transition-all shadow-sm">
|
||
<TrendingUp size={24} />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Detailed Breakdown Card */}
|
||
<div className="bg-white rounded-[2rem] shadow-sm border border-[#F4F7FE] overflow-hidden">
|
||
<div className="px-10 py-8 border-b border-[#F4F7FE] flex items-center justify-between">
|
||
<h3 className="text-xl font-black text-[#1B254B] tracking-tight">Detailed Breakdown</h3>
|
||
<button className="flex items-center gap-2 px-6 py-3 bg-[#00C566] text-white rounded-xl text-sm font-bold hover:shadow-lg hover:shadow-[#00C566]/20 transition-all active:scale-95">
|
||
<Download size={20} />
|
||
Export Data
|
||
</button>
|
||
</div>
|
||
|
||
<div className="overflow-x-auto">
|
||
<table className="w-full">
|
||
<thead>
|
||
<tr className="bg-[#F9FAFB]">
|
||
<th className="px-10 py-6 text-left text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">Date</th>
|
||
<th className="px-10 py-6 text-left text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">Transaction Type</th>
|
||
<th className="px-10 py-6 text-left text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">Details / Source</th>
|
||
<th className="px-10 py-6 text-left text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">Branch</th>
|
||
<th className="px-10 py-6 text-right text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">Amount</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody className="divide-y divide-[#F4F7FE]">
|
||
{profitData?.transactions?.length > 0 ? (
|
||
profitData.transactions.map((t, idx) => (
|
||
<tr key={idx} className="hover:bg-[#F4F7FE]/30 transition-colors group">
|
||
<td className="px-10 py-6">
|
||
<p className="text-sm font-bold text-[#1B254B]">{new Date(t.date).toLocaleDateString()}</p>
|
||
</td>
|
||
<td className="px-10 py-6">
|
||
<span className={`px-4 py-1.5 rounded-full text-[10px] font-black tracking-widest uppercase ${
|
||
t.type === 'Income' ? 'bg-emerald-50 text-emerald-600' : 'bg-red-50 text-red-600'
|
||
}`}>
|
||
{t.type}
|
||
</span>
|
||
</td>
|
||
<td className="px-10 py-6">
|
||
<p className="text-sm font-black text-[#1B254B]">{t.category}</p>
|
||
<p className="text-xs font-bold text-[#A3AED0] truncate max-w-xs">{t.description}</p>
|
||
</td>
|
||
<td className="px-10 py-6">
|
||
<div className="flex items-center gap-2">
|
||
<Building size={14} className="text-[#A3AED0]" />
|
||
<span className="text-sm font-bold text-[#1B254B]">{t.branch}</span>
|
||
</div>
|
||
</td>
|
||
<td className="px-10 py-6 text-right">
|
||
<div className="flex flex-col items-end gap-1">
|
||
<p className={`text-sm font-black ${
|
||
t.type === 'Income' ? 'text-emerald-500' : 'text-red-500'
|
||
}`}>
|
||
{t.type === 'Income' ? '+' : '-'}{t.amount.toLocaleString()} AED
|
||
</p>
|
||
{t.is_adjusted && (
|
||
<button
|
||
onClick={() => setSelectedItem(t)}
|
||
className="px-2 py-0.5 bg-amber-50 text-amber-600 rounded-md text-[9px] font-black uppercase tracking-wider border border-amber-100 hover:bg-amber-100 transition-colors"
|
||
>
|
||
Adjusted
|
||
</button>
|
||
)}
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
))
|
||
) : (
|
||
<tr>
|
||
<td colSpan="5" className="px-10 py-24 text-center">
|
||
<p className="text-lg font-black text-[#A3AED0] uppercase tracking-widest">No transaction data found</p>
|
||
</td>
|
||
</tr>
|
||
)}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{activeTab === 'Expiry Reminders' && (
|
||
<div className="space-y-8 animate-in slide-in-from-bottom-2 duration-500">
|
||
{/* Search Bar */}
|
||
<div className="grid grid-cols-1 gap-6 items-end">
|
||
<div>
|
||
<label className="block text-[10px] font-black text-[#A3AED0] uppercase tracking-widest mb-3 ml-1">Search</label>
|
||
<div className="relative group">
|
||
<Search className="absolute left-5 top-1/2 -translate-y-1/2 text-[#A3AED0] group-focus-within:text-[#E31B1B] transition-colors" size={20} />
|
||
<input
|
||
type="text"
|
||
placeholder="Search records..."
|
||
className="w-full pl-14 pr-6 py-4 bg-white border border-[#E0E5F2] rounded-2xl text-sm font-bold text-[#1B254B] focus:ring-2 focus:ring-[#E31B1B]/10 focus:border-[#E31B1B] transition-all outline-none shadow-sm"
|
||
value={searchQuery}
|
||
onChange={(e) => setSearchQuery(e.target.value)}
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Active Expiry Reminders Banner */}
|
||
<div className="bg-white border-2 border-amber-100 rounded-[2.5rem] p-8 shadow-sm group hover:shadow-lg transition-all border-l-[12px] border-l-amber-200">
|
||
<div className="flex items-center justify-between">
|
||
<div className="space-y-1">
|
||
<p className="text-xs font-black text-[#A3AED0] uppercase tracking-widest">Active Expiry Reminders</p>
|
||
<h4 className="text-4xl font-black text-[#1B254B]">{expiryReminders.length} Alerts</h4>
|
||
<p className="text-sm font-bold text-[#A3AED0]">{expiryReminders.length} Records found across branches</p>
|
||
</div>
|
||
<div className="w-16 h-16 bg-amber-50 rounded-full flex items-center justify-center text-amber-500 shadow-inner group-hover:scale-110 transition-transform">
|
||
<Bell size={28} />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Detailed Breakdown Card */}
|
||
<div className="bg-white rounded-[2.5rem] shadow-sm border border-[#F4F7FE] overflow-hidden">
|
||
<div className="px-10 py-8 border-b border-[#F4F7FE] flex items-center justify-between">
|
||
<h3 className="text-xl font-black text-[#1B254B] tracking-tight">Detailed Breakdown</h3>
|
||
<button className="flex items-center gap-2 px-6 py-3 bg-[#00C566] text-white rounded-xl text-sm font-bold hover:shadow-lg hover:shadow-[#00C566]/20 transition-all active:scale-95">
|
||
<Download size={20} />
|
||
Export Data
|
||
</button>
|
||
</div>
|
||
|
||
<div className="overflow-x-auto">
|
||
<table className="w-full">
|
||
<thead>
|
||
<tr className="bg-[#F9FAFB]">
|
||
<th className="px-10 py-6 text-left text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">Staff Name</th>
|
||
<th className="px-10 py-6 text-left text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">Branch</th>
|
||
<th className="px-10 py-6 text-left text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">Document Type</th>
|
||
<th className="px-10 py-6 text-left text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">Doc Number</th>
|
||
<th className="px-10 py-6 text-left text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">Reminder Started On</th>
|
||
<th className="px-10 py-6 text-left text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">Expiry Date</th>
|
||
<th className="px-10 py-6 text-left text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">Status</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody className="divide-y divide-[#F4F7FE]">
|
||
{expiryReminders.length > 0 ? (
|
||
expiryReminders.map((alert, idx) => (
|
||
<tr key={idx} className="hover:bg-[#F4F7FE]/50 transition-colors">
|
||
<td className="px-10 py-6">
|
||
<p className="text-sm font-black text-[#1B254B] uppercase tracking-tight">{alert.entity_name}</p>
|
||
</td>
|
||
<td className="px-10 py-6">
|
||
<p className="text-sm font-bold text-[#A3AED0]">{alert.branch_name}</p>
|
||
</td>
|
||
<td className="px-10 py-6">
|
||
<p className="text-xs font-black text-[#A3AED0] uppercase tracking-widest">{alert.document_name}</p>
|
||
</td>
|
||
<td className="px-10 py-6">
|
||
<p className="text-sm font-mono font-bold text-[#1B254B]">{alert.document_number || '---'}</p>
|
||
</td>
|
||
<td className="px-10 py-6">
|
||
<p className="text-sm font-bold text-[#A3AED0]">{alert.reminder_started_on || '---'}</p>
|
||
</td>
|
||
<td className="px-10 py-6">
|
||
<div className="flex items-center gap-2">
|
||
<Clock size={14} className="text-[#E31B1B]" />
|
||
<span className="text-sm font-black text-[#1B254B]">{new Date(alert.expiry_date).toLocaleDateString()}</span>
|
||
</div>
|
||
</td>
|
||
<td className="px-10 py-6">
|
||
<span className={`px-4 py-1.5 rounded-full text-[10px] font-black uppercase tracking-widest ${
|
||
alert.days_left <= 0 ? 'bg-red-100 text-[#E31B1B]' : 'bg-amber-100 text-amber-600'
|
||
}`}>
|
||
{alert.days_left <= 0 ? 'Expired' : 'Expiring Soon'}
|
||
</span>
|
||
</td>
|
||
</tr>
|
||
))
|
||
) : (
|
||
<tr>
|
||
<td colSpan="7" className="px-10 py-24 text-center">
|
||
<div className="flex flex-col items-center opacity-40">
|
||
<Shield size={64} className="text-[#A3AED0] mb-4" />
|
||
<p className="text-lg font-black text-[#A3AED0] uppercase tracking-widest">No Active Reminders</p>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
)}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{activeTab === 'Expense Report' && (
|
||
<div className="space-y-8 animate-in slide-in-from-bottom-2 duration-500">
|
||
{/* Summary Card */}
|
||
<div className="bg-white border-2 border-red-100 rounded-[2.5rem] p-8 shadow-sm group hover:shadow-lg transition-all border-l-[12px] border-l-red-200">
|
||
<div className="flex items-center justify-between">
|
||
<div className="space-y-1">
|
||
<p className="text-xs font-black text-[#A3AED0] uppercase tracking-widest">Total Expenses</p>
|
||
<h4 className="text-4xl font-black text-[#1B254B]">{expenseData.reduce((sum, e) => sum + parseFloat(e.amount || 0), 0).toLocaleString()} AED</h4>
|
||
<p className="text-sm font-bold text-[#A3AED0]">{expenseData.length} Expense Records</p>
|
||
</div>
|
||
<div className="w-16 h-16 bg-red-50 rounded-full flex items-center justify-center text-red-500 shadow-inner group-hover:scale-110 transition-transform">
|
||
<ArrowDownRight size={28} />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="bg-white rounded-[2rem] shadow-sm border border-[#F4F7FE] overflow-hidden">
|
||
<div className="px-10 py-8 border-b border-[#F4F7FE] flex items-center justify-between">
|
||
<h3 className="text-xl font-black text-[#1B254B]">Expense Records</h3>
|
||
</div>
|
||
<div className="overflow-x-auto">
|
||
<table className="w-full">
|
||
<thead>
|
||
<tr className="bg-[#F9FAFB]">
|
||
<th className="px-10 py-6 text-left text-[10px] font-black text-[#A3AED0] uppercase tracking-widest">Date</th>
|
||
<th className="px-10 py-6 text-left text-[10px] font-black text-[#A3AED0] uppercase tracking-widest">Category</th>
|
||
<th className="px-10 py-6 text-left text-[10px] font-black text-[#A3AED0] uppercase tracking-widest">Branch</th>
|
||
<th className="px-10 py-6 text-right text-[10px] font-black text-[#A3AED0] uppercase tracking-widest">Amount</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody className="divide-y divide-[#F4F7FE]">
|
||
{expenseData.map((e, idx) => (
|
||
<tr key={idx}>
|
||
<td className="px-10 py-6 text-sm font-bold text-[#1B254B]">{new Date(e.date).toLocaleDateString()}</td>
|
||
<td className="px-10 py-6 text-sm font-black text-[#1B254B]">{e.category?.name}</td>
|
||
<td className="px-10 py-6 text-sm font-bold text-[#A3AED0]">{e.branch?.name}</td>
|
||
<td className="px-10 py-6 text-right text-sm font-black text-red-500">{e.amount.toLocaleString()} AED</td>
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{activeTab === 'Collection Report' && (
|
||
<div className="space-y-8 animate-in slide-in-from-bottom-2 duration-500">
|
||
{/* Summary Card */}
|
||
<div className="bg-white border-2 border-emerald-100 rounded-[2.5rem] p-8 shadow-sm group hover:shadow-lg transition-all border-l-[12px] border-l-emerald-200">
|
||
<div className="flex items-center justify-between">
|
||
<div className="space-y-1">
|
||
<p className="text-xs font-black text-[#A3AED0] uppercase tracking-widest">Total Collections</p>
|
||
<h4 className="text-4xl font-black text-[#1B254B]">{collectionData.reduce((sum, c) => sum + parseFloat(c.amount || 0), 0).toLocaleString()} AED</h4>
|
||
<p className="text-sm font-bold text-[#A3AED0]">{collectionData.length} Collection Records</p>
|
||
</div>
|
||
<div className="w-16 h-16 bg-emerald-50 rounded-full flex items-center justify-center text-emerald-500 shadow-inner group-hover:scale-110 transition-transform">
|
||
<DollarSign size={28} />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="bg-white rounded-[2rem] shadow-sm border border-[#F4F7FE] overflow-hidden">
|
||
<div className="px-10 py-8 border-b border-[#F4F7FE] flex items-center justify-between">
|
||
<h3 className="text-xl font-black text-[#1B254B]">Collection Records</h3>
|
||
</div>
|
||
<div className="overflow-x-auto">
|
||
<table className="w-full">
|
||
<thead>
|
||
<tr className="bg-[#F9FAFB]">
|
||
<th className="px-10 py-6 text-left text-[10px] font-black text-[#A3AED0] uppercase tracking-widest">Date</th>
|
||
<th className="px-10 py-6 text-left text-[10px] font-black text-[#A3AED0] uppercase tracking-widest">Type</th>
|
||
<th className="px-10 py-6 text-left text-[10px] font-black text-[#A3AED0] uppercase tracking-widest">Branch</th>
|
||
<th className="px-10 py-6 text-right text-[10px] font-black text-[#A3AED0] uppercase tracking-widest">Amount</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody className="divide-y divide-[#F4F7FE]">
|
||
{collectionData.map((c, idx) => (
|
||
<tr key={idx}>
|
||
<td className="px-10 py-6 text-sm font-bold text-[#1B254B]">{new Date(c.date).toLocaleDateString()}</td>
|
||
<td className="px-10 py-6 text-sm font-black text-[#1B254B]">{c.type?.name}</td>
|
||
<td className="px-10 py-6 text-sm font-bold text-[#A3AED0]">{c.branch?.name}</td>
|
||
<td className="px-10 py-6 text-right text-sm font-black text-emerald-500">
|
||
<div className="flex flex-col items-end gap-1">
|
||
<span>{c.amount.toLocaleString()} AED</span>
|
||
{c.is_adjusted && (
|
||
<button
|
||
onClick={() => setSelectedItem({
|
||
transaction_id: c.transaction_id,
|
||
original_amount: c.original_amount,
|
||
amount: c.amount,
|
||
remarks: c.remarks
|
||
})}
|
||
className="px-2 py-0.5 bg-amber-50 text-amber-600 rounded-md text-[9px] font-black uppercase tracking-wider border border-amber-100 hover:bg-amber-100 transition-colors outline-none"
|
||
>
|
||
Adjusted
|
||
</button>
|
||
)}
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{activeTab === 'Low Stock Report' && (
|
||
<div className="space-y-8 animate-in slide-in-from-bottom-2 duration-500">
|
||
{/* Summary Card */}
|
||
<div className="bg-white border-2 border-rose-100 rounded-[2.5rem] p-8 shadow-sm group hover:shadow-lg transition-all border-l-[12px] border-l-rose-200">
|
||
<div className="flex items-center justify-between">
|
||
<div className="space-y-1">
|
||
<p className="text-xs font-black text-[#A3AED0] uppercase tracking-widest">Low Stock Items</p>
|
||
<h4 className="text-4xl font-black text-[#1B254B]">{lowStockData.length} Products</h4>
|
||
<p className="text-sm font-bold text-[#A3AED0]">Products below reorder level</p>
|
||
</div>
|
||
<div className="w-16 h-16 bg-rose-50 rounded-full flex items-center justify-center text-rose-500 shadow-inner group-hover:scale-110 transition-transform">
|
||
<AlertCircle size={28} />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="bg-white rounded-[2rem] shadow-sm border border-[#F4F7FE] overflow-hidden">
|
||
<div className="px-10 py-8 border-b border-[#F4F7FE] flex items-center justify-between">
|
||
<h3 className="text-xl font-black text-[#1B254B]">Low Stock Inventory</h3>
|
||
</div>
|
||
<div className="overflow-x-auto">
|
||
<table className="w-full">
|
||
<thead>
|
||
<tr className="bg-[#F9FAFB]">
|
||
<th className="px-10 py-6 text-left text-[10px] font-black text-[#A3AED0] uppercase tracking-widest">Product</th>
|
||
<th className="px-10 py-6 text-left text-[10px] font-black text-[#A3AED0] uppercase tracking-widest">Branch</th>
|
||
<th className="px-10 py-6 text-center text-[10px] font-black text-[#A3AED0] uppercase tracking-widest">Stock</th>
|
||
<th className="px-10 py-6 text-center text-[10px] font-black text-[#A3AED0] uppercase tracking-widest">Min Level</th>
|
||
<th className="px-10 py-6 text-right text-[10px] font-black text-[#A3AED0] uppercase tracking-widest">Status</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody className="divide-y divide-[#F4F7FE]">
|
||
{lowStockData.map((p, idx) => (
|
||
<tr key={idx}>
|
||
<td className="px-10 py-6 text-sm font-black text-[#1B254B] uppercase tracking-tight">{p.name}</td>
|
||
<td className="px-10 py-6 text-sm font-bold text-[#A3AED0]">{p.branch?.name}</td>
|
||
<td className="px-10 py-6 text-center text-sm font-black text-red-500 group-hover:scale-110 transition-transform">{p.current_stock}</td>
|
||
<td className="px-10 py-6 text-center text-sm font-bold text-gray-400">{p.reorder_level}</td>
|
||
<td className="px-10 py-6 text-right">
|
||
<span className="px-4 py-1.5 bg-red-50 text-red-600 rounded-full text-[10px] font-black uppercase tracking-widest border border-red-100 italic">
|
||
Low Stock
|
||
</span>
|
||
</td>
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{activeTab === 'Inventory Report' && (
|
||
<div className="space-y-8 animate-in slide-in-from-bottom-2 duration-500">
|
||
{/* Summary Card */}
|
||
<div className="bg-white border-2 border-indigo-100 rounded-[2.5rem] p-8 shadow-sm group hover:shadow-lg transition-all border-l-[12px] border-l-indigo-200">
|
||
<div className="flex items-center justify-between">
|
||
<div className="space-y-1">
|
||
<p className="text-xs font-black text-[#A3AED0] uppercase tracking-widest">Total Movements</p>
|
||
<h4 className="text-4xl font-black text-[#1B254B]">{movementsData.length} Records</h4>
|
||
<p className="text-sm font-bold text-[#A3AED0]">Stock Additions & Deductions</p>
|
||
</div>
|
||
<div className="w-16 h-16 bg-indigo-50 rounded-full flex items-center justify-center text-indigo-500 shadow-inner group-hover:scale-110 transition-transform">
|
||
<Package size={28} />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="bg-white rounded-[2rem] shadow-sm border border-[#F4F7FE] overflow-hidden">
|
||
<div className="px-10 py-8 border-b border-[#F4F7FE] flex items-center justify-between">
|
||
<div>
|
||
<h3 className="text-xl font-black text-[#1B254B]">Inventory Alerts & Movements</h3>
|
||
<p className="text-xs text-gray-500 font-bold mt-1">Global audit log of all stock adjustments and alerts.</p>
|
||
</div>
|
||
<button className="flex items-center gap-2 px-6 py-3 bg-[#00C566] text-white rounded-xl text-sm font-bold hover:shadow-lg hover:shadow-[#00C566]/20 transition-all active:scale-95">
|
||
<Download size={20} />
|
||
Export
|
||
</button>
|
||
</div>
|
||
<div className="overflow-x-auto">
|
||
<table className="w-full">
|
||
<thead>
|
||
<tr className="bg-[#F9FAFB]">
|
||
<th className="px-10 py-6 text-left text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">Date</th>
|
||
<th className="px-10 py-6 text-left text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">Product</th>
|
||
<th className="px-10 py-6 text-left text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">Branch</th>
|
||
<th className="px-10 py-6 text-left text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">Movement Type</th>
|
||
<th className="px-10 py-6 text-center text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">Change</th>
|
||
<th className="px-10 py-6 text-center text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">Stock After</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody className="divide-y divide-[#F4F7FE]">
|
||
{movementsData.length > 0 ? (
|
||
movementsData.map((m, idx) => (
|
||
<tr key={idx} className="hover:bg-[#F4F7FE]/30 transition-colors">
|
||
<td className="px-10 py-6 text-sm font-bold text-[#1B254B]">{new Date(m.date).toLocaleDateString()}</td>
|
||
<td className="px-10 py-6">
|
||
<p className="text-sm font-black text-[#1B254B] uppercase tracking-tight">{m.product_name}</p>
|
||
<p className="text-[10px] font-black text-[#A3AED0] uppercase tracking-widest mt-0.5">SKU: {m.sku}</p>
|
||
</td>
|
||
<td className="px-10 py-6 text-sm font-bold text-[#A3AED0]">{m.branch}</td>
|
||
<td className="px-10 py-6 text-sm font-bold text-[#1B254B] italic">{m.reason}</td>
|
||
<td className="px-10 py-6 text-center">
|
||
<span className={`px-3 py-1 rounded-lg text-xs font-black ${
|
||
m.change >= 0
|
||
? 'bg-emerald-50 text-emerald-600 border border-emerald-100'
|
||
: 'bg-red-50 text-red-600 border border-red-100'
|
||
}`}>
|
||
{m.change >= 0 ? '+' : ''}{m.change}
|
||
</span>
|
||
</td>
|
||
<td className="px-10 py-6 text-center text-sm font-black text-[#1B254B]">{m.new_stock}</td>
|
||
</tr>
|
||
))
|
||
) : (
|
||
<tr>
|
||
<td colSpan="6" className="px-10 py-24 text-center">
|
||
<p className="text-lg font-black text-[#A3AED0] uppercase tracking-widest">No inventory data found</p>
|
||
</td>
|
||
</tr>
|
||
)}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{activeTab === 'Product Sales' && (
|
||
<div className="space-y-8 animate-in slide-in-from-bottom-2 duration-500">
|
||
{/* Summary Card */}
|
||
<div className="bg-white border-2 border-emerald-100 rounded-[2.5rem] p-8 shadow-sm group hover:shadow-lg transition-all border-l-[12px] border-l-emerald-200">
|
||
<div className="flex items-center justify-between">
|
||
<div className="space-y-1">
|
||
<p className="text-xs font-black text-[#A3AED0] uppercase tracking-widest">Total Sales</p>
|
||
<h4 className="text-4xl font-black text-[#1B254B]">{salesData.reduce((sum, s) => sum + parseFloat(s.total_amount || 0), 0).toLocaleString()} AED</h4>
|
||
<p className="text-sm font-bold text-[#A3AED0]">{salesData.length} Sales Transactions</p>
|
||
</div>
|
||
<div className="w-16 h-16 bg-emerald-50 rounded-full flex items-center justify-center text-emerald-500 shadow-inner group-hover:scale-110 transition-transform">
|
||
<ShoppingCart size={28} />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="bg-white rounded-[2rem] shadow-sm border border-[#F4F7FE] overflow-hidden">
|
||
<div className="px-10 py-8 border-b border-[#F4F7FE] flex items-center justify-between">
|
||
<h3 className="text-xl font-black text-[#1B254B]">Sales Records</h3>
|
||
<button className="flex items-center gap-2 px-6 py-3 bg-[#00C566] text-white rounded-xl text-sm font-bold hover:shadow-lg hover:shadow-[#00C566]/20 transition-all active:scale-95">
|
||
<Download size={20} />
|
||
Export
|
||
</button>
|
||
</div>
|
||
<div className="overflow-x-auto">
|
||
<table className="w-full">
|
||
<thead>
|
||
<tr className="bg-[#F9FAFB]">
|
||
<th className="px-10 py-6 text-left text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">Date</th>
|
||
<th className="px-10 py-6 text-left text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">Transaction ID</th>
|
||
<th className="px-10 py-6 text-left text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">Branch</th>
|
||
<th className="px-10 py-6 text-left text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">Method</th>
|
||
<th className="px-10 py-6 text-right text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">Sub-Total</th>
|
||
<th className="px-10 py-6 text-right text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">VAT (5%)</th>
|
||
<th className="px-10 py-6 text-right text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">Total Amount</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody className="divide-y divide-[#F4F7FE]">
|
||
{salesData.length > 0 ? (
|
||
salesData.map((s, idx) => (
|
||
<tr key={idx} className="hover:bg-[#F4F7FE]/30 transition-colors">
|
||
<td className="px-10 py-6 text-sm font-bold text-[#1B254B]">{new Date(s.date).toLocaleDateString()}</td>
|
||
<td className="px-10 py-6 text-[10px] font-black text-[#A3AED0] tracking-widest">{s.transaction_id}</td>
|
||
<td className="px-10 py-6 text-sm font-bold text-[#A3AED0]">{s.branch?.name}</td>
|
||
<td className="px-10 py-6 text-sm font-bold text-[#1B254B]">{s.payment_method}</td>
|
||
<td className="px-10 py-6 text-right text-xs font-black text-[#A3AED0]">{parseFloat(s.subtotal_amount || 0).toFixed(2)} AED</td>
|
||
<td className="px-10 py-6 text-right text-xs font-black text-[#A3AED0]">{parseFloat(s.vat_amount || 0).toFixed(2)} AED</td>
|
||
<td className="px-10 py-6 text-right text-sm font-black text-emerald-500">{parseFloat(s.total_amount).toLocaleString()} AED</td>
|
||
</tr>
|
||
))
|
||
) : (
|
||
<tr>
|
||
<td colSpan="7" className="px-10 py-24 text-center">
|
||
<p className="text-lg font-black text-[#A3AED0] uppercase tracking-widest">No sales records found</p>
|
||
</td>
|
||
</tr>
|
||
)}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{activeTab === 'Investment Report' && (
|
||
<div className="space-y-8 animate-in slide-in-from-bottom-2 duration-500">
|
||
{/* Summary Cards */}
|
||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||
<div className="bg-white border-2 border-blue-100 rounded-[2.5rem] p-8 shadow-sm group hover:shadow-lg transition-all border-l-[12px] border-l-blue-200 cursor-default">
|
||
<div className="flex items-center justify-between">
|
||
<div className="space-y-1">
|
||
<p className="text-xs font-black text-[#A3AED0] uppercase tracking-widest">Total Active Investment</p>
|
||
<h4 className="text-4xl font-black text-[#1B254B]">{(investmentSummary?.total_invested || 0).toLocaleString()} AED</h4>
|
||
<p className="text-sm font-bold text-[#A3AED0]">{investmentData?.length || 0} Investors</p>
|
||
</div>
|
||
<div className="w-16 h-16 bg-blue-50 rounded-full flex items-center justify-center text-blue-500 shadow-inner group-hover:scale-110 transition-transform">
|
||
<PieChart size={28} />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="bg-white border-2 border-emerald-100 rounded-[2.5rem] p-8 shadow-sm group hover:shadow-lg transition-all border-l-[12px] border-l-emerald-200 cursor-default">
|
||
<div className="flex items-center justify-between">
|
||
<div className="space-y-1">
|
||
<p className="text-xs font-black text-[#A3AED0] uppercase tracking-widest">Total ROI Returned</p>
|
||
<h4 className="text-4xl font-black text-emerald-500">{(investmentSummary?.total_roi_returned || 0).toLocaleString()} AED</h4>
|
||
<p className="text-sm font-bold text-[#A3AED0]">Total Payouts Made</p>
|
||
</div>
|
||
<div className="w-16 h-16 bg-emerald-50 rounded-full flex items-center justify-center text-emerald-500 shadow-inner group-hover:scale-110 transition-transform">
|
||
<TrendingUp size={28} />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="bg-white rounded-[2rem] shadow-sm border border-[#F4F7FE] overflow-hidden">
|
||
<div className="px-10 py-8 border-b border-[#F4F7FE] flex items-center justify-between">
|
||
<div>
|
||
<h3 className="text-xl font-black text-[#1B254B]">Investment Performance</h3>
|
||
<p className="text-xs text-gray-500 font-bold mt-1">Overview of investor contributions, returns and pending payouts.</p>
|
||
</div>
|
||
<button className="flex items-center gap-2 px-6 py-3 bg-[#00C566] text-white rounded-xl text-sm font-bold hover:shadow-lg hover:shadow-[#00C566]/20 transition-all active:scale-95">
|
||
<Download size={20} />
|
||
Export
|
||
</button>
|
||
</div>
|
||
<div className="overflow-x-auto">
|
||
<table className="w-full">
|
||
<thead>
|
||
<tr className="bg-[#F9FAFB]">
|
||
<th className="px-10 py-6 text-left text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">Investor Name</th>
|
||
<th className="px-10 py-6 text-left text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">Investment Date</th>
|
||
<th className="px-10 py-6 text-right text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">Invested Amount</th>
|
||
<th className="px-10 py-6 text-right text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">Returns Earned</th>
|
||
<th className="px-10 py-6 text-right text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">Pending to Pay</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody className="divide-y divide-[#F4F7FE]">
|
||
{investmentData.length > 0 ? (
|
||
investmentData.map((inv, idx) => (
|
||
<tr key={idx} className="hover:bg-[#F4F7FE]/30 transition-colors">
|
||
<td className="px-10 py-6">
|
||
<p className="text-sm font-black text-[#1B254B] uppercase tracking-tight">{inv.investor_name}</p>
|
||
<p className="text-[10px] font-black text-[#A3AED0] uppercase tracking-widest mt-0.5">
|
||
{inv.roi_type === 'Percentage' ? `${inv.roi_value}%` : `${inv.roi_value} AED`} {inv.roi_period}
|
||
</p>
|
||
</td>
|
||
<td className="px-10 py-6 text-sm font-bold text-[#1B254B]">{new Date(inv.investment_date).toLocaleDateString()}</td>
|
||
<td className="px-10 py-6 text-right text-sm font-black text-[#1B254B]">{parseFloat(inv.investment_amount).toLocaleString()} AED</td>
|
||
<td className="px-10 py-6 text-right text-sm font-black text-emerald-500">{parseFloat(inv.returns_earned).toLocaleString()} AED</td>
|
||
<td className="px-10 py-6 text-right text-sm font-black text-amber-500">{parseFloat(inv.total_pending).toLocaleString()} AED</td>
|
||
</tr>
|
||
))
|
||
) : (
|
||
<tr>
|
||
<td colSpan="5" className="px-10 py-24 text-center">
|
||
<p className="text-lg font-black text-[#A3AED0] uppercase tracking-widest">No investments found</p>
|
||
</td>
|
||
</tr>
|
||
)}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{activeTab === 'Salary Report' && (
|
||
<div className="space-y-8 animate-in slide-in-from-bottom-2 duration-500">
|
||
{/* Summary Card */}
|
||
<div className="bg-white border-2 border-violet-100 rounded-[2.5rem] p-8 shadow-sm group hover:shadow-lg transition-all border-l-[12px] border-l-violet-200">
|
||
<div className="flex items-center justify-between">
|
||
<div className="space-y-1">
|
||
<p className="text-xs font-black text-[#A3AED0] uppercase tracking-widest">Total Released Salary</p>
|
||
<h4 className="text-4xl font-black text-[#1B254B]">{salaryData.reduce((sum, s) => sum + parseFloat(s.amount || 0), 0).toLocaleString()} AED</h4>
|
||
<p className="text-sm font-bold text-[#A3AED0]">{salaryData.length} Payout Batches</p>
|
||
</div>
|
||
<div className="w-16 h-16 bg-violet-50 rounded-full flex items-center justify-center text-violet-500 shadow-inner group-hover:scale-110 transition-transform">
|
||
<Users size={28} />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="bg-white rounded-[2rem] shadow-sm border border-[#F4F7FE] overflow-hidden">
|
||
<div className="px-10 py-8 border-b border-[#F4F7FE] flex items-center justify-between">
|
||
<div>
|
||
<h3 className="text-xl font-black text-[#1B254B]">Salary Release History</h3>
|
||
<p className="text-xs text-gray-500 font-bold mt-1">Overview of all individual and bulk salary payouts.</p>
|
||
</div>
|
||
<button className="flex items-center gap-2 px-6 py-3 bg-[#00C566] text-white rounded-xl text-sm font-bold hover:shadow-lg hover:shadow-[#00C566]/20 transition-all active:scale-95">
|
||
<Download size={20} />
|
||
Export
|
||
</button>
|
||
</div>
|
||
<div className="overflow-x-auto">
|
||
<table className="w-full">
|
||
<thead>
|
||
<tr className="bg-[#F9FAFB]">
|
||
<th className="px-10 py-6 text-left text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">Date</th>
|
||
<th className="px-10 py-6 text-left text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">Batch/Staff Details</th>
|
||
<th className="px-10 py-6 text-left text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">Branch</th>
|
||
<th className="px-10 py-6 text-left text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">Remarks</th>
|
||
<th className="px-10 py-6 text-right text-[10px] font-black text-[#A3AED0] uppercase tracking-widest border-b border-[#F4F7FE]">Total Amount</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody className="divide-y divide-[#F4F7FE]">
|
||
{salaryData.length > 0 ? (
|
||
salaryData.map((s, idx) => (
|
||
<tr key={idx} className="hover:bg-[#F4F7FE]/30 transition-colors">
|
||
<td className="px-10 py-6 text-sm font-bold text-[#1B254B]">{new Date(s.date).toLocaleDateString()}</td>
|
||
<td className="px-10 py-6">
|
||
<div className="flex items-center gap-3">
|
||
<div className={`w-10 h-10 rounded-xl flex items-center justify-center ${s.is_bulk ? 'bg-blue-50 text-blue-600' : 'bg-[#F4F7FE] text-[#1B254B]'}`}>
|
||
{s.is_bulk ? <Users size={18} /> : <Users size={18} />}
|
||
</div>
|
||
<div>
|
||
<p className="text-sm font-black text-[#1B254B] uppercase tracking-tight">{s.is_bulk ? 'Bulk Release' : 'Individual Release'}</p>
|
||
<p className="text-[10px] font-black text-[#A3AED0] uppercase tracking-widest mt-0.5">{s.count} Staff {s.count === 1 ? 'Member' : 'Members'}</p>
|
||
</div>
|
||
</div>
|
||
</td>
|
||
<td className="px-10 py-6 text-sm font-bold text-[#A3AED0]">{s.branch}</td>
|
||
<td className="px-10 py-6 text-sm font-bold text-[#1B254B] italic line-clamp-1">{s.remarks}</td>
|
||
<td className="px-10 py-6 text-right text-sm font-black text-emerald-500">{parseFloat(s.amount).toLocaleString()} AED</td>
|
||
</tr>
|
||
))
|
||
) : (
|
||
<tr>
|
||
<td colSpan="5" className="px-10 py-24 text-center">
|
||
<p className="text-lg font-black text-[#A3AED0] uppercase tracking-widest">No salary records found</p>
|
||
</td>
|
||
</tr>
|
||
)}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{activeTab !== 'Profit Report' && activeTab !== 'Expiry Reminders' &&
|
||
activeTab !== 'Expense Report' && activeTab !== 'Collection Report' &&
|
||
activeTab !== 'Low Stock Report' && activeTab !== 'Inventory Report' &&
|
||
activeTab !== 'Product Sales' && activeTab !== 'Investment Report' &&
|
||
activeTab !== 'Salary Report' && comingSoon(activeTab)}
|
||
|
||
{/* Details Modal */}
|
||
{selectedItem && (
|
||
<div className="fixed inset-0 bg-[#1B254B]/40 backdrop-blur-sm z-[100] flex items-center justify-center p-4 animate-in fade-in duration-300">
|
||
<div className="bg-white rounded-[2.5rem] w-full max-w-lg overflow-hidden shadow-2xl animate-in zoom-in-95 duration-300">
|
||
<div className="p-8 border-b border-gray-100 flex items-center justify-between bg-gray-50/50">
|
||
<div>
|
||
<h3 className="text-xl font-black text-[#1B254B]">Adjustment Details</h3>
|
||
<p className="text-[10px] font-black text-[#A3AED0] uppercase tracking-widest mt-1">Transaction: #{selectedItem.transaction_id || 'N/A'}</p>
|
||
</div>
|
||
<button
|
||
onClick={() => setSelectedItem(null)}
|
||
className="p-2 hover:bg-white rounded-xl transition-all text-[#A3AED0] hover:text-[#1B254B]"
|
||
>
|
||
<span className="font-black text-xl">×</span>
|
||
</button>
|
||
</div>
|
||
<div className="p-8 space-y-8">
|
||
<div className="grid grid-cols-2 gap-8">
|
||
<div className="space-y-1">
|
||
<p className="text-[10px] font-black text-[#A3AED0] uppercase tracking-widest">Original Total</p>
|
||
<p className="text-lg font-black text-gray-400 line-through">{(selectedItem.original_amount || 0).toLocaleString('en-AE', { minimumFractionDigits: 2 })} AED</p>
|
||
</div>
|
||
<div className="space-y-1">
|
||
<p className="text-[10px] font-black text-emerald-600 uppercase tracking-widest">Adjusted Total</p>
|
||
<p className="text-lg font-black text-[#22C55E]">{(parseFloat(selectedItem.amount) || 0).toLocaleString('en-AE', { minimumFractionDigits: 2 })} AED</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="space-y-2 p-6 bg-amber-50/50 rounded-2xl border border-amber-100">
|
||
<p className="text-[10px] font-black text-amber-600 uppercase tracking-widest block mb-2">Remarks / Reason</p>
|
||
<p className="text-sm font-bold text-[#1B254B] leading-relaxed italic">
|
||
"{selectedItem.remarks || 'No remarks provided for this adjustment.'}"
|
||
</p>
|
||
</div>
|
||
|
||
<button
|
||
onClick={() => setSelectedItem(null)}
|
||
className="w-full py-4 bg-[#1B254B] text-white rounded-2xl font-black text-xs uppercase tracking-[0.2em] hover:bg-[#2B3674] transition-all shadow-lg shadow-[#1B254B]/10"
|
||
>
|
||
Close Details
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</main>
|
||
</>
|
||
);
|
||
}
|