changes in phase 2

This commit is contained in:
Malini 2026-01-09 18:25:23 +05:30
parent 093eed99b2
commit 5e61c94f23
2 changed files with 285 additions and 261 deletions

View File

@ -146,6 +146,12 @@ const AdminHeader = () => {
iconActive={configActiveSrc}
iconInactive={configInactiveSrc}
/>
<NavItem
to="/manufacturing-index"
label="Manufacturing Index"
iconActive={configActiveSrc}
iconInactive={configInactiveSrc}
/>
</nav>
<div className="hidden lg:flex items-center gap-3 ml-auto">
@ -240,6 +246,12 @@ const AdminHeader = () => {
iconActive={configActiveSrc}
iconInactive={configInactiveSrc}
/>
<NavItem
to="/manufacturing-index"
label="Manufacturing"
iconActive={configActiveSrc}
iconInactive={configInactiveSrc}
/>
<NavItem
to="/admin/users"
label="Users"

View File

@ -1,4 +1,5 @@
import React, { useState, useMemo, useEffect } from 'react';
import AdminHeader from '@/components/admin/AdminHeader';
import {
IconButton,
Dialog,
@ -10,8 +11,10 @@ import Table from '@/components/common/Table';
import {
FiberManualRecord as FiberManualRecordIcon,
KeyboardArrowRight as KeyboardArrowRightIcon,
InfoOutlined as InfoOutlinedIcon
InfoOutlined as InfoOutlinedIcon,
NavigateNext as NavigateNextIcon
} from '@mui/icons-material';
import { Breadcrumbs, Link } from '@mui/material';
import Card from '@/components/common/Card';
import { getManufacturingIndex, getManufacturingMonthlyOverview } from '@/services/manufacturingIndex/ManufacturingIndex';
@ -59,12 +62,6 @@ const ManufacturingIndex = () => {
totalItems: 0
});
// Month name to number mapping
const monthMap = {
'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4,
'May': 5, 'Jun': 6, 'Jul': 7, 'Aug': 8,
'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12
};
// Fetch data from API
useEffect(() => {
@ -348,277 +345,292 @@ const ManufacturingIndex = () => {
}
return (
<div className="min-h-screen bg-gray-100">
{/* Popup Dialog */}
<Dialog
open={isPopupOpen}
onClose={handleClosePopup}
maxWidth="lg"
fullWidth={true}
className="relative"
>
<DialogTitle className="bg-[#F9F5E8] text-[#92722A] flex justify-between items-center pr-2">
<span>Monthly ISIC breakdown
<div className="min-h-screen w-full bg-gray-50">
<AdminHeader />
<div className="max-w-[1280px] mx-auto px-4 py-6">
{/* Popup Dialog */}
<Dialog
open={isPopupOpen}
onClose={handleClosePopup}
maxWidth="lg"
fullWidth={true}
className="relative"
>
<DialogTitle className="bg-[#F9F5E8] text-[#92722A] flex justify-between items-center pr-2">
<span>Monthly ISIC breakdown
- {selectedMonth?.month}</span>
<IconButton
onClick={handleClosePopup}
size="small"
className="absolute right-2 top-2 text-gray-500 hover:text-gray-700"
sx={{
'&:hover': {
backgroundColor: 'transparent'
}
}}
>
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clipRule="evenodd" />
</svg>
</IconButton>
</DialogTitle>
<DialogContent className="p-0">
<div className="p-6">
{apiLoading ? (
<div className="flex justify-center items-center h-64">
<div className="animate-spin rounded-full h-10 w-10 border-b-2 border-[#92722A]"></div>
<span className="ml-3">Loading detailed data...</span>
</div>
) : (
<div className="space-y-0 w-[1000px] max-w-[95vw] min-w-[800px]">
<p className="text-sm text-gray-600 mb-4">
Start from the manufacturing total, then drill down into ISIC 2-digit and 3 & 4-digit groups for the selected month.
</p>
{/* Tabs Header */}
<div className="sticky top-0 z-10 bg-white pt-2">
<div className="flex justify-between items-center border-b border-gray-200 pb-2">
<div className="flex space-x-1">
{['manufacturing', 'isic2', 'isic3', 'isic4'].map((tab) => (
<button
key={tab}
onClick={() => setActiveTab(tab)}
className={`px-4 py-2 text-sm font-medium ${
activeTab === tab
? 'text-[#92722A] border-b-2 border-[#92722A]'
: 'text-medium-500 hover:text-gray-700'
}`}
>
{tab === 'manufacturing' ? 'Manufacturing total' :
tab === 'isic2' ? 'ISIC 2-digit' :
tab === 'isic3' ? 'ISIC 3-digit' : 'ISIC 4-digit'}
</button>
))}
<IconButton
onClick={handleClosePopup}
size="small"
className="absolute right-2 top-2 text-gray-500 hover:text-gray-700"
sx={{
'&:hover': {
backgroundColor: 'transparent'
}
}}
>
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clipRule="evenodd" />
</svg>
</IconButton>
</DialogTitle>
<DialogContent className="p-0">
<div className="p-6">
{apiLoading ? (
<div className="flex justify-center items-center h-64">
<div className="animate-spin rounded-full h-10 w-10 border-b-2 border-[#92722A]"></div>
<span className="ml-3">Loading detailed data...</span>
</div>
) : (
<div className="space-y-0 w-[1000px] max-w-[95vw] min-w-[800px]">
<p className="text-sm text-gray-600 mb-4">
Start from the manufacturing total, then drill down into ISIC 2-digit and 3 & 4-digit groups for the selected month.
</p>
{/* Tabs Header */}
<div className="sticky top-0 z-10 bg-white pt-2">
<div className="flex justify-between items-center border-b border-gray-200 pb-2">
<div className="flex space-x-1">
{['manufacturing', 'isic2', 'isic3', 'isic4'].map((tab) => (
<button
key={tab}
onClick={() => setActiveTab(tab)}
className={`px-4 py-2 text-sm font-medium ${
activeTab === tab
? 'text-[#92722A] border-b-2 border-[#92722A]'
: 'text-medium-500 hover:text-gray-700'
}`}
>
{tab === 'manufacturing' ? 'Manufacturing total' :
tab === 'isic2' ? 'ISIC 2-digit' :
tab === 'isic3' ? 'ISIC 3-digit' : 'ISIC 4-digit'}
</button>
))}
</div>
<div className="w-5"></div>
</div>
<div className="w-5"></div>
</div>
{/* Tab Content */}
<div className="bg-white mt-2 rounded-lg shadow p-6 w-full">
{activeTab === 'manufacturing' && (
<ManufacturingTotal
selectedMonthData={selectedMonthData}
setActiveTab={setActiveTab}
apiData={monthlyOverviewData?.manufacturing}
/>
)}
{activeTab === 'isic2' && (
<ISIC2Digit
setActiveTab={setActiveTab}
apiData={monthlyOverviewData?.isic2}
/>
)}
{activeTab === 'isic3' && (
<ISIC3Digit
setActiveTab={setActiveTab}
apiData={monthlyOverviewData?.isic3}
/>
)}
{activeTab === 'isic4' && (
<ISIC4Digit
setActiveTab={setActiveTab}
apiData={monthlyOverviewData?.isic4}
/>
)}
</div>
</div>
{/* Tab Content */}
<div className="bg-white mt-2 rounded-lg shadow p-6 w-full">
{activeTab === 'manufacturing' && (
<ManufacturingTotal
selectedMonthData={selectedMonthData}
setActiveTab={setActiveTab}
apiData={monthlyOverviewData?.manufacturing}
/>
)}
{activeTab === 'isic2' && (
<ISIC2Digit
setActiveTab={setActiveTab}
apiData={monthlyOverviewData?.isic2}
/>
)}
{activeTab === 'isic3' && (
<ISIC3Digit
setActiveTab={setActiveTab}
apiData={monthlyOverviewData?.isic3}
/>
)}
{activeTab === 'isic4' && (
<ISIC4Digit
setActiveTab={setActiveTab}
apiData={monthlyOverviewData?.isic4}
/>
)}
</div>
</div>
)}
</div>
</DialogContent>
</Dialog>
{/* Main UI */}
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
<div className="mb-6">
<Card className="p-6 bg-white rounded-lg shadow">
<div className="flex flex-col md:flex-row justify-between items-start md:items-start gap-4">
<div>
<h2 className="text-xl font-semibold text-gray-900 mb-2">
Manufacturing Index - Monthly overview
</h2>
<p className="text-sm text-gray-600 max-w-3xl">
Monthly manufacturing indices are automatically generated on the 11th of each month using the finalized Laspeyres item indices. This view enables users to monitor trends and drill down into ISIC grouplevel details.
</p>
</div>
<div className="text-right">
<div className="mt-5 flex flex-col items-end gap-2">
<div className="flex items-center text-sm text-green-600">
<FiberManualRecordIcon className="text-xs mr-1" />
Next scheduled run: 11 Nov 2025, 02:00 GST
</div>
<div className="flex text-sm text-gray-600">
<InfoOutlinedIcon className="text-gray-400 mr-1 mt-0.5 flex-shrink-0" style={{ fontSize: '1rem' }} />
<span className="whitespace-nowrap">Formula: Manufacturing index<sub>t</sub> = Σ (sector weight<sub>i</sub> × group index<sub>i,t</sub>)</span>
</div>
</div>
</div>
)}
</div>
</Card>
</div>
</DialogContent>
</Dialog>
{/* Main Table */}
<div className="space-y-6">
<Card className="p-6 bg-white rounded-lg shadow">
<div className="space-y-4">
<div className="border border-gray-200 rounded-lg overflow-hidden">
{/* Filters */}
<div className="bg-white px-6 py-4 border-b border-gray-200">
<div className="flex flex-col sm:flex-row justify-between items-start sm:items-center mb-4">
<div className="mb-4 sm:mb-0">
<h3 className="text-lg font-semibold text-gray-900 mb-1">
Manufacturing index by reference month ({filteredMonths.length})
</h3>
<p className="text-sm text-gray-600">
Filter by year and quickly jump to a month to see its ISIC breakdown.
</p>
<div className="flex items-center gap-4 mt-2">
<div className="text-sm text-gray-600 bg-gray-100 px-3 py-1 rounded-full">
Base year: 2022 = 100
</div>
<div className="text-sm text-gray-600 bg-gray-100 px-3 py-1 rounded-full">
Coverage: Manufacturing (ISIC C)
{/* Main UI */}
<div className="w-full py-6">
{/* Breadcrumbs */}
<nav className="mb-6 text-sm text-[#8F9299] flex items-center gap-2">
<Link
to="/admin/dashboard"
className="font-bold flex items-center gap-1 !text-black no-underline hover:underline hover:!text-black"
>
Dashboard
<img src="/assets/images/Breadcrumb-vector.svg" alt="" className="ml-1 w-3 h-3" />
</Link>
<span className="text-[#92722A] font-medium">Manufacturing Index</span>
</nav>
<div className="mb-6">
<Card className="p-6 bg-white rounded-lg shadow">
<div className="flex flex-col md:flex-row justify-between items-start md:items-start gap-4">
<div>
<h2 className="text-xl font-semibold text-gray-900 mb-2">
Manufacturing Index - Monthly overview
</h2>
<p className="text-sm text-gray-600 max-w-3xl">
Monthly manufacturing indices are automatically generated on the 11th of each month using the finalized Laspeyres item indices. This view enables users to monitor trends and drill down into ISIC grouplevel details.
</p>
</div>
<div className="text-right">
<div className="mt-5 flex flex-col items-end gap-2">
<div className="flex items-center text-sm text-green-600">
<FiberManualRecordIcon className="text-xs mr-1" />
Next scheduled run: 11 Nov 2025, 02:00 GST
</div>
<div className="flex text-sm text-gray-600">
<InfoOutlinedIcon className="text-gray-400 mr-1 mt-0.5 flex-shrink-0" style={{ fontSize: '1rem' }} />
<span className="whitespace-nowrap">Formula: Manufacturing index<sub>t</sub> = Σ (sector weight<sub>i</sub> × group index<sub>i,t</sub>)</span>
</div>
</div>
</div>
</div>
</Card>
</div>
{/* Main Table */}
<div className="space-y-6">
<Card className="p-6 bg-white rounded-lg shadow">
<div className="space-y-4">
<div className="border border-gray-200 rounded-lg overflow-hidden">
{/* Filters */}
<div className="bg-white px-6 py-4 border-b border-gray-200">
<div className="flex flex-col sm:flex-row justify-between items-start sm:items-center mb-4">
<div className="mb-4 sm:mb-0">
<h3 className="text-lg font-semibold text-gray-900 mb-1">
Manufacturing index by reference month ({filteredMonths.length})
</h3>
<p className="text-sm text-gray-600">
Filter by year and quickly jump to a month to see its ISIC breakdown.
</p>
<div className="flex items-center gap-4 mt-2">
<div className="text-sm text-gray-600 bg-gray-100 px-3 py-1 rounded-full">
Base year: 2022 = 100
</div>
<div className="text-sm text-gray-600 bg-gray-100 px-3 py-1 rounded-full">
Coverage: Manufacturing (ISIC C)
</div>
</div>
</div>
</div>
<div className="flex items-center gap-3 w-full sm:w-auto">
<div className="flex-1 sm:flex-none w-40">
<div className="relative">
<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" />
<div className="flex items-center gap-3 w-full sm:w-auto">
<div className="flex-1 sm:flex-none w-40">
<div className="relative">
<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" />
</div>
<input
type="text"
placeholder="Search month"
className="w-full pl-10 pr-3 py-2 border border-gray-300 rounded-md h-[40px]"
value={searchMonth}
onChange={handleSearchMonth}
/>
</div>
<input
type="text"
placeholder="Search month"
className="w-full pl-10 pr-3 py-2 border border-gray-300 rounded-md h-[40px]"
value={searchMonth}
onChange={handleSearchMonth}
</div>
<div className="flex items-center w-32">
<SelectField
value={year}
onChange={handleYearChange}
className="w-full h-[40px]"
size="small"
options={years.map(y => ({ value: y, label: y }))}
/>
</div>
<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"
onClick={handleExportCSV}
>
<img src={downloadIconSrc} alt="Download" className="h-5 w-5" />
<span className="hidden xl:inline font-medium text-[#232528]">Export CSV</span>
<span className="xl:hidden font-medium text-[#232528]">Export</span>
</button>
</div>
<div className="flex items-center w-32">
<SelectField
value={year}
onChange={handleYearChange}
className="w-full h-[40px]"
size="small"
options={years.map(y => ({ value: y, label: y }))}
/>
</div>
<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"
onClick={handleExportCSV}
>
<img src={downloadIconSrc} alt="Download" className="h-5 w-5" />
<span className="hidden xl:inline font-medium text-[#232528]">Export CSV</span>
<span className="xl:hidden font-medium text-[#232528]">Export</span>
</button>
</div>
</div>
{/* Table */}
<div className="relative">
<div className="w-full">
<Table
headers={[
'Reference Month',
'Manufacturing Index',
'MOM Change',
'YOY Change',
'Generated On',
'Status',
'Actions'
]}
rows={filteredMonths.map((row) => {
const isSelected = selectedMonth?.month === row.month;
return [
<div key="month" className={`${isSelected ? 'font-medium' : ''}`}>
{row.month}
</div>,
<span className={isSelected ? 'font-medium' : ''} key="index">
{row.index} (2022=100)
</span>,
<span className={`${parseFloat(row.mom) >= 0 ? 'text-green-600' : 'text-red-600'} ${isSelected ? 'font-medium' : ''}`} key="mom">
{row.mom}%
</span>,
<span className={`${parseFloat(row.yoy) >= 0 ? 'text-green-600' : 'text-red-600'} ${isSelected ? 'font-medium' : ''}`} key="yoy">
{row.yoy}%
</span>,
<span className={isSelected ? 'font-medium' : ''} key="generated">
{row.generated}
</span>,
<span className={isSelected ? 'font-medium' : ''} key="status">
<span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${
row.status === 'Completed'
? 'bg-green-100 text-green-800'
: 'bg-yellow-100 text-yellow-800'
}`}>
{row.status}
</span>
</span>,
<div
key="arrow"
className={`cursor-pointer flex items-center justify-end pr-4 ${
isSelected ? 'text-gray-900' : 'text-gray-400'
}`}
onClick={() => handleMonthSelect(row)}
>
<KeyboardArrowRightIcon />
</div>
];
})}
columnWidths={['180px', '190px', '130px', '130px', '200px', '120px', '80px']}
getRowClass={(index) => {
const isSelected = selectedMonth?.month === filteredMonths[index]?.month;
return isSelected ? 'bg-[#F5F0E1]' : 'hover:bg-gray-50';
}}
pagination={{
currentPage: pagination.currentPage,
onPageChange: (page) => setPagination(prev => ({ ...prev, currentPage: page })),
pageSize: pagination.pageSize,
totalItems: filteredMonths.length,
pageSizeOptions: [10, 20, 50, 100],
onPageSizeChange: (size) => {
setPagination(prev => ({
...prev,
pageSize: size,
currentPage: 1
}));
}
}}
className="w-full"
/>
</div>
</div>
</div>
{/* Table */}
<div className="relative">
<div className="w-full">
<Table
headers={[
'Reference Month',
'Manufacturing Index',
'MOM Change',
'YOY Change',
'Generated On',
'Status',
'Actions'
]}
rows={filteredMonths.map((row) => {
const isSelected = selectedMonth?.month === row.month;
return [
<div key="month" className={`${isSelected ? 'font-medium' : ''}`}>
{row.month}
</div>,
<span className={isSelected ? 'font-medium' : ''} key="index">
{row.index} (2022=100)
</span>,
<span className={`${parseFloat(row.mom) >= 0 ? 'text-green-600' : 'text-red-600'} ${isSelected ? 'font-medium' : ''}`} key="mom">
{row.mom}%
</span>,
<span className={`${parseFloat(row.yoy) >= 0 ? 'text-green-600' : 'text-red-600'} ${isSelected ? 'font-medium' : ''}`} key="yoy">
{row.yoy}%
</span>,
<span className={isSelected ? 'font-medium' : ''} key="generated">
{row.generated}
</span>,
<span className={isSelected ? 'font-medium' : ''} key="status">
<span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${
row.status === 'Completed'
? 'bg-green-100 text-green-800'
: 'bg-yellow-100 text-yellow-800'
}`}>
{row.status}
</span>
</span>,
<div
key="arrow"
className={`cursor-pointer flex items-center justify-end pr-4 ${
isSelected ? 'text-gray-900' : 'text-gray-400'
}`}
onClick={() => handleMonthSelect(row)}
>
<KeyboardArrowRightIcon />
</div>
];
})}
columnWidths={['180px', '190px', '130px', '130px', '200px', '120px', '80px']}
getRowClass={(index) => {
const isSelected = selectedMonth?.month === filteredMonths[index]?.month;
return isSelected ? 'bg-[#F5F0E1]' : 'hover:bg-gray-50';
}}
pagination={{
currentPage: pagination.currentPage,
onPageChange: (page) => setPagination(prev => ({ ...prev, currentPage: page })),
pageSize: pagination.pageSize,
totalItems: filteredMonths.length,
pageSizeOptions: [10, 20, 50, 100],
onPageSizeChange: (size) => {
setPagination(prev => ({
...prev,
pageSize: size,
currentPage: 1
}));
}
}}
className="w-full"
/>
</div>
</div>
<p className="text-xs text-gray-500 mt-2">
Note: Indices shown here are headline manufacturing totals. Use the drill-down actions to move from manufacturing total to ISIC 2-digit, then to ISIC 3 & 4-digit groups.
</p>
</div>
<p className="text-xs text-gray-500 mt-2">
Note: Indices shown here are headline manufacturing totals. Use the drill-down actions to move from manufacturing total to ISIC 2-digit, then to ISIC 3 & 4-digit groups.
</p>
</div>
</Card>
</Card>
</div>
</div>
</div>
</div>