Untitled
unknown
plain_text
10 months ago
15 kB
14
Indexable
import React from "react";
import { Chart } from "react-google-charts";
import { useGetApiQuery } from "../../store/api/commonApi";
import { motion } from "framer-motion";
import { useInView } from "react-intersection-observer";
import useIsMobile from "../../hooks/useIsMobile";
const SectorWiseProjects = ({ napData, chartData, isTableLoading, isChartLoading }) => {
const isMobile = useIsMobile();
const [chartRef, chartInView] = useInView({
triggerOnce: false,
threshold: 0.3,
rootMargin: '50px 0px',
});
const shouldAnimate = isMobile ? true : chartInView;
// Loading state
if (isTableLoading || isChartLoading) {
return (
<section className="mt-2">
<div className="max-w-container mx-auto">
<h2 className="text-xl font-bold text-green-600 mb-6">
NAP Sector-Wise Projects
</h2>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
<div className="lg:col-span-2 bg-white rounded-lg shadow-md border border-gray-100 p-6">
<div className="animate-pulse">
<div className="h-6 bg-gray-200 rounded mb-4"></div>
<div className="space-y-3">
{[...Array(8)].map((_, i) => (
<div key={i} className="h-4 bg-gray-200 rounded"></div>
))}
</div>
</div>
</div>
<div className="lg:col-span-1 bg-white rounded-lg shadow-md border border-gray-100 p-6">
<div className="animate-pulse">
<div className="h-6 bg-gray-200 rounded mb-4"></div>
<div className="h-64 bg-gray-200 rounded"></div>
</div>
</div>
</div>
</div>
</section>
);
}
// Table data check
if (!napData || !napData.data || !napData.data.rows) {
return (
<section className="mt-2">
<div className="max-w-container mx-auto">
<h2 className="text-xl font-bold text-green-600 mb-6">
NAP Sector-Wise Projects
</h2>
<div className="bg-white rounded-lg shadow-md border border-gray-100 p-6">
<p className="text-gray-500 text-center">No data available</p>
</div>
</div>
</section>
);
}
// Table data
const { rows, totals } = napData.data;
const tableRows = rows.filter((row) => row[0] !== "TOTAL");
// Line chart data - Process API data correctly
const apiData = Array.isArray(chartData?.data) ? chartData.data : (Array.isArray(chartData) ? chartData : []);
// Process the API data to extract years for ticks
let lineChartData = null;
let yearTicks = [];
let maxDataValue = 0;
if (apiData.length > 0) {
// Use the API data directly as it's already in the correct format
lineChartData = apiData;
// Extract all years from the data (skip header row)
yearTicks = apiData.slice(1).map(row => row[0]);
// Find the maximum value in the data (excluding header row and year column)
apiData?.slice(1).forEach(row => {
for (let i = 1; i < row.length; i++) {
const value = parseInt(row[i]) || 0;
if (value > maxDataValue) {
maxDataValue = value;
}
}
});
}
// Calculate dynamic max value (round up to nearest 10)
const dynamicMaxValue = Math.ceil(maxDataValue / 10) * 10;
// Generate dynamic ticks from 0 to dynamicMaxValue with interval of 10
const generateTicks = (maxVal) => {
const ticks = [];
for (let i = 0; i <= maxVal; i += 10) {
ticks.push(i);
}
return ticks;
};
const dynamicTicks = generateTicks(dynamicMaxValue);
const lineChartOptions = {
backgroundColor: "transparent",
chartArea: { left: 50, top: 20, width: "92%", height: "70%" }, // Reduced left margin to minimize space before y-axis
colors: ["#5F8E59", "#ff7f0e"], // Match the HTML example colors
hAxis: {
title: "Year",
slantedText: true,
slantedTextAngle: 45,
textStyle: {
fontSize: 10
},
ticks: yearTicks,
gridlines: {
count: yearTicks.length || 5
},
minorGridlines: {
count: 0
}
},
vAxis: {
title: "Number of Projects",
minValue: 0,
maxValue: dynamicMaxValue,
viewWindow: { min: 0, max: dynamicMaxValue },
format: '0',
gridlines: {
count: -1,
units: {
years: {format: ['yyyy']},
months: {format: ['MMM yyyy']},
days: {format: ['dd MMM']}
}
},
ticks: dynamicTicks
},
seriesType: 'bars', // Default to bars (like the HTML example)
series: {
1: { type: 'line' } // Second series (index 1) as line - matches HTML example
},
legend: { position: "bottom" },
tooltip: {
trigger: 'both',
isHtml: false,
textStyle: {
fontSize: 12
}
},
focusTarget: 'category'
};
return (
<section className="mt-2">
<div className="max-w-container mx-auto">
{/* Section Title */}
<h2 className="text-xl text-[#3D5C39] font-bold NDC Sector Aligned Projects mb-3 mt-3">
NAP Sector Aligned Projects
</h2>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{/* Table Section - Takes 2/3 width */}
<motion.div
className="lg:col-span-2"
initial={isMobile ? { opacity: 1, y: 0 } : { opacity: 0, y: 60 }}
animate={shouldAnimate ? { opacity: 1, y: 0 } : { opacity: 0, y: 60 }}
transition={isMobile ? { duration: 0 } : { duration: 0.8, ease: 'easeOut' }}
>
{/* Apply shadow to a wrapper div that encompasses the entire table structure */}
<div className="bg-white rounded-lg shadow-lg border border-gray-100 overflow-hidden" style={{ height: '460px' }}>
{/* Desktop View */}
<div className="hidden md:flex md:flex-col md:h-full">
{/* Fixed Header */}
<div className="flex-shrink-0 bg-gray-50 relative z-20">
<div className="overflow-x-auto">
<table className="min-w-full table-fixed w-full">
<thead>
<tr>
<th className="px-3 py-4 text-center text-base font-semibold text-gray-700 w-16">
#
</th>
<th className="px-6 py-4 text-left text-base font-semibold text-gray-700 w-1/4">
NAP Sector
</th>
<th className="px-4 py-4 text-center text-base font-semibold text-gray-700 w-1/4">
Number of<br/>Completed Projects
</th>
<th className="px-6 py-4 text-center text-base font-semibold text-gray-700 w-1/4">
Number of<br/>Ongoing Projects
</th>
<th className="px-6 py-4 text-center text-base font-semibold text-gray-700 w-1/4">
Total Investment<br/>(USD in Million)
</th>
</tr>
</thead>
</table>
</div>
</div>
{/* Scrollable Body */}
<div className="flex-1 overflow-y-auto min-h-0 relative z-10">
<div className="overflow-x-auto">
<table className="min-w-full table-fixed w-full">
<tbody>
{tableRows?.map?.((row, index) => (
<tr key={index} className={`${index % 2 === 0 ? 'bg-[#FEFFFE]' : 'bg-[#F4F9F4]'} border-y border-gray-200`}>
<td className="px-3 py-3 text-md text-gray-700 text-center w-16 font-medium">{index + 1}</td>
<td className="px-6 py-3 text-md text-gray-700 text-left w-1/4">{row?.[0]}</td>
<td className="px-6 py-3 text-md text-gray-700 text-center w-1/4">{row?.[1]}</td>
<td className="px-6 py-3 text-md text-gray-700 text-center w-1/4">{row?.[2]}</td>
<td className="px-6 py-3 text-md text-gray-700 text-right w-1/4">{row?.[3]}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
{/* Fixed Total Row */}
<div className="flex-shrink-0 bg-[#d2e3cf] relative z-20">
<div className="overflow-x-auto">
<table className="min-w-full table-fixed w-full">
<tbody>
<tr>
<td className="px-3 py-3 w-16"></td>
<td className="px-6 py-3 font-bold text-gray-800 text-left w-1/4">Total</td>
<td className="px-6 py-3 font-bold text-gray-800 text-center w-1/4">{totals?.completed_project_count}</td>
<td className="px-6 py-3 font-semibold text-gray-800 text-center w-1/4">{totals?.ongoing_project_count}</td>
<td className="px-6 py-3 font-bold text-gray-800 text-right w-1/4">{totals?.total_investment ? `${totals.total_investment.toLocaleString()}` : ''}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
{/* Mobile View - Fully Scrollable */}
<div className="md:hidden h-full overflow-auto">
<div className="min-w-max">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50 sticky top-0 z-10">
<tr>
<th className="px-3 py-2 text-left text-xs font-medium text-gray-700 uppercase tracking-wider w-12">#</th>
<th className="px-4 py-2 text-left text-xs font-medium text-gray-700 uppercase tracking-wider w-40">NAP Sector</th>
<th className="px-3 py-2 text-center text-xs font-medium text-gray-700 uppercase tracking-wider w-20">Completed</th>
<th className="px-3 py-2 text-center text-xs font-medium text-gray-700 uppercase tracking-wider w-20">Ongoing</th>
<th className="px-3 py-2 text-center text-xs font-medium text-gray-700 uppercase tracking-wider w-32">Total Investment<br/>(USD Million)</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200">
{tableRows?.map?.((row, index) => (
<tr key={index} className={`${index % 2 === 0 ? 'bg-[#FEFFFE]' : 'bg-[#F4F9F4]'} hover:bg-gray-50 transition-colors`}>
<td className="px-3 py-3 text-sm font-medium text-gray-900 text-center w-12">{index + 1}</td>
<td className="px-4 py-3 text-sm text-gray-900 font-medium w-40">{row?.[0]}</td>
<td className="px-3 py-3 text-sm text-gray-900 text-center w-20">{row?.[1]}</td>
<td className="px-3 py-3 text-sm text-gray-900 text-center w-20">{row?.[2]}</td>
<td className="px-3 py-3 text-sm text-gray-900 text-center w-32">{row?.[3]}</td>
</tr>
))}
</tbody>
</table>
{/* Sticky Total Row for Mobile */}
<div className="sticky bottom-0 bg-[#d2e3cf] border-t-2 border-green-200 z-10">
<table className="min-w-full">
<tbody>
<tr>
<td className="px-3 py-3 text-sm font-bold text-gray-900 text-center w-12"></td>
<td className="px-4 py-3 text-sm font-bold text-gray-900 w-40">Total</td>
<td className="px-3 py-3 text-sm font-bold text-gray-900 text-center w-20">{totals?.completed_project_count}</td>
<td className="px-3 py-3 text-sm font-bold text-gray-900 text-center w-20">{totals?.ongoing_project_count}</td>
<td className="px-3 py-3 text-sm font-bold text-gray-900 text-center w-32">{totals?.total_investment ? `${totals.total_investment.toLocaleString()}` : ''}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</motion.div>
{/* Line Chart Section - Takes 1/3 width */}
<motion.div
ref={chartRef}
className="lg:col-span-1 bg-white rounded-lg shadow-lg border border-gray-100 p-6"
style={{ height: '460px' }}
initial={isMobile ? { opacity: 1, y: 0 } : { opacity: 0, y: 40 }}
animate={shouldAnimate ? { opacity: 1, y: 0 } : { opacity: 0, y: 40 }}
transition={isMobile ? { duration: 0 } : { duration: 0.8, ease: 'easeOut' }}
>
<div className="h-full flex flex-col">
{/* Chart Title */}
<h3 className="text-lg font-semibold text-[#3D5C39] mb-2 flex-shrink-0">
Number of Climate Adaptation Projects by Year
</h3>
{/* <p className="text-sm text-gray-500 mb-2">Projects by Year</p> */}
<div className="flex-1 flex min-h-0">
{lineChartData && lineChartData.length > 1 ? (
<div className="w-full h-full">
<Chart
chartType="ComboChart"
width="100%"
height="100%"
data={lineChartData}
options={lineChartOptions}
loader={<div className="text-gray-500">Loading Chart...</div>}
/>
</div>
) : (
<div className="w-full h-full flex items-center justify-center">
<div className="text-center">
<div className="text-gray-400 text-lg mb-2">📊</div>
<p className="text-gray-500">No chart data available</p>
<p className="text-sm text-gray-400">Waiting for API data</p>
</div>
</div>
)}
</div>
</div>
</motion.div>
</div>
</div>
</section>
);
};
export default SectorWiseProjects;Editor is loading...
Leave a Comment