bug fixed in establishemnet
This commit is contained in:
parent
74174618db
commit
0e65ba4d13
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M8.125 0C6.51803 0 4.94714 0.476523 3.611 1.36931C2.27485 2.2621 1.23344 3.53105 0.618482 5.0157C0.00352044 6.50035 -0.157382 8.13401 0.156123 9.71011C0.469628 11.2862 1.24346 12.7339 2.37976 13.8702C3.51606 15.0065 4.9638 15.7804 6.5399 16.0939C8.11599 16.4074 9.74966 16.2465 11.2343 15.6315C12.719 15.0166 13.9879 13.9752 14.8807 12.639C15.7735 11.3029 16.25 9.73197 16.25 8.125C16.2477 5.97081 15.391 3.90551 13.8677 2.38227C12.3445 0.85903 10.2792 0.00227486 8.125 0ZM7.5 4.375C7.5 4.20924 7.56585 4.05027 7.68306 3.93306C7.80027 3.81585 7.95924 3.75 8.125 3.75C8.29076 3.75 8.44974 3.81585 8.56695 3.93306C8.68416 4.05027 8.75 4.20924 8.75 4.375V8.75C8.75 8.91576 8.68416 9.07473 8.56695 9.19194C8.44974 9.30915 8.29076 9.375 8.125 9.375C7.95924 9.375 7.80027 9.30915 7.68306 9.19194C7.56585 9.07473 7.5 8.91576 7.5 8.75V4.375ZM8.125 12.5C7.93958 12.5 7.75833 12.445 7.60416 12.342C7.44999 12.239 7.32982 12.0926 7.25887 11.9213C7.18791 11.75 7.16934 11.5615 7.20552 11.3796C7.24169 11.1977 7.33098 11.0307 7.46209 10.8996C7.5932 10.7685 7.76025 10.6792 7.94211 10.643C8.12396 10.6068 8.31246 10.6254 8.48377 10.6964C8.65507 10.7673 8.80149 10.8875 8.90451 11.0417C9.00752 11.1958 9.0625 11.3771 9.0625 11.5625C9.0625 11.8111 8.96373 12.0496 8.78792 12.2254C8.6121 12.4012 8.37364 12.5 8.125 12.5Z" fill="#EA4F49"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.4 KiB |
@ -77,8 +77,9 @@ const Table = ({
|
|||||||
const safeCurrentPage = enablePagination ? Math.min(Math.max(currentPage, 1), totalPages) : 1;
|
const safeCurrentPage = enablePagination ? Math.min(Math.max(currentPage, 1), totalPages) : 1;
|
||||||
const startIndex = enablePagination ? (safeCurrentPage - 1) * pageSize : 0;
|
const startIndex = enablePagination ? (safeCurrentPage - 1) * pageSize : 0;
|
||||||
const endIndex = enablePagination ? startIndex + pageSize : rows.length;
|
const endIndex = enablePagination ? startIndex + pageSize : rows.length;
|
||||||
|
// Calculate range start and end, handling the case when there are no items
|
||||||
const rangeStart = totalItems === 0 ? 0 : startIndex + 1;
|
const rangeStart = totalItems === 0 ? 0 : startIndex + 1;
|
||||||
const rangeEnd = enablePagination ? Math.min(endIndex, totalItems) : rows.length;
|
const rangeEnd = totalItems === 0 ? 0 : (enablePagination ? Math.min(endIndex, totalItems) : rows.length);
|
||||||
|
|
||||||
const displayedRows = React.useMemo(() => {
|
const displayedRows = React.useMemo(() => {
|
||||||
if (!enablePagination) return rows;
|
if (!enablePagination) return rows;
|
||||||
|
|||||||
@ -489,6 +489,15 @@ export const DetailedOverview = ({ submission, onBack }) => {
|
|||||||
pagination={tablePagination}
|
pagination={tablePagination}
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
|
<button
|
||||||
|
onClick={onBack}
|
||||||
|
className="inline-flex items-center gap-2 h-9 px-4 rounded-md border border-[#92722A] text-[#92722A] bg-transparent hover:bg-[#92722A]/10"
|
||||||
|
>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" d="M15 19l-7-7 7-7" />
|
||||||
|
</svg>
|
||||||
|
<span>Back</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -37,10 +37,12 @@ const ProductDetails = ({ product, onBack, showToast: shouldShowToast, onToastSh
|
|||||||
rejected: {
|
rejected: {
|
||||||
type: 'rejected',
|
type: 'rejected',
|
||||||
bgColor: 'bg-red-50',
|
bgColor: 'bg-red-50',
|
||||||
textColor: '#D83731',
|
textColor: 'text-red-600',
|
||||||
iconColor: 'text-red-500',
|
iconColor: 'text-red-500',
|
||||||
message: 'Your survey has been rejected. Please review and resubmit.',
|
message: 'Your survey has been rejected. Please review and resubmit.',
|
||||||
// icon: 'warning-circle-fill-1.svg'
|
icon: '/assets/images/Vector-rejected.svg',
|
||||||
|
iconAlt: 'Rejected',
|
||||||
|
iconClassName: 'mr-2 h-5 w-5 flex-shrink-0'
|
||||||
},
|
},
|
||||||
submitted: {
|
submitted: {
|
||||||
type: 'submitted',
|
type: 'submitted',
|
||||||
@ -146,18 +148,11 @@ const ProductDetails = ({ product, onBack, showToast: shouldShowToast, onToastSh
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
) : toast.type === 'rejected' ? (
|
) : toast.type === 'rejected' ? (
|
||||||
<svg
|
<img
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
src={toast.icon}
|
||||||
viewBox="0 0 20 20"
|
alt={toast.iconAlt || 'Rejected'}
|
||||||
fill="currentColor"
|
className={toast.iconClassName || 'w-5 h-5 mr-2'}
|
||||||
className={`w-5 h-5 mr-2 ${toast.iconColor}`}
|
/>
|
||||||
>
|
|
||||||
<path
|
|
||||||
fillRule="evenodd"
|
|
||||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z"
|
|
||||||
clipRule="evenodd"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
) : (
|
) : (
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
@ -205,7 +200,7 @@ const ProductDetails = ({ product, onBack, showToast: shouldShowToast, onToastSh
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="bg-white rounded-lg shadow-sm border border-[#E2E8F0] p-6">
|
<div className="bg-white rounded-lg shadow-sm border border-[#E2E8F0] p-6 mt-3">
|
||||||
{/* Basic Information */}
|
{/* Basic Information */}
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-6 mb-4">
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-6 mb-4">
|
||||||
@ -380,6 +375,15 @@ const ProductDetails = ({ product, onBack, showToast: shouldShowToast, onToastSh
|
|||||||
</div>
|
</div>
|
||||||
</div> */}
|
</div> */}
|
||||||
</div>
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={onBack}
|
||||||
|
className="inline-flex items-center gap-2 h-9 px-4 mt-8 rounded-md border border-[#92722A] text-[#92722A] bg-transparent hover:bg-[#92722A]/10"
|
||||||
|
>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" d="M15 19l-7-7 7-7" />
|
||||||
|
</svg>
|
||||||
|
<span>Back</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -178,12 +178,25 @@ const ProductData = ({
|
|||||||
const [unitsError, setUnitsError] = React.useState('');
|
const [unitsError, setUnitsError] = React.useState('');
|
||||||
const [activeTab, setActiveTab] = React.useState('current');
|
const [activeTab, setActiveTab] = React.useState('current');
|
||||||
const [isInitialLoad, setIsInitialLoad] = React.useState(true);
|
const [isInitialLoad, setIsInitialLoad] = React.useState(true);
|
||||||
const [remarks, setRemarks] = React.useState('');
|
const [remarks, setRemarks] = React.useState(() => {
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
const savedRemarks = localStorage.getItem('surveyRemarks');
|
||||||
|
return savedRemarks || '';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
});
|
||||||
const [formErrors, setFormErrors] = React.useState({});
|
const [formErrors, setFormErrors] = React.useState({});
|
||||||
const [quarterPeriods, setQuarterPeriods] = useState(null);
|
const [quarterPeriods, setQuarterPeriods] = useState(null);
|
||||||
const [isLoadingPeriods, setIsLoadingPeriods] = useState(false);
|
const [isLoadingPeriods, setIsLoadingPeriods] = useState(false);
|
||||||
|
|
||||||
// Fetch quarter periods when component mounts or quarter/year changes
|
const handleRemarksChange = (e) => {
|
||||||
|
const newRemarks = e.target.value;
|
||||||
|
setRemarks(newRemarks);
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
localStorage.setItem('surveyRemarks', newRemarks);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchQuarterPeriods = async () => {
|
const fetchQuarterPeriods = async () => {
|
||||||
if (!quarter || !year) return;
|
if (!quarter || !year) return;
|
||||||
@ -1239,7 +1252,7 @@ const ProductData = ({
|
|||||||
<Textarea
|
<Textarea
|
||||||
placeholder="Enter your remarks here..."
|
placeholder="Enter your remarks here..."
|
||||||
value={remarks}
|
value={remarks}
|
||||||
onChange={(e) => setRemarks(e.target.value)}
|
onChange={handleRemarksChange}
|
||||||
className="min-h-[60px]"
|
className="min-h-[60px]"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -254,7 +254,13 @@ const ReviewSubmit = ({
|
|||||||
hasSubmitted = false,
|
hasSubmitted = false,
|
||||||
}) => {
|
}) => {
|
||||||
const [confirm, setConfirm] = React.useState(false);
|
const [confirm, setConfirm] = React.useState(false);
|
||||||
const [remarks, setRemarks] = React.useState('');
|
const [remarks, setRemarks] = React.useState(() => {
|
||||||
|
// Load remarks from localStorage on component mount
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
return localStorage.getItem('surveyRemarks') || '';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
});
|
||||||
const establishmentDetails = React.useMemo(() => buildEstablishmentDetails(establishment), [establishment]);
|
const establishmentDetails = React.useMemo(() => buildEstablishmentDetails(establishment), [establishment]);
|
||||||
const employmentDetails = React.useMemo(() => buildEmploymentDetails(establishment), [establishment]);
|
const employmentDetails = React.useMemo(() => buildEmploymentDetails(establishment), [establishment]);
|
||||||
const productRows = React.useMemo(() => buildProductRows(products), [products]);
|
const productRows = React.useMemo(() => buildProductRows(products), [products]);
|
||||||
@ -598,6 +604,15 @@ const ReviewSubmit = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Remarks Section */}
|
||||||
|
{/* {remarks && (
|
||||||
|
<Card title="Remarks" className="mb-6">
|
||||||
|
<div className="p-4 bg-gray-50 rounded-md">
|
||||||
|
<p className="text-gray-700 whitespace-pre-line">{remarks}</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
)} */}
|
||||||
|
|
||||||
{/* Table */}
|
{/* Table */}
|
||||||
<div className="overflow-x-auto">
|
<div className="overflow-x-auto">
|
||||||
<table className="min-w-full border border-gray-300 text-sm text-center">
|
<table className="min-w-full border border-gray-300 text-sm text-center">
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
import React, { useEffect, useState, useCallback } from 'react';
|
import React, { useEffect, useState, useMemo,useCallback } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import Table from '@/components/common/Table';
|
import Table from '@/components/common/Table';
|
||||||
import HeaderBar from '@/components/layout/HeaderBar';
|
import HeaderBar from '@/components/layout/HeaderBar';
|
||||||
import { fetchSubmissionHistory } from '@/services/submissions/submissionService.js';
|
// import { fetchSubmissionHistory } from '@/services/submissions/submissionService.js';
|
||||||
import { fetchProducts } from '@/services/masters/masterService';
|
import { fetchProducts } from '@/services/masters/masterService';
|
||||||
|
import { fetchSubmissionHistory, getSubmissionAuditHistory } from '@/services/submissions/submissionService';
|
||||||
|
|
||||||
const searchIconSrc = '/assets/images/material-symbols_search-rounded.svg';
|
const searchIconSrc = '/assets/images/material-symbols_search-rounded.svg';
|
||||||
const BreadcrumbVector = '/assets/images/Breadcrumb-vector.svg';
|
const BreadcrumbVector = '/assets/images/Breadcrumb-vector.svg';
|
||||||
@ -35,6 +36,11 @@ const History = () => {
|
|||||||
const [hscodeFilter, setHscodeFilter] = React.useState('');
|
const [hscodeFilter, setHscodeFilter] = React.useState('');
|
||||||
const [hscodeOptions, setHscodeOptions] = React.useState([]);
|
const [hscodeOptions, setHscodeOptions] = React.useState([]);
|
||||||
const [isLoadingHscodes, setIsLoadingHscodes] = React.useState(false);
|
const [isLoadingHscodes, setIsLoadingHscodes] = React.useState(false);
|
||||||
|
const [auditHistory, setAuditHistory] = useState([]);
|
||||||
|
const [isLoadingAudit, setIsLoadingAudit] = useState(false);
|
||||||
|
const [actorOptions, setActorOptions] = useState([]);
|
||||||
|
const [selectedActor, setSelectedActor] = useState('');
|
||||||
|
|
||||||
const [pagination, setPagination] = React.useState({
|
const [pagination, setPagination] = React.useState({
|
||||||
currentPage: 1,
|
currentPage: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
@ -59,6 +65,105 @@ const History = () => {
|
|||||||
loadHscodeOptions();
|
loadHscodeOptions();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// useEffect(() => {
|
||||||
|
// const loadAuditHistory = async () => {
|
||||||
|
// setIsLoadingAudit(true);
|
||||||
|
// try {
|
||||||
|
// const establishmentId = 41; // Replace with dynamic ID if available
|
||||||
|
// const response = await getSubmissionAuditHistory(establishmentId, {
|
||||||
|
// year: yearFilter || undefined,
|
||||||
|
// quarter: quarterFilter || undefined,
|
||||||
|
// product_id: hscodeFilter || undefined
|
||||||
|
// });
|
||||||
|
// setAuditHistory(response?.data || []);
|
||||||
|
// setPagination(prev => ({
|
||||||
|
// ...prev,
|
||||||
|
// totalItems: response?.data?.length,
|
||||||
|
// currentPage: 1,
|
||||||
|
// }));
|
||||||
|
// } catch (error) {
|
||||||
|
// console.error('Error loading audit history:', error);
|
||||||
|
// setAuditHistory([]);
|
||||||
|
// } finally {
|
||||||
|
// setIsLoadingAudit(false);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
// loadAuditHistory();
|
||||||
|
// }, [yearFilter, quarterFilter, hscodeFilter]);
|
||||||
|
useEffect(() => {
|
||||||
|
const loadAuditHistory = async () => {
|
||||||
|
setIsLoadingAudit(true);
|
||||||
|
try {
|
||||||
|
const establishmentId = 41; // Replace with dynamic ID if available
|
||||||
|
|
||||||
|
// Extract product_name from selected value ("HS - Product" → "Product")
|
||||||
|
const productName = hscodeFilter.includes(" - ")
|
||||||
|
? hscodeFilter.split(" - ")[1].trim()
|
||||||
|
: hscodeFilter.trim();
|
||||||
|
|
||||||
|
console.log("📦 Loading audit history with:", {
|
||||||
|
yearFilter,
|
||||||
|
quarterFilter,
|
||||||
|
productName,
|
||||||
|
});
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
year: yearFilter || undefined,
|
||||||
|
quarter: quarterFilter || undefined,
|
||||||
|
product_name: productName || undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await getSubmissionAuditHistory(establishmentId, params);
|
||||||
|
|
||||||
|
const data = response?.data || [];
|
||||||
|
setAuditHistory(data);
|
||||||
|
|
||||||
|
const actors = [...new Set(data.map(item => item.actor).filter(Boolean))];
|
||||||
|
setActorOptions(actors.map(actor => ({
|
||||||
|
value: actor,
|
||||||
|
label: actor
|
||||||
|
})));
|
||||||
|
|
||||||
|
setPagination((prev) => ({
|
||||||
|
...prev,
|
||||||
|
totalItems: data.length,
|
||||||
|
currentPage: 1,
|
||||||
|
}));
|
||||||
|
|
||||||
|
console.log("✅ Loaded audit history rows:", data.length);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(" Error loading audit history:", error);
|
||||||
|
setAuditHistory([]);
|
||||||
|
} finally {
|
||||||
|
setIsLoadingAudit(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
loadAuditHistory();
|
||||||
|
}, [yearFilter, quarterFilter, hscodeFilter , searchTerm , selectedActor]);
|
||||||
|
|
||||||
|
|
||||||
|
const formatExportDateTime = (value) => {
|
||||||
|
if (!value) return '-';
|
||||||
|
const date = new Date(value);
|
||||||
|
if (Number.isNaN(date.getTime())) return '-';
|
||||||
|
|
||||||
|
// Format as DD/MM/YYYY, HH:MM AM/PM
|
||||||
|
const day = String(date.getDate()).padStart(2, '0');
|
||||||
|
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||||
|
const year = date.getFullYear();
|
||||||
|
let hours = date.getHours();
|
||||||
|
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||||
|
const ampm = hours >= 12 ? 'PM' : 'AM';
|
||||||
|
hours = hours % 12;
|
||||||
|
hours = hours ? hours : 12; // the hour '0' should be '12'
|
||||||
|
|
||||||
|
return `${day}/${month}/${year}, ${hours}:${minutes} ${ampm}`;
|
||||||
|
};
|
||||||
|
|
||||||
const toVariant = React.useCallback((status) => {
|
const toVariant = React.useCallback((status) => {
|
||||||
const text = String(status || '').toLowerCase();
|
const text = String(status || '').toLowerCase();
|
||||||
if (text === 'approved') return 'approved';
|
if (text === 'approved') return 'approved';
|
||||||
@ -169,66 +274,45 @@ const History = () => {
|
|||||||
const statusOptions = [
|
const statusOptions = [
|
||||||
{ value: 'all', label: 'All Status' },
|
{ value: 'all', label: 'All Status' },
|
||||||
{ value: 'approved', label: 'Approved' },
|
{ value: 'approved', label: 'Approved' },
|
||||||
{ value: 'pending', label: 'Pending' },
|
|
||||||
{ value: 'rejected', label: 'Rejected' },
|
{ value: 'rejected', label: 'Rejected' },
|
||||||
{ value: 'submitted', label: 'Submitted' },
|
{ value: 'submitted', label: 'Submitted' },
|
||||||
];
|
];
|
||||||
|
|
||||||
const filteredRows = React.useMemo(() => {
|
const filteredRows = useMemo(() => {
|
||||||
const term = searchTerm.trim().toLowerCase();
|
const term = searchTerm.trim().toLowerCase();
|
||||||
const statusValue = statusFilter.toLowerCase();
|
|
||||||
|
|
||||||
const filtered = rows.filter((entry) => {
|
const filtered = auditHistory.filter((entry) => {
|
||||||
// Status filter
|
const matchesSearch =
|
||||||
const matchesStatus =
|
!term ||
|
||||||
statusValue === 'all' ||
|
Object.values(entry)
|
||||||
toVariant(entry.status) === statusValue ||
|
.join(' ')
|
||||||
formatStatus(entry.status).toLowerCase() === statusValue;
|
.toLowerCase()
|
||||||
|
.includes(term);
|
||||||
|
|
||||||
// Year filter
|
const matchesYear = !yearFilter || String(entry.year) === yearFilter;
|
||||||
const matchesYear = !yearFilter || String(entry.year) === yearFilter;
|
const matchesQuarter = !quarterFilter || entry.quarter?.toUpperCase() === quarterFilter.toUpperCase();
|
||||||
|
|
||||||
// Quarter filter
|
const matchesHscode = (() => {
|
||||||
const matchesQuarter = !quarterFilter ||
|
if (!hscodeFilter) return true;
|
||||||
(entry.quarter && entry.quarter.toUpperCase() === quarterFilter.toUpperCase());
|
const productName = hscodeFilter.includes(' - ')
|
||||||
|
? hscodeFilter.split(' - ')[1].trim()
|
||||||
|
: hscodeFilter.trim();
|
||||||
|
return entry.product_name?.toLowerCase().includes(productName.toLowerCase());
|
||||||
|
})();
|
||||||
|
|
||||||
// HS Code/Product filter
|
return matchesSearch && matchesYear && matchesQuarter && matchesHscode;
|
||||||
const matchesHscode = !hscodeFilter ||
|
});
|
||||||
(entry.hs_code && entry.hs_code.toString() === hscodeFilter) ||
|
|
||||||
(entry.product_id && entry.product_id.toString() === hscodeFilter);
|
|
||||||
|
|
||||||
// Search term filter
|
setPagination((prev) => ({
|
||||||
if (term) {
|
...prev,
|
||||||
const haystack = [
|
totalItems: filtered.length,
|
||||||
entry.year,
|
currentPage: 1,
|
||||||
entry.quarter,
|
}));
|
||||||
entry.submission_window,
|
|
||||||
entry.total_products,
|
|
||||||
entry.products_submitted,
|
|
||||||
entry.total_cost,
|
|
||||||
formatStatus(entry.status),
|
|
||||||
formatDate(entry.created_at),
|
|
||||||
entry.hs_code,
|
|
||||||
entry.product_name
|
|
||||||
]
|
|
||||||
.map((val) => String(val || '').toLowerCase())
|
|
||||||
.join(' ');
|
|
||||||
|
|
||||||
return matchesStatus && matchesYear && matchesQuarter && matchesHscode && haystack.includes(term);
|
return filtered;
|
||||||
}
|
}, [auditHistory, searchTerm, yearFilter, quarterFilter, hscodeFilter]);
|
||||||
|
|
||||||
return matchesStatus && matchesYear && matchesQuarter && matchesHscode;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Update total items when filtered rows change
|
|
||||||
setPagination(prev => ({
|
|
||||||
...prev,
|
|
||||||
totalItems: filtered.length,
|
|
||||||
currentPage: 1, // Reset to first page when filter changes
|
|
||||||
}));
|
|
||||||
|
|
||||||
return filtered;
|
|
||||||
}, [rows, searchTerm, statusFilter, yearFilter, quarterFilter, hscodeFilter, toVariant, formatStatus, formatDate]);
|
|
||||||
|
|
||||||
const formatNumber = (num) => {
|
const formatNumber = (num) => {
|
||||||
if (num === null || num === undefined) return '—';
|
if (num === null || num === undefined) return '—';
|
||||||
@ -242,19 +326,29 @@ const History = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 🟩 Updated tableRows with expandable details
|
// 🟩 Updated tableRows with expandable details
|
||||||
const handlePageChange = (newPage) => {
|
const handlePageChange = React.useCallback((page) => {
|
||||||
setPagination(prev => ({
|
setPagination(prev => ({
|
||||||
...prev,
|
...prev,
|
||||||
currentPage: newPage,
|
currentPage: page,
|
||||||
}));
|
}));
|
||||||
};
|
}, []);
|
||||||
|
|
||||||
const handlePageSizeChange = (newSize) => {
|
const handlePageSizeChange = React.useCallback((newSize) => {
|
||||||
setPagination(prev => ({
|
setPagination(prev => ({
|
||||||
...prev,
|
...prev,
|
||||||
pageSize: newSize,
|
pageSize: newSize,
|
||||||
currentPage: 1, // Reset to first page when page size changes
|
currentPage: 1, // Reset to first page when page size changes
|
||||||
}));
|
}));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Calculate pagination range text
|
||||||
|
const getPaginationRangeText = () => {
|
||||||
|
if (filteredRows.length === 0) {
|
||||||
|
return '0-0 of 0';
|
||||||
|
}
|
||||||
|
const start = (pagination.currentPage - 1) * pagination.pageSize + 1;
|
||||||
|
const end = Math.min(start + pagination.pageSize - 1, pagination.totalItems);
|
||||||
|
return `${start}-${end} of ${pagination.totalItems}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const downloadCsv = () => {
|
const downloadCsv = () => {
|
||||||
@ -281,18 +375,76 @@ const History = () => {
|
|||||||
// Convert data to CSV rows
|
// Convert data to CSV rows
|
||||||
const csvRows = [
|
const csvRows = [
|
||||||
headers.join(','),
|
headers.join(','),
|
||||||
...filteredRows.map(row =>
|
...filteredRows.map(row => {
|
||||||
[
|
// Get actor(s) - handle both array and single value
|
||||||
getFieldValue(formatDateTime(row.created_at)),
|
let actors = '';
|
||||||
getFieldValue(row.year),
|
if (Array.isArray(row.actor)) {
|
||||||
getFieldValue(row.quarter),
|
actors = row.actor.filter(a => a && a.trim() !== '').join(', ');
|
||||||
getFieldValue(row.hs_code),
|
} else if (row.actor) {
|
||||||
getFieldValue(row.product_name),
|
actors = row.actor;
|
||||||
getFieldValue(formatStatus(row.status)),
|
} else {
|
||||||
(row.actors && row.actors.length ? row.actors.join(', ') : '-').replace(/"/g, '""'),
|
actors = '-';
|
||||||
'Quantity and cost updates' // This is a placeholder for the details column
|
}
|
||||||
].map(field => `"${field}"`).join(',')
|
|
||||||
)
|
// Calculate quantity and cost changes from details
|
||||||
|
const details = row.details || [];
|
||||||
|
const quantityChange = details
|
||||||
|
.filter(d => d.column.includes('quantity'))
|
||||||
|
.reduce((sum, d) => sum + (Number(d.new) - Number(d.old)), 0);
|
||||||
|
|
||||||
|
const costChange = details
|
||||||
|
.filter(d => d.column.includes('cost'))
|
||||||
|
.reduce((sum, d) => sum + (Number(d.new) - Number(d.old)), 0);
|
||||||
|
|
||||||
|
// Format the summary line with actual values
|
||||||
|
const summaryParts = [];
|
||||||
|
|
||||||
|
if (details.some(d => d.column.includes('quantity'))) {
|
||||||
|
const change = details
|
||||||
|
.filter(d => d.column.includes('quantity'))
|
||||||
|
.reduce((sum, d) => sum + (Number(d.new) - Number(d.old)), 0);
|
||||||
|
|
||||||
|
if (change !== 0) {
|
||||||
|
summaryParts.push(`Quantity updated: ${change > 0 ? '+' : ''}${change.toLocaleString('en-IN')}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (details.some(d => d.column.includes('cost'))) {
|
||||||
|
const change = details
|
||||||
|
.filter(d => d.column.includes('cost'))
|
||||||
|
.reduce((sum, d) => sum + (Number(d.new) - Number(d.old)), 0);
|
||||||
|
|
||||||
|
if (change !== 0) {
|
||||||
|
const absChange = Math.abs(change);
|
||||||
|
const sign = change > 0 ? '+' : '-';
|
||||||
|
summaryParts.push(`Cost updated: ${sign}AED ${absChange.toLocaleString('en-IN', {
|
||||||
|
minimumFractionDigits: 2,
|
||||||
|
maximumFractionDigits: 2
|
||||||
|
})}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const displayText = summaryParts.length > 0
|
||||||
|
? summaryParts.join('; ')
|
||||||
|
: 'No changes';
|
||||||
|
|
||||||
|
// Create the row with proper escaping
|
||||||
|
const rowData = [
|
||||||
|
formatExportDateTime(row.created_at || row.submission_date) || '-',
|
||||||
|
row.year || '-',
|
||||||
|
row.quarter || '-',
|
||||||
|
row.hs_code || '-',
|
||||||
|
row.product_name || '-',
|
||||||
|
formatStatus(row.status) || '-',
|
||||||
|
actors,
|
||||||
|
displayText // Use the summary line here instead of detailsText
|
||||||
|
];
|
||||||
|
|
||||||
|
// Properly escape and quote CSV fields
|
||||||
|
return rowData
|
||||||
|
.map(field => `"${String(field || '').replace(/"/g, '""')}"`)
|
||||||
|
.join(',');
|
||||||
|
})
|
||||||
];
|
];
|
||||||
|
|
||||||
// Create CSV content
|
// Create CSV content
|
||||||
@ -312,66 +464,98 @@ const History = () => {
|
|||||||
document.body.removeChild(link);
|
document.body.removeChild(link);
|
||||||
};
|
};
|
||||||
|
|
||||||
const tableRows = filteredRows.map((entry, index) => {
|
const tableRows = auditHistory.map((entry, index) => {
|
||||||
const isExpanded = expandedRow === index;
|
const isExpanded = expandedRow === index;
|
||||||
return [
|
const details = entry.details || [];
|
||||||
formatDateTime(entry.created_at),
|
|
||||||
entry.year || '—',
|
|
||||||
entry.quarter || '—',
|
|
||||||
entry.hs_code || '—',
|
|
||||||
entry.product_name || '—',
|
|
||||||
formatStatus(entry.status),
|
|
||||||
entry.actors ? entry.actors.join(', ') : '—',
|
|
||||||
<div className="flex flex-col w-full">
|
|
||||||
<div className="flex items-center justify-between text-sm text-gray-800">
|
|
||||||
<span>
|
|
||||||
Quantity updated -; Cost updated -
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<button
|
// Check if there are quantity or cost changes
|
||||||
onClick={() => handleToggleDetails(index)}
|
const hasQuantityChanges = details.some(d => d.column.includes('quantity'));
|
||||||
className="flex items-center justify-center w-5 h-5 border border-gray-300 rounded hover:bg-gray-100"
|
const hasCostChanges = details.some(d => d.column.includes('cost'));
|
||||||
|
|
||||||
|
return [
|
||||||
|
formatDateTime(entry.submission_date || entry.created_at),
|
||||||
|
entry.year || '—',
|
||||||
|
entry.quarter || '—',
|
||||||
|
entry.hs_code || '—',
|
||||||
|
entry.product_name || '—',
|
||||||
|
<div className="flex justify-center">
|
||||||
|
<Badge variant={toVariant(entry.status)}>
|
||||||
|
{formatStatus(entry.status)}
|
||||||
|
</Badge>
|
||||||
|
</div>,
|
||||||
|
entry.actor || '—',
|
||||||
|
<div className="flex flex-col w-full">
|
||||||
|
<div className="flex items-center justify-between text-sm pt-2 text-gray-800">
|
||||||
|
<span>
|
||||||
|
{hasQuantityChanges ? 'Quantity updated' : ''}
|
||||||
|
{hasQuantityChanges && hasCostChanges ? '; ' : ''}
|
||||||
|
{hasCostChanges ? 'Cost updated' : ''}
|
||||||
|
{!hasQuantityChanges && !hasCostChanges ? 'No changes' : ''}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
handleToggleDetails(index);
|
||||||
|
}}
|
||||||
|
className="flex items-center justify-center w-5 h-5 border border-gray-300 rounded hover:bg-gray-100"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
width="12"
|
||||||
|
height="12"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
className={`transition-transform duration-200 ${isExpanded ? 'rotate-180' : ''}`}
|
||||||
>
|
>
|
||||||
<svg
|
<path
|
||||||
width="12"
|
d="M6 9L12 15L18 9"
|
||||||
height="12"
|
stroke="currentColor"
|
||||||
viewBox="0 0 24 24"
|
strokeWidth="2"
|
||||||
fill="none"
|
strokeLinecap="round"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
strokeLinejoin="round"
|
||||||
className={`transition-transform duration-200 ${isExpanded ? 'rotate-180' : ''}`}
|
/>
|
||||||
>
|
</svg>
|
||||||
<path
|
</button>
|
||||||
d="M6 9L12 15L18 9"
|
|
||||||
stroke="currentColor"
|
|
||||||
strokeWidth="2"
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{isExpanded && (
|
|
||||||
<div className="mt-2 ml-2 border border-gray-200 rounded p-2 bg-gray-50 text-sm text-gray-700">
|
|
||||||
<div className="flex gap-6 mb-2">
|
|
||||||
<div>
|
|
||||||
<div className="font-medium">Quantity Updated:</div>
|
|
||||||
<div>-</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="font-medium">Cost Updated:</div>
|
|
||||||
<div>-</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="font-medium">Reason for variations:</div>
|
|
||||||
<div>-</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
];
|
|
||||||
});
|
{isExpanded && details.length > 0 && (
|
||||||
|
<div className="mt-2 ml-1 border border-gray-200 rounded p-2 bg-gray-50 text-sm text-gray-700">
|
||||||
|
<div className="grid grid-cols-2 gap-4">
|
||||||
|
<div>
|
||||||
|
<div className="font-medium">Quantity Updated: </div>
|
||||||
|
<div>
|
||||||
|
{details
|
||||||
|
.filter(d => d.column.includes('quantity'))
|
||||||
|
.reduce((sum, d) => sum + (Number(d.new) - Number(d.old)), 0)
|
||||||
|
.toLocaleString('en-IN')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="font-medium">Cost Updated:</div>
|
||||||
|
<div>
|
||||||
|
{details
|
||||||
|
.filter(d => d.column.includes('cost'))
|
||||||
|
.reduce((sum, d) => sum + (Number(d.new) - Number(d.old)), 0)
|
||||||
|
.toLocaleString('en-IN', {
|
||||||
|
style: 'currency',
|
||||||
|
currency: 'AED',
|
||||||
|
minimumFractionDigits: 2,
|
||||||
|
maximumFractionDigits: 2
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="font-medium">Reason for variations: -</div>
|
||||||
|
<div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
const toolbar = (
|
const toolbar = (
|
||||||
<div className="px-6 py-4 flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
|
<div className="px-6 py-4 flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
|
||||||
@ -386,11 +570,16 @@ const History = () => {
|
|||||||
<div className="relative w-full md:w-56">
|
<div className="relative w-full md:w-56">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
|
placeholder="Search..."
|
||||||
value={searchTerm}
|
value={searchTerm}
|
||||||
onChange={(e) => setSearchTerm(e.target.value)}
|
onChange={(e) => {
|
||||||
placeholder="Search submissions"
|
const value = e.target.value;
|
||||||
className="w-full h-10 rounded-md border border-[#E5E7EB] pl-10 pr-3 text-sm focus:outline-none"
|
setSearchTerm(value);
|
||||||
|
console.log("🔍 Searching for:", value);
|
||||||
|
}}
|
||||||
|
className="w-64 h-10 border border-gray-300 rounded-md px-3 text-sm focus:outline-none focus:ring-1 focus:ring-blue-500"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<img src={searchIconSrc} alt="Search" className="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 h-5 w-5" />
|
<img src={searchIconSrc} alt="Search" className="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 h-5 w-5" />
|
||||||
</div>
|
</div>
|
||||||
<div className="relative w-full md:w-40">
|
<div className="relative w-full md:w-40">
|
||||||
@ -512,35 +701,60 @@ const History = () => {
|
|||||||
<polyline points="6 9 12 15 18 9" />
|
<polyline points="6 9 12 15 18 9" />
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
|
{/* Replace both HS Code and Product dropdowns with this */}
|
||||||
|
<div className="relative">
|
||||||
|
<select
|
||||||
|
value={hscodeFilter}
|
||||||
|
onChange={(e) => {
|
||||||
|
console.log("HS filter selected:", e.target.value);
|
||||||
|
setHscodeFilter(e.target.value);
|
||||||
|
}}
|
||||||
|
className="h-10 w-48 rounded-md border border-[#E2E8F0] bg-white pl-3 pr-8 text-sm text-[#232528] focus:outline-none cursor-pointer appearance-none"
|
||||||
|
>
|
||||||
|
<option value="">HS Codes & Products</option>
|
||||||
|
{hscodeOptions.map((option) => (
|
||||||
|
<option
|
||||||
|
key={option.id}
|
||||||
|
value={option.product_name} // ✅ this is the fix
|
||||||
|
>
|
||||||
|
{option.hs_code
|
||||||
|
? `${option.hs_code} - ${option.product_name || ""}`.trim()
|
||||||
|
: option.label}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
{isLoadingHscodes ? (
|
||||||
|
<div className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4 border-2 border-t-[#6B7280] border-r-transparent border-b-transparent border-l-transparent rounded-full animate-spin"></div>
|
||||||
|
) : (
|
||||||
|
<svg
|
||||||
|
className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4 text-[#6B7280]"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="2"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
>
|
||||||
|
<polyline points="6 9 12 15 18 9" />
|
||||||
|
</svg>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<select
|
<select
|
||||||
value={hscodeFilter}
|
value={selectedActor}
|
||||||
onChange={(e) => setHscodeFilter(e.target.value)}
|
onChange={(e) => setSelectedActor(e.target.value)}
|
||||||
disabled={isLoadingHscodes}
|
className="h-10 rounded-md border border-[#E2E8F0] bg-white pl-3 pr-8 text-sm text-[#232528] focus:outline-none cursor-pointer appearance-none"
|
||||||
className={`h-[40px] w-[170px] rounded-md border border-[#E2E8F0] bg-white pl-3 pr-8 text-sm text-[#232528] focus:outline-none cursor-pointer appearance-none ${isLoadingHscodes ? 'opacity-70' : ''}`}
|
>
|
||||||
>
|
<option value="">Actors</option>
|
||||||
<option value="">HS Code/Product</option>
|
{actorOptions.map((actor) => (
|
||||||
{hscodeOptions.map((option) => (
|
<option key={actor.value} value={actor.value}>
|
||||||
<option key={option.id || option.value} value={option.id || option.value}>
|
{actor.label}
|
||||||
{option.hs_code ? `${option.hs_code} - ${option.product_name || ''}` : option.label}
|
</option>
|
||||||
</option>
|
))}
|
||||||
))}
|
</select>
|
||||||
</select>
|
|
||||||
{isLoadingHscodes ? (
|
|
||||||
<div className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4 border-2 border-t-[#6B7280] border-r-transparent border-b-transparent border-l-transparent rounded-full animate-spin"></div>
|
|
||||||
) : (
|
|
||||||
<svg className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4 text-[#6B7280]" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
||||||
<polyline points="6 9 12 15 18 9" />
|
|
||||||
</svg>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className="relative">
|
|
||||||
<select
|
|
||||||
className="h-10 w-32 rounded-md border border-[#E2E8F0] bg-white pl-3 pr-8 text-sm text-[#232528] focus:outline-none cursor-pointer appearance-none"
|
|
||||||
disabled
|
|
||||||
>
|
|
||||||
<option value="">Actor</option>
|
|
||||||
</select>
|
|
||||||
<svg className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4 text-[#6B7280]" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
<svg className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4 text-[#6B7280]" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||||
<polyline points="6 9 12 15 18 9" />
|
<polyline points="6 9 12 15 18 9" />
|
||||||
</svg>
|
</svg>
|
||||||
@ -553,7 +767,6 @@ const History = () => {
|
|||||||
>
|
>
|
||||||
<option value="all">Status</option>
|
<option value="all">Status</option>
|
||||||
<option value="approved">Approved</option>
|
<option value="approved">Approved</option>
|
||||||
<option value="pending">Pending</option>
|
|
||||||
<option value="rejected">Rejected</option>
|
<option value="rejected">Rejected</option>
|
||||||
<option value="submitted">Submitted</option>
|
<option value="submitted">Submitted</option>
|
||||||
</select>
|
</select>
|
||||||
@ -576,7 +789,7 @@ const History = () => {
|
|||||||
type="text"
|
type="text"
|
||||||
value={searchTerm}
|
value={searchTerm}
|
||||||
onChange={(e) => setSearchTerm(e.target.value)}
|
onChange={(e) => setSearchTerm(e.target.value)}
|
||||||
placeholder="Search establishment"
|
placeholder="Search Product"
|
||||||
className="w-full h-10 rounded-md border border-[#E2E8F0] pl-10 pr-3 text-sm text-[#232528] focus:outline-none"
|
className="w-full h-10 rounded-md border border-[#E2E8F0] pl-10 pr-3 text-sm text-[#232528] focus:outline-none"
|
||||||
/>
|
/>
|
||||||
<img
|
<img
|
||||||
@ -599,10 +812,23 @@ const History = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{filteredRows.length === 0 && !loading ? (
|
{filteredRows.length === 0 && !loading ? (
|
||||||
<div className="flex flex-col items-center justify-center py-12">
|
<div className="w-full flex flex-col h-5items-center justify-start pt-1 pb-7 text-center">
|
||||||
<p className="text-gray-500 text-lg">No details found</p>
|
<div className="w-full max-w-md mx-auto">
|
||||||
{/* <p className="text-gray-400 text-sm mt-1">Try adjusting your search or filter to find what you're looking for.</p> */}
|
{/* <svg
|
||||||
</div>
|
className="w-16 h-16 text-gray-400 mx-auto mb-2"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
|
||||||
|
</svg> */}
|
||||||
|
<h3 className="text-lg font-medium text-[#92722A] pt-4 text-center">No submissions History found</h3>
|
||||||
|
{/* <p className="mt-1 text-sm text-gray-500">
|
||||||
|
No submission history is available for the current filters
|
||||||
|
</p> */}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<Table
|
<Table
|
||||||
headers={headers}
|
headers={headers}
|
||||||
@ -622,20 +848,20 @@ const History = () => {
|
|||||||
if (ci === 5) { // Status column
|
if (ci === 5) { // Status column
|
||||||
return <Badge variant={toVariant(filteredRows[ri]?.status)}>{formatStatus(filteredRows[ri]?.status)}</Badge>;
|
return <Badge variant={toVariant(filteredRows[ri]?.status)}>{formatStatus(filteredRows[ri]?.status)}</Badge>;
|
||||||
}
|
}
|
||||||
if (ci === 6) {
|
// if (ci === 6) {
|
||||||
const submission = filteredRows[ri];
|
// const submission = filteredRows[ri];
|
||||||
const disabled = !submission;
|
// const disabled = !submission;
|
||||||
return (
|
// return (
|
||||||
<button
|
// <button
|
||||||
className={`text-[#92722A] hover:underline ${disabled ? 'cursor-not-allowed opacity-50 hover:no-underline' : ''}`}
|
// className={`text-[#92722A] hover:underline ${disabled ? 'cursor-not-allowed opacity-50 hover:no-underline' : ''}`}
|
||||||
type="button"
|
// type="button"
|
||||||
disabled={disabled}
|
// disabled={disabled}
|
||||||
onClick={() => handleViewDetails(submission)}
|
// onClick={() => handleViewDetails(submission)}
|
||||||
>
|
// >
|
||||||
{String(value)}
|
// {String(value)}
|
||||||
</button>
|
// </button>
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
return value;
|
return value;
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -314,6 +314,7 @@ const Survey = () => {
|
|||||||
return {
|
return {
|
||||||
quarter: establishmentData?.quarter ?? '',
|
quarter: establishmentData?.quarter ?? '',
|
||||||
year: parseNumber(establishmentData?.year),
|
year: parseNumber(establishmentData?.year),
|
||||||
|
status: 'Submitted',
|
||||||
emirati_male: parseNumber(info.emiratiMale),
|
emirati_male: parseNumber(info.emiratiMale),
|
||||||
emirati_female: parseNumber(info.emiratiFemale),
|
emirati_female: parseNumber(info.emiratiFemale),
|
||||||
non_emirati_male: parseNumber(info.nonEmiratiMale),
|
non_emirati_male: parseNumber(info.nonEmiratiMale),
|
||||||
|
|||||||
@ -103,6 +103,26 @@ export const getSubmissionHistoryByEstablishment = async (establishmentId, confi
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getSubmissionAuditHistory = async (establishmentId, params = {}) => {
|
||||||
|
try {
|
||||||
|
if (!establishmentId) {
|
||||||
|
throw new Error('Establishment ID is required');
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await getRequest('/submission-audit-history', {
|
||||||
|
params: {
|
||||||
|
establishment_id: establishmentId,
|
||||||
|
...params // Spread any additional parameters (year, quarter, product_id)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return response.data || response;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching submission audit history:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
getSubmissions,
|
getSubmissions,
|
||||||
submitSurvey,
|
submitSurvey,
|
||||||
@ -110,5 +130,6 @@ export default {
|
|||||||
fetchSubmissionDetail,
|
fetchSubmissionDetail,
|
||||||
getQuarterPeriods,
|
getQuarterPeriods,
|
||||||
getPreviousForecastData,
|
getPreviousForecastData,
|
||||||
getSubmissionHistoryByEstablishment
|
getSubmissionHistoryByEstablishment,
|
||||||
|
getSubmissionAuditHistory
|
||||||
};
|
};
|
||||||
Loading…
Reference in New Issue
Block a user