Diagramme.tsx 5,54 ko
Newer Older
antoH's avatar
antoH a validé
'use client'

import { pie, arc } from "d3-shape";
import { useState } from "react";

type Data = {
    region: string;
    commune: string;
    departement: string;
    taxRate: number;
    taxe: string;   // ex: "CFE", "TFPB"
    year: number;   // ex: 2021
    value: number;
};


type Props = {
    data: Data[];
};

const taxes = ["CFE", "TFPB", "CVAE"];
const years = [2019, 2020, 2021, 2022, 2023];

const COLORS = [
    "#2563eb", // blue-600
    "#16a34a", // green-600
    "#ea580c", // orange-600
    "#7c3aed", // violet-600
];

export default function PieChart({ data }: Props) {
    const [selectedTaxe, setSelectedTaxe] = useState<string>("CFE");
    const [selectedYear, setSelectedYear] = useState<number>(2022);
    const [hoveredRegion, setHoveredRegion] = useState<string | null>(null);


    const radius = 190;

    const filteredData = data.filter(
        d => d.taxe === selectedTaxe && d.year === selectedYear
    );

    const pieGenerator = pie<Data>()
        .value(d => d.value);

    const arcGenerator = arc<any>()
        .innerRadius(0)
        .outerRadius(radius);

    const arcs = pieGenerator(filteredData);

    return (
        <section className="w-full max-w-5xl bg-white rounded-xl shadow-sm p-6">
            <h2 className="text-xl font-semibold text-gray-800 mb-4">
                Impôt collecté par région
            </h2>

            <div className="flex gap-4 mb-6">
                <div>
                    <label className="block text-sm font-medium text-gray-700 mb-1">
                        Taxe
                    </label>
                    <select
                        value={selectedTaxe}
                        onChange={e => setSelectedTaxe(e.target.value)}
                        className="rounded-md border border-gray-300 bg-white px-3 py-2 text-sm text-gray-700 shadow-sm focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500"
                    >
                        {taxes.map(t => (
                            <option key={t + "taxe"} value={t}>{t}</option>
                        ))}
                    </select>
                </div>

                <div>
                    <label className="block text-sm font-medium text-gray-700 mb-1">
                        Année
                    </label>
                    <select
                        value={selectedYear}
                        onChange={e => setSelectedYear(Number(e.target.value))}
                                            className="rounded-md border border-gray-300 bg-white px-3 py-2 text-sm text-gray-700 shadow-sm focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500"
                    >
                        {years.map(y => (
                            <option key={y + "year"} value={y}>{y}</option>
                        ))}
                    </select>
                </div>
            </div>

            <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
                <div className="flex justify-center md:col-span-3">
                    <svg width={440} height={440}>
                        <g transform="translate(220, 220)">
                            {arcs.map((d, i) => {
                                const isActive =
                                    hoveredRegion === null || hoveredRegion === d.data.region;

                                return (
                                    <path
                                        key={d.data.region + "diagram"}
                                        d={arcGenerator(d)!}
                                        fill={COLORS[i % COLORS.length]}
                                        opacity={isActive ? 1 : 0.25}
                                        onMouseEnter={() => setHoveredRegion(d.data.region)}
                                        onMouseLeave={() => setHoveredRegion(null)}
                                        className="transition-opacity duration-200 cursor-pointer"
                                    />
                                );
                            })}
                        </g>
                    </svg>

                </div>

                <div className="md:col-span-1 space-y-2 self-center">
                    {arcs.map((d, i) => {
                        const isActive =
                            hoveredRegion === null || hoveredRegion === d.data.region;

                        return (
                            <div
                                key={d.data.region + "legend"}
                                onMouseEnter={() => setHoveredRegion(d.data.region)}
                                onMouseLeave={() => setHoveredRegion(null)}
                                className={`flex items-center gap-3 cursor-pointer transition-opacity ${isActive ? "opacity-100" : "opacity-40"
                                    }`}
                            >
                                <span
                                    className="w-4 h-4 rounded-sm"
                                    style={{ backgroundColor: COLORS[i % COLORS.length] }}
                                />

                                <span className="text-sm text-gray-700 flex-1">
                                    {d.data.region}
                                </span>

                                <span className="text-sm font-medium text-gray-900">
                                    {d.data.value}
                                </span>
                            </div>
                        );
                    })}
                </div>

            </div>
        </section >
    );
}