Compare commits

...

10 Commits

Author SHA1 Message Date
Swetha-Josh
5fd663a7d0 updates 2026-06-25 16:16:14 +05:30
Swetha-Josh
812a74455e updates 2026-06-24 13:10:46 +05:30
Swetha-Josh
01203f955c updates 2026-06-23 11:45:36 +05:30
Swetha-Josh
3daf9f03d3 changes 2026-06-22 14:30:18 +05:30
Swetha-Josh
6929a4802c Bug fixes 2026-06-18 11:25:49 +05:30
Swetha-Josh
bb16e2abd0 changes 2026-06-16 10:59:56 +05:30
Swetha-Josh
81061d2e90 total column removed 2026-06-12 17:21:56 +05:30
Swetha-Josh
32d87c634a bug fixes 2026-06-12 11:18:30 +05:30
naveen prabhu
01be34ae6f filter fixed 2026-06-10 16:52:45 +05:30
naveen prabhu
10df4cb741 filter fixed 2026-06-10 16:50:12 +05:30
10 changed files with 313 additions and 151 deletions

View File

@ -434,21 +434,29 @@ export const SelectField = ({
className={`w-full text-sm focus:outline-none ${className}`} className={`w-full text-sm focus:outline-none ${className}`}
style={{ style={{
...inputStyle, ...inputStyle,
height: 'auto', // override fixed height
minHeight: '40px',
cursor: readOnly ? 'not-allowed' : 'pointer', cursor: readOnly ? 'not-allowed' : 'pointer',
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
justifyContent: 'space-between', justifyContent: 'space-between',
minHeight: '40px', padding: '8px 16px',
padding: '0 16px' }}
}}
onClick={toggleDropdown} onClick={toggleDropdown}
onFocus={handleFocus} onFocus={handleFocus}
onBlur={handleBlur} onBlur={handleBlur}
tabIndex={readOnly ? -1 : 0} tabIndex={readOnly ? -1 : 0}
> >
<span style={{ color: hasValue ? '#232528' : '#9CA3AF' }}> <span
style={{
color: hasValue ? '#232528' : '#9CA3AF',
flex: 1,
whiteSpace: 'normal',
lineHeight: '20px'
}}
>
{getDisplayValue()} {getDisplayValue()}
</span> </span>
{showClear ? ( {showClear ? (
<button <button
type="button" type="button"

View File

@ -1284,9 +1284,12 @@ setAdditionalForecastMonths([
> >
<thead> <thead>
<tr> <tr>
<th rowSpan="2" className="bg-[#F2ECCF] text-[#92722A] px-4 py-1 text-xs font-semibold uppercase align-middle border-r border-[#E5E7EB]"> <th
rowSpan="2"
className="w-[140px] bg-[#F2ECCF] text-[#92722A] px-4 py-1 text-xs font-semibold uppercase align-middle border-r border-[#E5E7EB]"
>
Metric Metric
</th> </th>
{showPreviousNext ? ( {showPreviousNext ? (
<> <>
@ -1453,9 +1456,14 @@ setAdditionalForecastMonths([
<tbody> <tbody>
<tr className="border-t border-[#E5E7EB]"> <tr className="border-t border-[#E5E7EB]">
<td className="bg-[#FFFCF2] px-4 py-3 font-medium text-[#232528] border border-[#E5E7EB]"> <td className="w-[180px] bg-[#FFFCF2] px-4 py-3 font-medium text-[#232528] border border-[#E5E7EB] align-top">
Quantity ({product?.unit?.uom || 'units'}) <div className="flex flex-col leading-5">
</td> <span>Quantity</span>
<span className="text-sm">
({product?.unit?.uom || 'units'})
</span>
</div>
</td>
{showPreviousNext ? ( {showPreviousNext ? (
<> <>

View File

@ -92,7 +92,7 @@ const ManageSubmissions = () => {
const [isRejecting, setIsRejecting] = React.useState(false); const [isRejecting, setIsRejecting] = React.useState(false);
const [rejectReason, setRejectReason] = React.useState(''); const [rejectReason, setRejectReason] = React.useState('');
const [showRejectError, setShowRejectError] = React.useState(false); const [showRejectError, setShowRejectError] = React.useState(false);
const pageSize = 10; const [pageSize, setPageSize] = React.useState(10);
const [isInitialLoad, setIsInitialLoad] = React.useState(true); const [isInitialLoad, setIsInitialLoad] = React.useState(true);
const [filters, setFilters] = React.useState({ const [filters, setFilters] = React.useState({
search: '', search: '',
@ -398,7 +398,7 @@ React.useEffect(() => {
const term = search.trim().toLowerCase(); const term = search.trim().toLowerCase();
const filteredItems = submissions.filter((item) => { const filteredItems = submissions.filter((item) => {
if (!item) return false; if (!item || item.status === 'Draft') return false;
const allValues = Object.values(item) const allValues = Object.values(item)
.map((v) => String(v ?? '').toLowerCase()) .map((v) => String(v ?? '').toLowerCase())
@ -423,16 +423,21 @@ React.useEffect(() => {
return filteredItems; return filteredItems;
}, [submissions, search, year, quarter, emirate, status]); }, [submissions, search, year, quarter, emirate, status]);
const summaryCounts = React.useMemo( const nonDraftSubmissions = React.useMemo(
() => ({ () => submissions.filter((i) => i.status !== 'Draft'),
total: submissions.length,
approved: submissions.filter((i) => i.status === 'Approved').length,
submitted: submissions.filter((i) => i.status === 'Submitted').length,
rejected: submissions.filter((i) => i.status === 'Rejected').length,
resubmitted: submissions.filter((i) => i.status === 'Resubmitted').length,
}),
[submissions] [submissions]
); );
const summaryCounts = React.useMemo(
() => ({
total: nonDraftSubmissions.length,
approved: nonDraftSubmissions.filter((i) => i.status === 'Approved').length,
submitted: nonDraftSubmissions.filter((i) => i.status === 'Submitted').length,
rejected: nonDraftSubmissions.filter((i) => i.status === 'Rejected').length,
resubmitted: nonDraftSubmissions.filter((i) => i.status === 'Resubmitted').length,
}),
[nonDraftSubmissions]
);
const headers = [ const headers = [
'Establishment', 'Establishment',
@ -694,7 +699,12 @@ React.useEffect(() => {
onPageChange: setCurrentPage, onPageChange: setCurrentPage,
pageSize, pageSize,
totalItems: filtered.length, totalItems: filtered.length,
}} pageSizeOptions: [10, 20, 50, 100],
onPageSizeChange: (size) => {
setPageSize(size);
setCurrentPage(1);
}
}}
renderCell={(value, _, columnIndex) => { renderCell={(value, _, columnIndex) => {
if (columnIndex === 7) if (columnIndex === 7)
return ( return (

View File

@ -1775,7 +1775,7 @@ const displayedRows = sortedProfiles.map((item) => {
item.establishmentName || "-", item.establishmentName || "-",
// Contact Name (userProfileName contactPersonName createdBy "-") // Contact Name (userProfileName contactPersonName createdBy "-")
item.userProfileName || item.contactPersonName || "-", // item.userProfileName || item.contactPersonName || "-",
// Emirate // Emirate
item.emirate || "-", item.emirate || "-",
@ -2617,7 +2617,7 @@ const handleView = async (id) => {
const requiredFields = [ const requiredFields = [
{ field: 'userProfileName', label: 'Name' }, { field: 'userProfileName', label: 'Name' },
{ field: 'userProfileEmail', label: 'Email' }, { field: 'userProfileEmail', label: 'Email' },
{ field: 'contactName', label: 'Contact Name' }, // { field: 'contactName', label: 'Contact Name' },
{ field: 'contactAddress', label: 'Contact Address' }, { field: 'contactAddress', label: 'Contact Address' },
{ field: 'contactEmirate', label: 'Emirate' }, { field: 'contactEmirate', label: 'Emirate' },
{ field: 'contactMobileNumber', label: 'Mobile Number' }, { field: 'contactMobileNumber', label: 'Mobile Number' },
@ -3411,7 +3411,7 @@ const handleImport = async () => {
<Table <Table
headers={[ headers={[
{ name: 'Establishment Name', key: 'establishmentName', sortable: true, className: 'whitespace-nowrap' }, { name: 'Establishment Name', key: 'establishmentName', sortable: true, className: 'whitespace-nowrap' },
{ name: 'Contact Name', key: 'contactName', sortable: true, className: 'whitespace-nowrap' }, // { name: 'Contact Name', key: 'contactName', sortable: true, className: 'whitespace-nowrap' },
{ name: 'Emirate', key: 'emirate', sortable: true, className: 'whitespace-nowrap' }, { name: 'Emirate', key: 'emirate', sortable: true, className: 'whitespace-nowrap' },
{ name: 'ISIC Code', key: 'isicCode', sortable: false, className: 'whitespace-nowrap' }, { name: 'ISIC Code', key: 'isicCode', sortable: false, className: 'whitespace-nowrap' },
{ name: 'Establishment ID', key: 'establishmentId', sortable: true, className: 'whitespace-nowrap' }, { name: 'Establishment ID', key: 'establishmentId', sortable: true, className: 'whitespace-nowrap' },
@ -3467,7 +3467,7 @@ const handleImport = async () => {
}} }}
columnWidths={[ columnWidths={[
300, // Establishment Name (increased from 250) 300, // Establishment Name (increased from 250)
180, // Contact Name (increased from 150) // 180, // Contact Name (increased from 150)
150, // Emirate (increased from 120) 150, // Emirate (increased from 120)
150, // ISIC Code (increased from 120) 150, // ISIC Code (increased from 120)
200, // Establishment ID (increased from 150) 200, // Establishment ID (increased from 150)

View File

@ -622,7 +622,7 @@ const IsicHsCodes = () => {
// Filter data based on search term // Filter data based on search term
React.useEffect(() => { React.useEffect(() => {
if (!searchTerm.trim()) { if (!searchTerm?.trim()) {
setFilteredData(rowsData); setFilteredData(rowsData);
} else { } else {
const lowercasedSearch = searchTerm.toLowerCase(); const lowercasedSearch = searchTerm.toLowerCase();
@ -1623,8 +1623,8 @@ const handleExportCSV = () => {
<option value="">Select Unit</option> <option value="">Select Unit</option>
{unitOptions.map((option) => ( {unitOptions.map((option) => (
<option key={option.value} value={option.value}> <option key={option.value} value={option.value}>
{option.label.split('-')[1].trim()} {option?.label}
</option> </option>
))} ))}
</select> </select>
)} )}

View File

@ -19,7 +19,8 @@ import { Breadcrumbs } from '@mui/material';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import Card from '@/components/common/Card'; import Card from '@/components/common/Card';
import triggerIcon from '@/assets/trigger.png'; import triggerIcon from '@/assets/trigger.png';
import { getManufacturingIndex, getManufacturingMonthlyOverview, autoSubmitSurvey } from '@/services/manufacturingIndex/ManufacturingIndex'; import { getManufacturingIndex, getManufacturingMonthlyOverview, autoSubmitSurvey, getManufacturingIndexFiltered } from '@/services/manufacturingIndex/ManufacturingIndex';
import apiClient from '@/services/api/apiClient';
// Import popup components // Import popup components
import ManufacturingTotal from './ManufacturingIndexPopup/ManufacturingTotal'; import ManufacturingTotal from './ManufacturingIndexPopup/ManufacturingTotal';
@ -27,6 +28,7 @@ import ISIC2Digit from './ManufacturingIndexPopup/ISIC2Digit';
import ISIC3Digit from './ManufacturingIndexPopup/ISIC3Digit'; import ISIC3Digit from './ManufacturingIndexPopup/ISIC3Digit';
import ISIC4Digit from './ManufacturingIndexPopup/ISIC4Digit'; import ISIC4Digit from './ManufacturingIndexPopup/ISIC4Digit';
// Custom components // Custom components
const SelectField = (props) => ( const SelectField = (props) => (
<BaseSelectField <BaseSelectField
@ -58,20 +60,27 @@ const ManufacturingIndex = () => {
const [monthlyOverviewData, setMonthlyOverviewData] = useState(null); const [monthlyOverviewData, setMonthlyOverviewData] = useState(null);
const [isPopupOpen, setIsPopupOpen] = useState(false); const [isPopupOpen, setIsPopupOpen] = useState(false);
const [apiLoading, setApiLoading] = useState(false); const [apiLoading, setApiLoading] = useState(false);
const [quarter, setQuarter] = useState('Q2'); const [quarter, setQuarter] = useState('All');
const [surveySubmitLoading, setSurveySubmitLoading] = useState(false); const [surveySubmitLoading, setSurveySubmitLoading] = useState(false);
const [surveySubmitStatus, setSurveySubmitStatus] = useState(''); const [surveySubmitStatus, setSurveySubmitStatus] = useState('');
const [surveySubmitError, setSurveySubmitError] = useState(null); const [surveySubmitError, setSurveySubmitError] = useState(null);
const [baseYearLoading, setBaseYearLoading] = useState(false);
const [baseYearStatus, setBaseYearStatus] = useState('');
const [baseYearError, setBaseYearError] = useState('');
const [nextScheduledRun, setNextScheduledRun] = useState(''); // Default value const [nextScheduledRun, setNextScheduledRun] = useState(''); // Default value
const [refreshKey, setRefreshKey] = useState(0); const [refreshKey, setRefreshKey] = useState(0);
const [pagination, setPagination] = useState({ const [pagination, setPagination] = useState({
currentPage: 1, currentPage: 1,
pageSize: 20, pageSize: 10,
totalItems: 0 totalItems: 0
}); });
useEffect(() => {
applyFilters(year, searchMonth, allMonths, quarter);
}, [year, quarter, searchMonth, allMonths]);
// Fetch data from API // Fetch data from API
useEffect(() => { useEffect(() => {
const fetchData = async () => { const fetchData = async () => {
@ -128,9 +137,7 @@ const ManufacturingIndex = () => {
} }
// Debug: Log the actual data structure // Debug: Log the actual data structure
console.log('API Response:', response);
console.log('Data Array:', dataArray);
console.log('Sample item:', dataArray[0]);
// Format the data // Format the data
const formattedData = dataArray.map((item, index) => { const formattedData = dataArray.map((item, index) => {
@ -155,6 +162,14 @@ const ManufacturingIndex = () => {
const monthName = dateObj.toLocaleString('en-US', { month: 'short' }); const monthName = dateObj.toLocaleString('en-US', { month: 'short' });
year = item.year || dateObj.getFullYear() || 2025; year = item.year || dateObj.getFullYear() || 2025;
monthNumber = item.month || (dateObj.getMonth() + 1) || 1; monthNumber = item.month || (dateObj.getMonth() + 1) || 1;
// Normalize quarter value to form 'Q1'..'Q4'
let quarterVal = item.quarter || item.quarter_name || item.quarterName || '-';
if (quarterVal !== '-' && quarterVal !== null && quarterVal !== undefined) {
quarterVal = String(quarterVal).trim();
// If it's numeric like '2' or 2 -> convert to 'Q2'
if (/^\d+$/.test(quarterVal)) quarterVal = `Q${quarterVal}`;
quarterVal = quarterVal.toUpperCase();
}
return { return {
id: item.id || `${year}-${monthNumber}` || `item-${index}`, id: item.id || `${year}-${monthNumber}` || `item-${index}`,
@ -183,7 +198,7 @@ const ManufacturingIndex = () => {
timeZone: 'Asia/Dubai', timeZone: 'Asia/Dubai',
timeZoneName: 'short' timeZoneName: 'short'
}) : '-', }) : '-',
quarter: item.quarter || item.quarter_name || '-', quarter: quarterVal || '-',
totalWeight: item.total_weight || '-', totalWeight: item.total_weight || '-',
status: item.status || 'Completed', status: item.status || 'Completed',
rawData: item rawData: item
@ -191,7 +206,7 @@ const ManufacturingIndex = () => {
}); });
setAllMonths(formattedData); setAllMonths(formattedData);
applyFilters(year, searchMonth, formattedData); applyFilters(year, searchMonth, formattedData, quarter);
setPagination(prev => ({ setPagination(prev => ({
...prev, ...prev,
totalItems: formattedData.length totalItems: formattedData.length
@ -293,12 +308,14 @@ const ManufacturingIndex = () => {
setMonthlyOverviewData(null); setMonthlyOverviewData(null);
}; };
// Apply both year and search filters // Apply year, quarter and search filters
const applyFilters = (selectedYear, searchTerm, monthsData = allMonths) => { const applyFilters = (selectedYear, searchTerm, monthsData = allMonths, selectedQuarter = quarter) => {
const filtered = monthsData.filter(month => { const filtered = monthsData.filter(month => {
const matchesYear = selectedYear === 'All' || month.year.toString() === selectedYear; const matchesYear = selectedYear === 'All' || month.year.toString() === selectedYear;
const matchesSearch = searchTerm === '' || month.month.toLowerCase().includes(searchTerm.toLowerCase()); const matchesSearch = searchTerm === '' || month.month.toLowerCase().includes(searchTerm.toLowerCase());
return matchesYear && matchesSearch; const matchesQuarter = !selectedQuarter || selectedQuarter === 'All' || selectedQuarter === '-' ? true : (month.quarter || '').toUpperCase() === String(selectedQuarter).toUpperCase();
return matchesYear && matchesSearch && matchesQuarter;
}); });
setFilteredMonths(filtered); setFilteredMonths(filtered);
@ -310,21 +327,46 @@ const ManufacturingIndex = () => {
}; };
const handleYearChange = (e) => { const handleYearChange = (e) => {
const selectedYear = e.target.value; setYear(e.target.value);
setYear(selectedYear); };
applyFilters(selectedYear, searchMonth);
};
const handleSearchMonth = (e) => { const handleQuarterChange = (e) => {
const searchTerm = e.target.value; setQuarter(e.target.value);
setSearchMonth(searchTerm); };
applyFilters(year, searchTerm);
}; const handleSearchMonth = (e) => {
setSearchMonth(e.target.value);
};
const handleBaseYear = async () => {
setSurveySubmitLoading(true);
setSurveySubmitStatus('');
setSurveySubmitError('');
try {
const response = await apiClient.post('/calculate_base_year', {
baseYear: 2022,
forceRecalculate: true,
});
setSurveySubmitStatus(
response?.data?.message ||
'Base year calculation completed successfully.'
);
} catch (error) {
setSurveySubmitError(
error?.response?.data?.message ||
error.message ||
'Base year calculation failed.'
);
console.error('Error:', error);
} finally {
setSurveySubmitLoading(false);
}
};
const handleQuarterChange = (e) => {
const selectedQuarter = e.target.value;
setQuarter(selectedQuarter);
};
const handleTriggerData = async () => { const handleTriggerData = async () => {
setError(null); setError(null);
@ -339,12 +381,117 @@ const ManufacturingIndex = () => {
setSurveySubmitLoading(true); setSurveySubmitLoading(true);
try { try {
// Trigger backend calculate/auto-submit
const response = await autoSubmitSurvey(parseInt(year, 10), quarter); const response = await autoSubmitSurvey(parseInt(year, 10), quarter);
setSurveySubmitStatus( setSurveySubmitStatus(
response?.data?.message || 'Survey auto-submit request sent successfully.' response?.data?.message || 'Survey auto-submit request sent successfully.'
); );
setRefreshKey(prev => prev + 1);
// After auto-submit, fetch the filtered manufacturing index for selected year and quarter/all
try {
const filteredResp = await getManufacturingIndexFiltered(
parseInt(year, 10),
quarter === 'All' ? undefined : quarter
);
// Extract array similar to initial fetch
let dataArray = [];
if (Array.isArray(filteredResp)) {
dataArray = filteredResp;
} else if (filteredResp && filteredResp.data && Array.isArray(filteredResp.data)) {
dataArray = filteredResp.data;
} else if (filteredResp && filteredResp.data && typeof filteredResp.data === 'object') {
if (Array.isArray(filteredResp.data.manufacturingIndex) || Array.isArray(filteredResp.data.data)) {
dataArray = filteredResp.data.manufacturingIndex || filteredResp.data.data || [];
} else {
dataArray = Object.values(filteredResp.data);
}
} else {
const findArray = (obj) => {
if (Array.isArray(obj)) return obj;
if (typeof obj === 'object' && obj !== null) {
for (const key in obj) {
if (Array.isArray(obj[key])) return obj[key];
}
}
return [];
};
dataArray = findArray(filteredResp);
}
const formattedData = dataArray.map((item, index) => {
let dateObj = new Date();
let yearVal = 2025;
let monthNumber = 1;
if (item.reference_date) {
dateObj = new Date(item.reference_date);
} else if (item.date) {
dateObj = new Date(item.date);
} else if (item.referenceDate) {
dateObj = new Date(item.referenceDate);
} else if (item.year && item.month) {
yearVal = item.year;
monthNumber = item.month;
dateObj = new Date(yearVal, monthNumber - 1, 1);
}
const monthName = dateObj.toLocaleString('en-US', { month: 'short' });
yearVal = item.year || dateObj.getFullYear() || 2025;
monthNumber = item.month || (dateObj.getMonth() + 1) || 1;
// Normalize quarter value to form 'Q1'..'Q4'
let quarterVal = item.quarter || item.quarter_name || item.quarterName || '-';
if (quarterVal !== '-' && quarterVal !== null && quarterVal !== undefined) {
quarterVal = String(quarterVal).trim();
if (/^\d+$/.test(quarterVal)) quarterVal = `Q${quarterVal}`;
quarterVal = quarterVal.toUpperCase();
}
return {
id: item.id || `${yearVal}-${monthNumber}` || `item-${index}`,
month: `${monthName} ${yearVal}`,
monthName: monthName,
year: yearVal,
monthNumber: monthNumber,
index: item.manufacturing_index?.toString() || item.index?.toString() || item.manufacturingIndex?.toString() || '-',
mom: item.mom_change || item.mom || item.momChange ?
(parseFloat(item.mom_change || item.mom || item.momChange) > 0 ?
`+${item.mom_change || item.mom || item.momChange}` :
(item.mom_change || item.mom || item.momChange).toString()) :
'-',
yoy: item.yoy_change || item.yoy || item.yoyChange ?
(parseFloat(item.yoy_change || item.yoy || item.yoyChange) > 0 ?
`+${item.yoy_change || item.yoy || item.yoyChange}` :
(item.yoy_change || item.yoy || item.yoyChange).toString()) :
'-',
generated: item.generated_on || item.generatedOn || item.generated_at ?
new Date(item.generated_on || item.generatedOn || item.generated_at).toLocaleString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
timeZone: 'Asia/Dubai',
timeZoneName: 'short'
}) : '-',
quarter: quarterVal || '-',
totalWeight: item.total_weight || '-',
status: item.status || 'Completed',
rawData: item
};
});
setAllMonths(formattedData);
applyFilters(year, searchMonth, formattedData, quarter);
setPagination(prev => ({
...prev,
totalItems: formattedData.length,
currentPage: 1
}));
} catch (fetchErr) {
console.error('Error fetching filtered manufacturing index after trigger:', fetchErr);
}
} catch (error) { } catch (error) {
setSurveySubmitError( setSurveySubmitError(
error?.response?.data?.message || error.message || 'Survey auto-submit failed.' error?.response?.data?.message || error.message || 'Survey auto-submit failed.'
@ -595,9 +742,10 @@ const ManufacturingIndex = () => {
Coverage: Manufacturing (ISIC C) Coverage: Manufacturing (ISIC C)
</div> </div>
</div> </div>
</div> </div>
<div className="flex items-center gap-3 w-full sm:w-auto"> <div className="flex items-center gap-3">
<div className="flex-1 sm:flex-none w-40"> <div className="w-[180px]">
<div className="relative"> <div className="relative">
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none"> <div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<img src="/assets/images/material-symbols_search-rounded.svg" alt="Search" className="h-5 w-5" /> <img src="/assets/images/material-symbols_search-rounded.svg" alt="Search" className="h-5 w-5" />
@ -611,31 +759,39 @@ const ManufacturingIndex = () => {
/> />
</div> </div>
</div> </div>
<div className="flex items-center w-auto min-w-[88px]"> <div className="flex items-center w-[99px]">
<SelectField <SelectField
value={year} value={year}
onChange={handleYearChange} onChange={handleYearChange}
className="w-auto h-[40px]" className="w-full h-[40px]"
size="small" size="small"
options={years.map(y => ({ value: y, label: y }))} options={years.map(y => ({ value: y, label: y }))}
/> />
</div> </div>
<div className="flex items-center w-auto min-w-[72px]"> <div className="flex items-center w-[89px]">
<SelectField <SelectField
value={quarter} value={quarter}
onChange={handleQuarterChange} onChange={handleQuarterChange}
className="w-auto h-[40px]" className="w-full h-[40px]"
size="small" size="small"
options={['Q1', 'Q2', 'Q3', 'Q4'].map(q => ({ value: q, label: q }))} options={['All', 'Q1', 'Q2', 'Q3', 'Q4'].map(q => ({ value: q, label: q }))}
/> />
</div> </div>
<button <button
type="button" type="button"
className="h-10 px-3 xl:px-4 rounded-[6px] bg-[#F7F7F7] border border-[#C3C6CB] text-sm inline-flex items-center gap-2 hover:bg-gray-50 whitespace-nowrap font-medium text-[#232528]" className="h-[40px] px-4 rounded-[6px] bg-[#F7F7F7] border border-[#C3C6CB] text-sm inline-flex items-center gap-2 hover:bg-gray-50 whitespace-nowrap font-medium text-[#232528]"
onClick={handleTriggerData} onClick={handleTriggerData}
> >
<img src={triggerIcon} alt="Trigger" className="h-5 w-5" /> <img src={triggerIcon} alt="Trigger" className="h-5 w-5" />
Trigger Data Calculate
</button>
<button
type="button"
className="h-[40px] px-4 rounded-[6px] bg-[#F7F7F7] border border-[#C3C6CB] text-sm inline-flex items-center gap-2 hover:bg-gray-50 whitespace-nowrap font-medium text-[#232528]"
onClick={handleBaseYear}
>
<img src={triggerIcon} alt="Trigger" className="h-5 w-5" />
Base Year
</button> </button>
<button <button
className="h-10 px-3 xl:px-4 rounded-[6px] bg-[#F7F7F7] border border-[#C3C6CB] text-sm inline-flex items-center gap-2 hover:bg-gray-50 whitespace-nowrap" className="h-10 px-3 xl:px-4 rounded-[6px] bg-[#F7F7F7] border border-[#C3C6CB] text-sm inline-flex items-center gap-2 hover:bg-gray-50 whitespace-nowrap"
@ -645,6 +801,7 @@ const ManufacturingIndex = () => {
<span className="hidden xl:inline font-medium text-[#232528]">Export CSV</span> <span className="hidden xl:inline font-medium text-[#232528]">Export CSV</span>
<span className="xl:hidden font-medium text-[#232528]">Export</span> <span className="xl:hidden font-medium text-[#232528]">Export</span>
</button> </button>
</div> </div>
</div> </div>
{surveySubmitLoading || surveySubmitStatus || surveySubmitError ? ( {surveySubmitLoading || surveySubmitStatus || surveySubmitError ? (

View File

@ -181,7 +181,7 @@ const showToast = (message, type = 'success') => {
record.year, record.year,
record.quarter, record.quarter,
`${record.quarter} ${record.year}`, `${record.quarter} ${record.year}`,
10, // Always show 10 for Total Products // 10, // Always show 10 for Total Products
record.product_count || 0, // Show actual submitted products count record.product_count || 0, // Show actual submitted products count
record.total_cost !== undefined ? ( record.total_cost !== undefined ? (
<span className="flex items-center"> <span className="flex items-center">
@ -236,12 +236,22 @@ const showToast = (message, type = 'success') => {
</button> </button>
</div> </div>
) : ) :
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
<button
onClick={(e) => {
e.stopPropagation();
setSelectedSubmission(record);
}}
className="focus:outline-none"
>
<img <img
src="/assets/images/Eye.svg" src="/assets/images/Eye.svg"
alt="View" alt="View"
className="w-5 h-5 text-[#A88632] opacity-60 hover:opacity-100 transition-opacity" // className="w-5 h-5 opacity-60 hover:opacity-100 transition-opacity"
className="w-5 h-5 text-[#92722A] opacity-60 hover:opacity-100 transition-opacity"
style={{ filter: 'invert(36%) sepia(49%) saturate(680%) hue-rotate(1deg) brightness(89%) contrast(91%)' }}
/> />
</button>
{record.status === 'Rejected' && ( {record.status === 'Rejected' && (
<HiMiniArrowPathRoundedSquare <HiMiniArrowPathRoundedSquare
className={`w-5 h-5 transition-opacity ${ className={`w-5 h-5 transition-opacity ${
@ -491,7 +501,7 @@ const showToast = (message, type = 'success') => {
</div> </div>
<section className="bg-white rounded-lg border border-[#E2E8F0] shadow-sm"> <section className="bg-white rounded-lg border border-[#E2E8F0] shadow-sm">
<Table <Table
headers={['Year', 'Quarter', 'Submission Window', 'Total Products', 'Products Submitted', 'Total Value (AED)', 'Status', 'Date Submitted', 'Action']} headers={['Year', 'Quarter', 'Submission Window', 'Products Submitted', 'Total Value (AED)', 'Status', 'Date Submitted', 'Action']}
rows={rows} rows={rows}
beforeHeader={toolbar} beforeHeader={toolbar}
separated separated
@ -507,7 +517,7 @@ const showToast = (message, type = 'success') => {
</span> </span>
); );
} }
if (columnIndex === 8) { // Action column if (columnIndex === 7) { // Action column
return ( return (
<button <button
className="text-[#92722A] hover:underline text-sm font-medium focus:outline-none" className="text-[#92722A] hover:underline text-sm font-medium focus:outline-none"

View File

@ -9,8 +9,6 @@ const PublicContactForm = () => {
const [formData, setFormData] = useState({ const [formData, setFormData] = useState({
userType: "establishment_user", userType: "establishment_user",
establishmentName: "",
establishmentId: "",
email: "", email: "",
}); });
@ -61,9 +59,6 @@ const PublicContactForm = () => {
if (!data.userType) { if (!data.userType) {
newErrors.userType = "Please select user type"; newErrors.userType = "Please select user type";
} else if (data.userType === 'establishment_user') {
if (!data.establishmentName.trim()) newErrors.establishmentName = "Required.";
if (!data.establishmentId.trim()) newErrors.establishmentId = "Required.";
} }
if (!data.email.trim()) newErrors.email = "Required."; if (!data.email.trim()) newErrors.email = "Required.";
@ -94,8 +89,6 @@ const PublicContactForm = () => {
try { try {
const payload = { const payload = {
user_type: formData.userType, user_type: formData.userType,
establishment_name: formData.establishmentName.trim(),
establishment_code: formData.establishmentId.trim(),
registered_email: formData.email.trim(), registered_email: formData.email.trim(),
}; };
@ -256,48 +249,6 @@ const PublicContactForm = () => {
</div> </div>
)} )}
{formData.userType === 'establishment_user' && (
<div className="space-y-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Establishment Name <span className="text-red-500">*</span>
</label>
<input
type="text"
name="establishmentName"
value={formData.establishmentName}
onChange={handleChange}
className={`block w-full h-10 rounded-md border-2 ${
errors.establishmentName ? "border-red-500" : "border-[#92722A]"
} focus:border-[#92722A] focus:ring-0 px-4 text-sm`}
placeholder="Enter establishment name"
/>
{errors.establishmentName && (
<p className="text-xs text-red-600 mt-1">{errors.establishmentName}</p>
)}
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Establishment ID <span className="text-red-500">*</span>
</label>
<input
type="text"
name="establishmentId"
value={formData.establishmentId}
onChange={handleChange}
className={`block w-full h-10 rounded-md border-2 ${
errors.establishmentId ? "border-red-500" : "border-[#92722A]"
} focus:border-[#92722A] focus:ring-0 px-4 text-sm`}
placeholder="Enter establishment ID"
/>
{errors.establishmentId && (
<p className="text-xs text-red-600 mt-1">{errors.establishmentId}</p>
)}
</div>
</div>
)}
<InputField <InputField
label="Registered Email" label="Registered Email"
name="email" name="email"

View File

@ -12,6 +12,22 @@ export const getManufacturingIndex = async () => {
} }
}; };
// Fetch manufacturing index with optional filters (year, quarter)
export const getManufacturingIndexFiltered = async (year, quarter) => {
try {
const params = {};
if (year) params.year = year.toString();
if (quarter) params.quarter = quarter.toString();
const response = await getRequest(`${MANUFACTURING_ENDPOINT}/getManufacturingIndex`, {
params,
});
return response;
} catch (error) {
console.error('Error fetching filtered manufacturing index:', error);
throw error;
}
};
export const getManufacturingMonthlyOverview = async (year, quarter) => { export const getManufacturingMonthlyOverview = async (year, quarter) => {
try { try {

View File

@ -67,7 +67,8 @@ const toUnitOption = (item) => {
const id = toStringOrNull(item.id ?? item.unit_id ?? item.value ?? item.code); const id = toStringOrNull(item.id ?? item.unit_id ?? item.value ?? item.code);
const short = toStringOrNull(item.uom_short_name ?? item.short_name); const short = toStringOrNull(item.uom_short_name ?? item.short_name);
const name = toStringOrNull(item.uom ?? item.name ?? item.label); const name = toStringOrNull(item.uom ?? item.name ?? item.label);
const label = toStringOrNull(short && name ? `${short} - ${name}` : name ?? short); // const label = toStringOrNull(short && name ? `${short} - ${name}` : name ?? short);
const label = toStringOrNull(name ?? short);
const finalLabel = label ?? id; const finalLabel = label ?? id;
if (!finalLabel) return null; if (!finalLabel) return null;
return { label: finalLabel, value: id ?? finalLabel }; return { label: finalLabel, value: id ?? finalLabel };
@ -114,7 +115,7 @@ const toIsicOption = (item) => {
return value ? { label: value, value } : null; return value ? { label: value, value } : null;
} }
if (typeof item === 'object') { if (typeof item === 'object') {
const id = toStringOrNull(item.id ?? item.value ?? item.code); const id = toStringOrNull(item.code ?? item.id ?? item.value);
const code = toStringOrNull(item.code); const code = toStringOrNull(item.code);
const description = toStringOrNull(item.description ?? item.name ?? item.label); const description = toStringOrNull(item.description ?? item.name ?? item.label);
const label = code && description ? `${code} - ${description}` : description ?? code ?? item.label; const label = code && description ? `${code} - ${description}` : description ?? code ?? item.label;
@ -125,6 +126,7 @@ const toIsicOption = (item) => {
return null; return null;
}; };
export const getVariationReasons = async (config = {}) => { export const getVariationReasons = async (config = {}) => {
const response = await getRequest(endpoints.variationReasons, config); const response = await getRequest(endpoints.variationReasons, config);
return response.data; return response.data;