admin dashboard completed
This commit is contained in:
parent
3c0665a909
commit
e979c7a488
@ -78,7 +78,7 @@ const AdminHeader = () => {
|
|||||||
<img src={logoSrc} alt="FCSC" className="w-[140px] h-[44px] " />
|
<img src={logoSrc} alt="FCSC" className="w-[140px] h-[44px] " />
|
||||||
<nav className="flex-1 flex justify-end items-center gap-6 xl:gap-8 text-[14px] leading-5 ml-auto ">
|
<nav className="flex-1 flex justify-end items-center gap-6 xl:gap-8 text-[14px] leading-5 ml-auto ">
|
||||||
<NavItem to="/admin/dashboard" end label="Dashboard" iconActive={dashboardIconActiveSrc} iconInactive={dashboardIconInactiveSrc} />
|
<NavItem to="/admin/dashboard" end label="Dashboard" iconActive={dashboardIconActiveSrc} iconInactive={dashboardIconInactiveSrc} />
|
||||||
<NavItem to="/admin/validations" label="Manage Submissions" iconActive={checkCircleActiveSrc} iconInactive={manageSubmissionInactiveSrc} />
|
<NavItem to="/admin/validations" label="Submissions" iconActive={checkCircleActiveSrc} iconInactive={manageSubmissionInactiveSrc} />
|
||||||
<NavItem to="/admin/configuration" label="Configuration" iconActive={configActiveSrc} iconInactive={configInactiveSrc} />
|
<NavItem to="/admin/configuration" label="Configuration" iconActive={configActiveSrc} iconInactive={configInactiveSrc} />
|
||||||
<NavItem to="/admin/users" label="Users" iconActive={userActiveSrc} iconInactive={userInactiveSrc} />
|
<NavItem to="/admin/users" label="Users" iconActive={userActiveSrc} iconInactive={userInactiveSrc} />
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
@ -1,16 +1,16 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
const StatCard = ({ icon = null, label, value, width = 200.4 }) => {
|
const StatCard = ({ icon = null, label, value, tooltipText, width = 200.4 }) => {
|
||||||
const resolvedWidth = typeof width === 'number' ? `${width}px` : width;
|
const resolvedWidth = typeof width === 'number' ? `${width}px` : width;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="flex flex-col items-center justify-center rounded-[8px] border border-[#E3E5E8] bg-white px-5 py-5 shadow-[0_8px_20px_rgba(42,47,66,0.06)]"
|
className="relative group flex flex-col items-center justify-center rounded-[8px] border border-[#E3E5E8] bg-white px-5 py-5 shadow-[0_8px_20px_rgba(42,47,66,0.06)]"
|
||||||
style={{ width: resolvedWidth, minHeight: '120px' }}
|
style={{ width: resolvedWidth, minHeight: '120px' }}
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-center gap-2">
|
<div className="flex items-center justify-center gap-2 whitespace-nowrap">
|
||||||
{icon && <div className="flex items-center justify-center w-5 h-5">{icon}</div>}
|
{icon && <div className="flex items-center justify-center w-5 h-5">{icon}</div>}
|
||||||
<span className="text-[15px] font-medium text-[#5F646D] leading-[22px] text-center">
|
<span className="text-[15px] font-medium text-[#5F646D] leading-[22px] text-center truncate">
|
||||||
{label}
|
{label}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@ -18,6 +18,13 @@ const StatCard = ({ icon = null, label, value, width = 200.4 }) => {
|
|||||||
<span className="mt-2 text-[24px] font-semibold text-[#232528] leading-[30px] text-center">
|
<span className="mt-2 text-[24px] font-semibold text-[#232528] leading-[30px] text-center">
|
||||||
{value}
|
{value}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
{tooltipText && (
|
||||||
|
<div className="absolute bottom-[-58px] left-1/2 -translate-x-1/2 z-20 hidden w-[220px] text-center rounded-md bg-black text-white text-xs px-3 py-2 group-hover:block">
|
||||||
|
{tooltipText}
|
||||||
|
<div className="absolute -top-1 left-1/2 -translate-x-1/2 w-2 h-2 bg-black rotate-45"></div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,125 +1,68 @@
|
|||||||
import React, { useState, useMemo } from 'react';
|
import React, { useState, useEffect, useMemo } from 'react';
|
||||||
import Table from '@/components/common/Table';
|
import Table from '@/components/common/Table';
|
||||||
|
import apiClient from '../../services/api/apiClient.js';
|
||||||
|
import { CheckCircle2, XCircle, Eye } from 'lucide-react';
|
||||||
|
|
||||||
const searchIconSrc = '/assets/images/material-symbols_search-rounded.svg';
|
const SubmissionTable = ({ selectedQuarter, selectedYear }) => {
|
||||||
const checkCircleSrc = '/assets/images/check-circle-fill 1.svg';
|
const [data, setData] = useState([]);
|
||||||
const xCircleSrc = '/assets/images/warning-circle-fill 1.svg';
|
const [loading, setLoading] = useState(true);
|
||||||
const eyeIconSrc = '/assets/images/User-active.svg';
|
useEffect(() => {
|
||||||
|
const fetchDashboardData = async () => {
|
||||||
|
try {
|
||||||
|
setLoading(true);
|
||||||
|
const response = await apiClient.get('/admin_dashboard');
|
||||||
|
const result = response?.data;
|
||||||
|
if (result?.status === 'success') {
|
||||||
|
setData(result.recent_submissions || []);
|
||||||
|
} else {
|
||||||
|
console.error('Error: Invalid response', result);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching recent submissions:', error);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fetchDashboardData();
|
||||||
|
}, []);
|
||||||
|
|
||||||
const submissions = [
|
|
||||||
{
|
|
||||||
establishment: 'CASCADE MARINE FOODS LLC',
|
|
||||||
emirate: 'Sharjah',
|
|
||||||
productCount: '5',
|
|
||||||
year: '2025',
|
|
||||||
quarter: 'Q4',
|
|
||||||
lastSubmission: '10/12/2024',
|
|
||||||
deadline: '20/12/2024',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
establishment: 'Khazan meat factory',
|
|
||||||
emirate: 'Sharjah',
|
|
||||||
productCount: '8',
|
|
||||||
year: '2025',
|
|
||||||
quarter: 'Q3',
|
|
||||||
lastSubmission: '15/11/2024',
|
|
||||||
deadline: '15/12/2024',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
establishment: 'SPINNEYS FRESH FOOD INDUSTRIES L.L.C',
|
|
||||||
emirate: 'Dubai',
|
|
||||||
productCount: '6',
|
|
||||||
year: '2025',
|
|
||||||
quarter: 'Q2',
|
|
||||||
lastSubmission: '12/12/2024',
|
|
||||||
deadline: '10/12/2024',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
establishment: 'FRESHLY FROZEN FOODS FACTORY L.L.C',
|
|
||||||
emirate: 'Dubai',
|
|
||||||
productCount: '8',
|
|
||||||
year: '2025',
|
|
||||||
quarter: 'Q1',
|
|
||||||
lastSubmission: '08/12/2024',
|
|
||||||
deadline: '18/12/2024',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
establishment: 'SAHAR FOOD INDUSTRY (L.L.C)',
|
|
||||||
emirate: 'Dubai',
|
|
||||||
productCount: '8',
|
|
||||||
year: '2025',
|
|
||||||
quarter: 'Q4',
|
|
||||||
lastSubmission: '08/12/2024',
|
|
||||||
deadline: '18/12/2024',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
establishment: 'CONTINENTAL FOOD PROCESSING LLC',
|
|
||||||
emirate: 'Ajman',
|
|
||||||
productCount: '8',
|
|
||||||
year: '2025',
|
|
||||||
quarter: 'Q3',
|
|
||||||
lastSubmission: '08/12/2024',
|
|
||||||
deadline: '18/12/2024',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
establishment: 'AL KHAZNA POULTRY FARM',
|
|
||||||
emirate: 'Abu Dhabi',
|
|
||||||
productCount: '8',
|
|
||||||
year: '2025',
|
|
||||||
quarter: 'Q2',
|
|
||||||
lastSubmission: '08/12/2024',
|
|
||||||
deadline: '18/12/2024',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
establishment: 'DIAMOND MEAT PROCESSING L.L.C',
|
|
||||||
emirate: 'Abu Dhabi',
|
|
||||||
productCount: '8',
|
|
||||||
year: '2025',
|
|
||||||
quarter: 'Q2',
|
|
||||||
lastSubmission: '08/12/2024',
|
|
||||||
deadline: '18/12/2024',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
establishment: 'ALLIANCE FOODS CO L.L.C',
|
|
||||||
emirate: 'Abu Dhabi',
|
|
||||||
productCount: '8',
|
|
||||||
year: '2025',
|
|
||||||
quarter: 'Q2',
|
|
||||||
lastSubmission: '08/12/2024',
|
|
||||||
deadline: '18/12/2024',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
establishment: 'KRUSTASIA FOODS L.L.C',
|
|
||||||
emirate: 'Dubai',
|
|
||||||
productCount: '4',
|
|
||||||
year: '2025',
|
|
||||||
quarter: 'Q1',
|
|
||||||
lastSubmission: '14/12/2024',
|
|
||||||
deadline: '21/12/2024',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const SubmissionTable = () => {
|
|
||||||
const [search, setSearch] = useState('');
|
|
||||||
const [selectedYear, setSelectedYear] = useState('2025');
|
|
||||||
const [selectedQuarter, setSelectedQuarter] = useState('Q4');
|
|
||||||
const [loading, setLoading] = useState(false);
|
|
||||||
|
|
||||||
// Filter submissions by selected year and quarter
|
|
||||||
const filteredByQuarterYear = useMemo(() => {
|
|
||||||
return submissions.filter(
|
|
||||||
(item) => item.year === selectedYear && item.quarter === selectedQuarter
|
|
||||||
);
|
|
||||||
}, [selectedYear, selectedQuarter]);
|
|
||||||
|
|
||||||
// Apply search filter to the filteredByQuarterYear results
|
|
||||||
const filtered = useMemo(() => {
|
const filtered = useMemo(() => {
|
||||||
if (!search.trim()) return filteredByQuarterYear;
|
let list = [...data];
|
||||||
const normalized = search.trim().toLowerCase();
|
if (selectedQuarter !== 'None') {
|
||||||
return filteredByQuarterYear.filter((item) =>
|
list = list.filter((item) => item.quarter === selectedQuarter);
|
||||||
Object.values(item).join(' ').toLowerCase().includes(normalized)
|
}
|
||||||
);
|
if (selectedYear !== 'None') {
|
||||||
}, [search, filteredByQuarterYear]);
|
list = list.filter((item) => String(item.year) === String(selectedYear));
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}, [data, selectedQuarter, selectedYear]);
|
||||||
|
|
||||||
|
const titleText = useMemo(() => {
|
||||||
|
const count = filtered.length;
|
||||||
|
if (selectedQuarter !== 'None' && selectedYear !== 'None') {
|
||||||
|
return `Recent 10 Submissions for Selected Quarter ${selectedQuarter} ${selectedYear} (${count})`;
|
||||||
|
} else if (selectedQuarter !== 'None') {
|
||||||
|
return `Recent 10 Submissions for Selected Quarter ${selectedQuarter} (${count})`;
|
||||||
|
} else if (selectedYear !== 'None') {
|
||||||
|
return `Recent 10 Submissions for Selected Year ${selectedYear} (${count})`;
|
||||||
|
} else {
|
||||||
|
return `Recent 10 Submissions (${count})`;
|
||||||
|
}
|
||||||
|
}, [selectedQuarter, selectedYear, filtered]);
|
||||||
|
|
||||||
|
const formatDate = (dateStr) => {
|
||||||
|
if (!dateStr) return '-';
|
||||||
|
const date = new Date(dateStr);
|
||||||
|
const formatted = date.toLocaleString('en-GB', {
|
||||||
|
day: '2-digit',
|
||||||
|
month: '2-digit',
|
||||||
|
year: 'numeric',
|
||||||
|
hour: '2-digit',
|
||||||
|
minute: '2-digit',
|
||||||
|
hour12: true,
|
||||||
|
});
|
||||||
|
return formatted.replace(/\s?(am|pm)$/i, (match) => match.toUpperCase());
|
||||||
|
};
|
||||||
|
|
||||||
const headers = [
|
const headers = [
|
||||||
'Establishment',
|
'Establishment',
|
||||||
@ -139,25 +82,25 @@ const SubmissionTable = () => {
|
|||||||
const normalized = status?.toLowerCase();
|
const normalized = status?.toLowerCase();
|
||||||
if (normalized === 'approved') {
|
if (normalized === 'approved') {
|
||||||
return (
|
return (
|
||||||
<span className="px-3 py-1 rounded-md text-green-700 bg-green-50 font-medium text-sm">
|
<span className="px-3 py-1 rounded-md text-green-700 bg-green-50 font-medium text-sm whitespace-nowrap">
|
||||||
Approved
|
Approved
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
} else if (normalized === 'rejected') {
|
} else if (normalized === 'rejected') {
|
||||||
return (
|
return (
|
||||||
<span className="px-3 py-1 rounded-md text-red-600 bg-red-50 font-medium text-sm">
|
<span className="px-3 py-1 rounded-md text-red-600 bg-red-50 font-medium text-sm whitespace-nowrap">
|
||||||
Rejected
|
Rejected
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
} else if (normalized === 'pending') {
|
} else if (normalized === 'pending') {
|
||||||
return (
|
return (
|
||||||
<span className="px-3 py-1 rounded-md text-blue-600 bg-blue-50 font-medium text-sm">
|
<span className="px-3 py-1 rounded-md text-blue-600 bg-blue-50 font-medium text-sm whitespace-nowrap">
|
||||||
Pending
|
Pending
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<span className="px-3 py-1 rounded-md text-gray-600 bg-gray-50 font-medium text-sm">
|
<span className="px-3 py-1 rounded-md text-gray-600 bg-gray-50 font-medium text-sm whitespace-nowrap">
|
||||||
{status || '-'}
|
{status || '-'}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
@ -165,69 +108,53 @@ const SubmissionTable = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const tableRows = filtered.map((item) => [
|
const tableRows = filtered.map((item) => [
|
||||||
item.establishment,
|
item?.establishment?.factory_name || '-',
|
||||||
item.emirate,
|
item?.establishment?.establishment_emirate?.name || '-',
|
||||||
item.year,
|
item?.year || '-',
|
||||||
item.quarter,
|
item?.quarter || '-',
|
||||||
item.productCount,
|
item?.product_count || '-',
|
||||||
item.submittedBy,
|
item?.created_by || '-',
|
||||||
item.submissionDateTime,
|
<span className="whitespace-nowrap">{formatDate(item?.created_at)}</span>,
|
||||||
renderStatusBadge(item.status),
|
renderStatusBadge(item?.status),
|
||||||
item.reviewer,
|
item?.updated_by || '-',
|
||||||
item.reviewedOn,
|
<span className="whitespace-nowrap">{formatDate(item?.updated_at)}</span>,
|
||||||
<div className="flex items-center justify-center gap-3">
|
<div className="flex items-center justify-center gap-[10px]">
|
||||||
<img src={checkCircleSrc} alt="Approve" className="text-green-600 w-5 h-5 cursor-pointer hover:scale-110 transition-transform" />
|
<CheckCircle2
|
||||||
<img src={xCircleSrc} alt="Reject" className="text-red-500 w-5 h-5 cursor-pointer hover:scale-110 transition-transform" />
|
size={22}
|
||||||
<img src={eyeIconSrc} alt="View" className="text-gray-500 w-5 h-5 cursor-pointer hover:scale-110 transition-transform" />
|
className="text-green-600 cursor-pointer hover:scale-110 transition-transform"
|
||||||
</div>,
|
strokeWidth={2.5}
|
||||||
|
/>
|
||||||
|
<XCircle
|
||||||
|
size={22}
|
||||||
|
className="text-red-600 cursor-pointer hover:scale-110 transition-transform"
|
||||||
|
strokeWidth={2.5}
|
||||||
|
/>
|
||||||
|
<Eye
|
||||||
|
size={22}
|
||||||
|
className={`cursor-pointer hover:scale-110 transition-transform ${
|
||||||
|
item.status?.toLowerCase() === 'pending'
|
||||||
|
? 'text-[#9E792B]'
|
||||||
|
: 'text-gray-500'
|
||||||
|
}`}
|
||||||
|
strokeWidth={2.3}
|
||||||
|
/>
|
||||||
|
</div>,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const columnWidths = [240, 120, 100, 100, 130, 150, 180, 150, 150, 180, 120];
|
const columnWidths = [240, 120, 100, 100, 130, 150, 180, 150, 150, 180, 120];
|
||||||
|
|
||||||
const titleText = useMemo(() => {
|
|
||||||
const count = filtered.length;
|
|
||||||
if (selectedQuarter !== 'None' && selectedYear !== 'None') {
|
|
||||||
return `Recent 10 Submissions for Selected Quarter ${selectedQuarter} ${selectedYear} (${count})`;
|
|
||||||
} else if (selectedQuarter !== 'None') {
|
|
||||||
return `Recent 10 Submissions for Selected Quarter ${selectedQuarter} (${count})`;
|
|
||||||
} else if (selectedYear !== 'None') {
|
|
||||||
return `Recent 10 Submissions for Selected Year ${selectedYear} (${count})`;
|
|
||||||
} else {
|
|
||||||
return `Recent 10 Submissions (${count})`;
|
|
||||||
}
|
|
||||||
}, [selectedQuarter, selectedYear, filtered]);
|
|
||||||
|
|
||||||
const toolbar = (
|
|
||||||
<div className="px-6 pt-6 pb-4">
|
|
||||||
<div className="mx-auto flex h-10 w-full max-w-[1280px] items-center justify-between gap-4">
|
|
||||||
<h2 className="text-[18px] leading-[28px] font-medium text-[#232528]">
|
|
||||||
{titleText}
|
|
||||||
</h2>
|
|
||||||
<div className="relative w-[280px]">
|
|
||||||
<img
|
|
||||||
src={searchIconSrc}
|
|
||||||
alt="Search"
|
|
||||||
className="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4"
|
|
||||||
/>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={search}
|
|
||||||
onChange={(event) => setSearch(event.target.value)}
|
|
||||||
placeholder="Search Establishment or Status"
|
|
||||||
className="h-10 w-full rounded-md border border-[#C3C6CB] pl-9 pr-3 text-sm focus:outline-none focus:ring-1 focus:ring-[#92722A]"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="border border-[#E5E7EB] bg-white shadow-[0_16px_32px_rgba(15,23,42,0.06)] rounded-[8px]"
|
className="border border-[#E5E7EB] bg-white shadow-[0_16px_32px_rgba(15,23,42,0.06)] rounded-[8px]"
|
||||||
style={{ width: '1250px', height: '706px' }}
|
style={{ width: '1250px', minHeight: '780px' }}
|
||||||
>
|
>
|
||||||
<div className="space-y-[1px] overflow-x-auto">
|
<div className="space-y-[1px] overflow-x-auto">
|
||||||
{toolbar}
|
<div className="px-6 pt-6 pb-4">
|
||||||
|
<h2 className="text-[18px] leading-[28px] font-medium text-[#232528]">
|
||||||
|
{titleText}
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<div className="flex items-center justify-center h-[500px] text-gray-500">
|
<div className="flex items-center justify-center h-[500px] text-gray-500">
|
||||||
Loading submissions...
|
Loading submissions...
|
||||||
@ -245,10 +172,10 @@ const SubmissionTable = () => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex justify-end px-6 pb-6">
|
<div className="flex justify-end px-6 pb-14 pt-6">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="inline-flex h-[44px] w-[168px] items-center justify-center gap-2 rounded-md bg-[#9E792B] text-sm font-medium text-white shadow-[0_8px_18px_rgba(146,114,42,0.35)] hover:bg-[#846522]"
|
className="inline-flex h-[44px] w-[190px] items-center justify-center gap-2 rounded-md bg-[#9E792B] text-sm font-medium text-white shadow-[0_8px_18px_rgba(146,114,42,0.35)] hover:bg-[#846522]"
|
||||||
>
|
>
|
||||||
View All Submissions
|
View All Submissions
|
||||||
</button>
|
</button>
|
||||||
@ -257,4 +184,4 @@ const SubmissionTable = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SubmissionTable
|
export default SubmissionTable;
|
||||||
@ -98,36 +98,42 @@ const AdminDashboard = () => {
|
|||||||
value={loading ? '--' : summary.total_establishments}
|
value={loading ? '--' : summary.total_establishments}
|
||||||
width={290}
|
width={290}
|
||||||
icon={<img src={surveyIconSrc} alt="Total Establishments" className="h-5 w-5" />}
|
icon={<img src={surveyIconSrc} alt="Total Establishments" className="h-5 w-5" />}
|
||||||
|
tooltipText="Total establishments enrolled in the survey for selected quarter."
|
||||||
/>
|
/>
|
||||||
<StatCard
|
<StatCard
|
||||||
label="Submitted"
|
label="Submitted"
|
||||||
value={loading ? '--' : summary.submitted}
|
value={loading ? '--' : summary.submitted}
|
||||||
width={190}
|
width={190}
|
||||||
icon={<img src={submittedIconSrc} alt="Submitted" className="h-5 w-5" />}
|
icon={<img src={submittedIconSrc} alt="Submitted" className="h-5 w-5" />}
|
||||||
|
tooltipText="Establishments that have submitted all products for this quarter."
|
||||||
/>
|
/>
|
||||||
<StatCard
|
<StatCard
|
||||||
label="Approved"
|
label="Approved"
|
||||||
value={loading ? '--' : summary.approved}
|
value={loading ? '--' : summary.approved}
|
||||||
width={190}
|
width={190}
|
||||||
icon={<img src={approvedIconSrc} alt="Approved" className="h-5 w-5" />}
|
icon={<img src={approvedIconSrc} alt="Approved" className="h-5 w-5" />}
|
||||||
|
tooltipText="Submissions fully validated and approved."
|
||||||
/>
|
/>
|
||||||
<StatCard
|
<StatCard
|
||||||
label="Rejected"
|
label="Rejected"
|
||||||
value={loading ? '--' : summary.rejected}
|
value={loading ? '--' : summary.rejected}
|
||||||
width={190}
|
width={190}
|
||||||
icon={<img src={rejectedIconSrc} alt="Rejected" className="h-5 w-5" />}
|
icon={<img src={rejectedIconSrc} alt="Rejected" className="h-5 w-5" />}
|
||||||
|
tooltipText="Submissions rejected and pending resubmission."
|
||||||
/>
|
/>
|
||||||
<StatCard
|
<StatCard
|
||||||
label="Not Started"
|
label="Not Started"
|
||||||
value={loading ? '--' : summary.not_started}
|
value={loading ? '--' : summary.not_started}
|
||||||
width={190}
|
width={190}
|
||||||
icon={<img src={overdueIconSrc} alt="Not Started" className="h-5 w-5" />}
|
icon={<img src={overdueIconSrc} alt="Not Started" className="h-5 w-5" />}
|
||||||
|
tooltipText="Establishments past submission deadline."
|
||||||
/>
|
/>
|
||||||
<StatCard
|
<StatCard
|
||||||
label="Pending"
|
label="Pending"
|
||||||
value={loading ? '--' : summary.pending}
|
value={loading ? '--' : summary.pending}
|
||||||
width={190}
|
width={190}
|
||||||
icon={<img src={pendingIconSrc} alt="Pending" className="h-5 w-5" />}
|
icon={<img src={pendingIconSrc} alt="Pending" className="h-5 w-5" />}
|
||||||
|
tooltipText="Establishments not yet submitted."
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user