feat: complete security overhaul with JWT backend and authenticated frontend API

This commit is contained in:
Shanmuga Krishnan S M
2026-04-28 14:31:01 +05:30
28 changed files with 7077 additions and 21 deletions

View File

@@ -75,8 +75,9 @@ const Bills: React.FC = () => {
};
const filteredOrders = orders.filter(order => {
const matchesSearch = order.purchaseId.toLowerCase().includes(searchTerm.toLowerCase()) ||
order.referenceId?.toLowerCase().includes(searchTerm.toLowerCase());
const search = (searchTerm || '').toLowerCase();
const matchesSearch = (order.purchaseId || '').toLowerCase().includes(search) ||
(order.referenceId || '').toLowerCase().includes(search);
const matchesStatus = statusFilter === 'All' || order.status === statusFilter;
return matchesSearch && matchesStatus;
});

View File

@@ -44,13 +44,13 @@ const Login = () => {
const user = await response.json();
// Strict Role Validation
if (user.role.toLowerCase() !== role) {
alert(`Access Denied: You are trying to login as ${role.toUpperCase()}, but your credentials belong to a ${user.role.toUpperCase()} account.`);
if ((user.role || '').toLowerCase() !== (role || '').toLowerCase()) {
alert(`Access Denied: You are trying to login as ${(role || '').toUpperCase()}, but your credentials belong to a ${(user.role || '').toUpperCase()} account.`);
return;
}
sessionStorage.setItem('isLoggedIn', 'true');
sessionStorage.setItem('userRole', user.role.toLowerCase());
sessionStorage.setItem('userRole', (user.role || '').toLowerCase());
sessionStorage.setItem('userPermissions', JSON.stringify(user.permissions || []));
// Persist user profile + JWT token for authenticated API calls

View File

@@ -194,7 +194,11 @@ const Managers = () => {
</tr>
</thead>
<tbody className="divide-y divide-[#e2e8f0]">
{managers.filter(m => m.name.toLowerCase().includes(searchQuery.toLowerCase()) || m.email.toLowerCase().includes(searchQuery.toLowerCase())).map((manager) => (
{managers.filter(m => {
const query = (searchQuery || '').toLowerCase();
return (m.name || '').toLowerCase().includes(query) ||
(m.email || '').toLowerCase().includes(query);
}).map((manager) => (
<tr key={manager.id} className="hover:bg-gray-50/50 transition-colors">
<td className="px-6 py-5">
<div className="flex items-center gap-3">

View File

@@ -162,7 +162,7 @@ const PurchaseAnalytics = () => {
};
const filteredAnalytics = analytics.filter(item => {
const matchesSearch = item.product.toLowerCase().includes(searchTerm.toLowerCase());
const matchesSearch = (item.product || '').toLowerCase().includes((searchTerm || '').toLowerCase());
const matchesFilter = filterType === 'all' || item.trend === filterType;
return matchesSearch && matchesFilter;
});

View File

@@ -298,7 +298,7 @@ const Purchases: React.FC = () => {
<Loader2 className="animate-spin inline-block mr-2" /> Loading records...
</td>
</tr>
) : orders.filter(o => o.purchaseId.toLowerCase().includes(searchTerm.toLowerCase())).map((order) => (
) : orders.filter(o => (o.purchaseId || '').toLowerCase().includes((searchTerm || '').toLowerCase())).map((order) => (
<tr key={order.id} className="hover:bg-gray-50/50 transition-all font-medium">
<td className="px-6 py-4 text-sm font-bold text-[#231651]">{order.purchaseId}</td>
<td className="px-6 py-4 text-sm text-[#64748b]">{new Date(order.date).toLocaleDateString()}</td>

View File

@@ -110,10 +110,11 @@ const Staff = () => {
}
};
const filteredStaff = staffList.filter(s =>
s.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
s.email.toLowerCase().includes(searchQuery.toLowerCase())
);
const filteredStaff = staff.filter(s => {
const query = (searchQuery || '').toLowerCase();
return (s.name || '').toLowerCase().includes(query) ||
(s.email || '').toLowerCase().includes(query);
});
return (
<div className="p-8 space-y-8 bg-[#f8fafc] min-h-screen font-inter">

View File

@@ -61,11 +61,11 @@ const Terminals = () => {
}
};
const filteredTerminals = terminals.filter(t =>
t.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
t.location.toLowerCase().includes(searchQuery.toLowerCase())
);
const filteredTerminals = terminals.filter(t => {
const query = (searchQuery || '').toLowerCase();
return (t.name || '').toLowerCase().includes(query) ||
(t.location || '').toLowerCase().includes(query);
});
return (
<div className="p-8 max-w-7xl mx-auto space-y-8 font-inter">
{/* Header Section */}

View File

@@ -135,10 +135,13 @@ const Vendors: React.FC = () => {
}
};
const filteredVendors = vendors.filter(v =>
v.name?.toLowerCase().includes(searchTerm.toLowerCase()) ||
v.companyName?.toLowerCase().includes(searchTerm.toLowerCase())
);
const filteredVendors = vendors.filter(v => {
if (!v) return false;
const search = (searchTerm || '').toLowerCase();
const name = (v.name || '').toLowerCase();
const company = (v.companyName || '').toLowerCase();
return name.includes(search) || company.includes(search);
});
return (
<>