baublet/w8mngr

View on GitHub
client/components/Nutrition/MacrosPieChart.tsx

Summary

Maintainability
B
4 hrs
Test Coverage
import React from "react";
import { Cell, Pie, PieChart, ResponsiveContainer } from "recharts";

const COLORS = ["#f59e0b", "#be185d", "#84cc16"];

export type MacrosPieChartProps = {
  averageDailyFat: number;
  averageDailyCarbs: number;
  averageDailyProtein: number;
};

export function MacrosPieChart({
  averageDailyCarbs,
  averageDailyFat,
  averageDailyProtein,
}: MacrosPieChartProps) {
  const data = React.useMemo(() => {
    return [
      { name: "Fat", value: Math.ceil(averageDailyFat) },
      { name: "Carbs", value: Math.ceil(averageDailyCarbs) },
      { name: "Protein", value: Math.ceil(averageDailyProtein) },
    ];
  }, [averageDailyFat, averageDailyCarbs, averageDailyProtein]);

  return (
    <div className="flex flex-col gap-2">
      <div className="flex gap-2 text-sm text-slate-900 text-opacity-70">
        <div>
          <b style={{ color: "#f59e0b" }}>Fat: </b>
          {Math.ceil(averageDailyFat)}
          <span className="text-xs text-slate-900 text-opacity-40">g</span>
        </div>
        <div>
          <b style={{ color: "#be185d" }}>Carbs: </b>
          {Math.ceil(averageDailyCarbs)}
          <span className="text-xs text-slate-900 text-opacity-40">g</span>
        </div>
        <div>
          <b style={{ color: "#84cc16" }}>Protein: </b>
          {Math.ceil(averageDailyProtein)}
          <span className="text-xs text-slate-900 text-opacity-40">g</span>
        </div>
      </div>
      <div style={{ width: "100%", height: 250 }}>
        <ResponsiveContainer>
          <PieChart width={450} height={450}>
            <Pie
              dataKey="value"
              data={data}
              cx="50%"
              cy="50%"
              outerRadius={"100%"}
              fill="#1e293b"
              labelLine={false}
              label={renderCustomizedLabel}
            >
              {data.map((entry, index) => (
                <Cell
                  key={`cell-${index}`}
                  fill={COLORS[index % COLORS.length]}
                  stroke="#FFF"
                  strokeWidth={2}
                />
              ))}
            </Pie>
          </PieChart>
        </ResponsiveContainer>
      </div>
    </div>
  );
}

const RADIAN = Math.PI / 180;
function renderCustomizedLabel({
  cx,
  cy,
  midAngle,
  innerRadius,
  outerRadius,
  percent,
  payload,
}: {
  cx: number;
  cy: number;
  midAngle: number;
  innerRadius: number;
  outerRadius: number;
  percent: number;
  index: number;
  payload: { payload: { name: string; value: number } };
}) {
  const radius = innerRadius + (outerRadius - innerRadius) * 0.5;
  const x = cx + radius * Math.cos(-midAngle * RADIAN);
  const y = cy + radius * Math.sin(-midAngle * RADIAN);

  return (
    <>
      <text
        x={x - 15}
        y={y}
        fill="white"
        textAnchor={"start"}
        dominantBaseline="central"
        className="text-xs"
      >
        {payload.payload.name}
      </text>
      <text
        x={x - 15}
        y={y + 12}
        fill="white"
        textAnchor={"start"}
        dominantBaseline="central"
        className="text-xs"
      >
        {`${(percent * 100).toFixed(0)}%`}
      </text>
    </>
  );
}