Untitled

 avatar
unknown
plain_text
10 months ago
15 kB
15
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