Untitled

mail@pastecode.io avatar
unknown
plain_text
17 days ago
5.1 kB
5
Indexable
Never
"use client";
import React from "react";
import {
  Area,
  AreaChart,
  ResponsiveContainer,
  Tooltip,
  XAxis,
  YAxis,
  CartesianGrid,
} from "recharts";

// Function to format Y-axis values
const formatNumber = (num) => {
  if (num >= 1000000000) {
    return Math.round(num / 1000000000) + "B"; // For billions
  } else if (num >= 1000000) {
    return Math.round(num / 1000000) + "M"; // For millions
  } else if (num >= 1000) {
    return Math.round(num / 1000) + "K"; // For thousands
  } else {
    return num?.toString(); // For numbers less than 1000
  }
};

// Updated formatYAxis function to use formatNumber
const formatYAxis = (chartItem) => {
  return formatNumber(chartItem);
};

const CustomTooltip = ({ active, payload, label }) => {
  if (active && payload && payload.length) {
    return (
      <div className="custom-tooltip bg-white px-8 py-1 rounded-full border-2 border-slate-300">
        <p className="label text-sm ">{`${formatNumber(payload[0].value)}`}</p>
      </div>
    );
  }

  return null;
};

// Function to generate X-axis labels based on the selected period
const generateXAxisLabels = (selectedPeriod) => {
  const currentDate = new Date();
  const currentMonth = currentDate.getMonth();
  const monthNames = [
    "Jan",
    "Feb",
    "Mar",
    "Apr",
    "May",
    "Jun",
    "Jul",
    "Aug",
    "Sep",
    "Oct",
    "Nov",
    "Dec",
  ];

  if (selectedPeriod === "6m") {
    let labels = [];
    for (let i = 5; i >= 0; i--) {
      let monthIndex = (currentMonth - i + 12) % 12;
      labels.push(monthNames[monthIndex]);
    }
    return labels;
  }

  // Default behavior for other periods
  switch (selectedPeriod) {
    case "7d":
      return ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
    case "30d":
      return ["Week 1", "Week 2", "Week 3", "Week 4"];
    case "12m":
      return monthNames;
    default:
      return [];
  }
};

export const Chart = ({ data, selectedPeriod, isLoading }) => {
  const xAxisLabels = generateXAxisLabels(selectedPeriod);


  // Prepare chart data to ensure all X-axis labels are included
  let chartData = xAxisLabels.map((label) => {
    const item = data?.find((d) => d.typeValue === label);
    const increasedValue = item ? Math.round((item.value * 1.2) / 10) * 10 : 0; // Increase by 20% and round to nearest 10
    return {
      name: label,
      value: increasedValue,
    };
  });

  const hasData = chartData.some((item) => item.value !== 0);

  // Calculate the maximum value for the Y-axis
  const maxValue = Math.max(...chartData.map((item) => item.value));

  // Calculate tick interval and max Y-axis value to always have 5 ticks
  const tickInterval = maxValue > 0 ? Math.ceil(maxValue / 5) : 1;
  const maxYAxisValue = tickInterval * 5; // Ensure we have exactly 5 ticks

  // Generate tick values for the Y-axis
  const yAxisTicks = Array.from({ length: 6 }, (_, i) => i * tickInterval); // Includes 0 to maxYAxisValue

  return (
    <div className="mb-10">
      <ResponsiveContainer width={"100%"} minHeight={300}>
        <AreaChart
          data={chartData}
          margin={{ left: 15, right: 15, top: 10, bottom: 10 }}
        >
          <defs>
            <linearGradient id="colorPv" x1="0" y1="0" x2="0" y2="1">
              <stop offset="5%" stopColor="#EEF6FF" stopOpacity={0.8} />
              <stop offset="95%" stopColor="#DADEFF" stopOpacity={0} />
            </linearGradient>
          </defs>
          {hasData && <CartesianGrid strokeDasharray="3 3" vertical={false} />}

          <XAxis
            dataKey="name"
            axisLine={{ stroke: "#DADEFE" }}
            tickLine={true}
            // padding={{ left: 15, right: 15 }}
            interval={0} // Ensure every tick is displayed
            tick={{
              dy: 15, // Add space between the X-axis values and the axis line
            }}
          />
          {hasData && (
            <YAxis
              axisLine={false}
              tickFormatter={formatYAxis}
              tick={{
                fill: "#999",
                fontSize: 14,
              }}
              domain={[0, maxYAxisValue]} // Set Y-axis domain
              ticks={yAxisTicks} // Set specific tick values
            />
          )}

          <Tooltip content={<CustomTooltip />} />
          <Area
            type="monotone"
            dataKey="value"
            stroke={hasData ? "#347DFD" : "none"}
            strokeWidth={3}
            fillOpacity={4}
            fill="url(#colorPv)"
          />
          {!hasData && !isLoading && (
            <text
              x="50%"
              y="50%"
              textAnchor="middle"
              dominantBaseline="middle"
              style={{ fontSize: "16px", fill: "#888" }}
            >
              No data available
            </text>
          )}
        </AreaChart>
      </ResponsiveContainer>
    </div>
  );
};
Leave a Comment