Skip to content

Commit

Permalink
feat: Charts tooltips enhancement
Browse files Browse the repository at this point in the history
  • Loading branch information
PaulBayfield committed Jan 24, 2025
1 parent 3f284f3 commit ce544bb
Show file tree
Hide file tree
Showing 2 changed files with 139 additions and 30 deletions.
24 changes: 24 additions & 0 deletions src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,30 @@ html {
animation: fade-in 2s;
}

.custom-tooltip {
z-index: 9999;
background-color: #fff;
border: 1px solid #000;
border-radius: 0.5rem;
padding: 0.5rem;
box-shadow: 0 0 0.5rem rgba(0, 0, 0, 0.1);
animation: fade-in 0.5s;
}

.dark .custom-tooltip {
background-color: #000;
color: #fff;
box-shadow: 0 0 0.5rem rgba(255, 255, 255, 0.1);
}

.custom-tooltip > .label {
font-weight: bold;
}

.recharts-dot {
opacity: 0.3;
}

@keyframes fade-in {
0%,
50% {
Expand Down
145 changes: 115 additions & 30 deletions src/components/stats/stats-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,99 @@ interface StatsPageProps {
stats: GlobalStats;
}

interface TooltipPayload {
color: string;
value: number | string;
dataKey: string;
}

interface CustomTooltipProps {
locale: "en" | "fr";
tooltipMapping: Record<string, string>;
active: boolean;
payload?: TooltipPayload[];
label: string | number;
}

interface DotProps {
cx: any;
cy: any;
stroke: any;
payload: any;
value: any;
}

const CustomTooltip: React.FC<CustomTooltipProps> = ({
locale,
tooltipMapping,
active,
payload,
label,
}) => {
const formattedLabel =
locale === "fr"
? new Date(label).toLocaleDateString("fr-FR", {
day: "2-digit",
month: "long",
year: "numeric",
})
: new Date(label).toLocaleDateString("en-GB", {
day: "2-digit",
month: "long",
year: "numeric",
});

let localeString = "fr-FR";
if (locale === "en") {
localeString = "en-GB";
}

if (active && payload && payload.length) {
return (
<div className="custom-tooltip">
<p className="label">{formattedLabel}</p>
<ul>
{payload.map((entry, index) => (
<li key={`item-${index}`} style={{ color: entry.color }}>
{`${(entry.value).toLocaleString(localeString)} ${tooltipMapping[entry.dataKey] || entry.dataKey}`}
</li>
))}
</ul>
</div>
);
}

return null;
};

const CustomDot = (props: { cx: any; cy: any; stroke: any; payload: any; value: any; }) => {
const { cx, cy, stroke, payload, value } = props;

return (
<svg
xmlns="http://www.w3.org/2000/svg"
width="8"
height="8"
fill={stroke}
className="recharts-dot"
viewBox="0 0 8 8"
x={cx - 4}
y={cy - 4}
>
<circle cx="4" cy="4" r="4" />
</svg>
);
};

export default function StatsPage({ taches, stats }: StatsPageProps) {
const t = useTranslations("StatsPage");

const locale = useLocale();
let localeString = "fr-FR";
if (locale === "en") {
localeString = "en-GB";
}

return (
<div className="space-y-6 mt-6 lg:mt-12">
<Alert>
Expand All @@ -44,43 +134,43 @@ export default function StatsPage({ taches, stats }: StatsPageProps) {
<Stat variant="default">
<StatTitle>{t("stats.menus")}</StatTitle>
<StatDescription>
{(stats?.menus ?? 0).toLocaleString("fr")}
{(stats?.menus ?? 0).toLocaleString(localeString)}
</StatDescription>
</Stat>
<Stat variant="default">
<StatTitle>{t("stats.compositions")}</StatTitle>
<StatDescription>
{(stats?.compositions ?? 0).toLocaleString("fr")}
{(stats?.compositions ?? 0).toLocaleString(localeString)}
</StatDescription>
</Stat>
<Stat variant="default">
<StatTitle>{t("stats.categories")}</StatTitle>
<StatDescription>
{(stats?.categories ?? 0).toLocaleString("fr")}
{(stats?.categories ?? 0).toLocaleString(localeString)}
</StatDescription>
</Stat>
<Stat variant="default">
<StatTitle>{t("stats.repas")}</StatTitle>
<StatDescription>
{(stats?.repas ?? 0).toLocaleString("fr")}
{(stats?.repas ?? 0).toLocaleString(localeString)}
</StatDescription>
</Stat>
<Stat variant="default">
<StatTitle>{t("stats.plats")}</StatTitle>
<StatDescription>
{(stats?.plats ?? 0).toLocaleString("fr")}
{(stats?.plats ?? 0).toLocaleString(localeString)}
</StatDescription>
</Stat>
<Stat variant="default">
<StatTitle>{t("stats.restaurants")}</StatTitle>
<StatDescription>
{(stats?.restaurants ?? 0).toLocaleString("fr")}
{(stats?.restaurants ?? 0).toLocaleString(localeString)}
</StatDescription>
</Stat>
<Stat variant="default">
<StatTitle>{t("stats.regions")}</StatTitle>
<StatDescription>
{(stats?.regions ?? 0).toLocaleString("fr")}
{(stats?.regions ?? 0).toLocaleString(localeString)}
</StatDescription>
</Stat>
</div>
Expand All @@ -89,26 +179,7 @@ export default function StatsPage({ taches, stats }: StatsPageProps) {
);
}

const chartConfig = {
menuAdded: {
label: "Menus Added",
},
compositionAdded: {
label: "Compositions Added",
},
categoryAdded: {
label: "Categories Added",
},
repasAdded: {
label: "Repas Added",
},
platAdded: {
label: "Plats Added",
},
requests: {
label: "Requests",
},
} satisfies ChartConfig;
const chartConfig = {} satisfies ChartConfig;

const TacheCharts = ({ data }: { data: Tache[] }) => {
const processedData = useMemo(() => {
Expand Down Expand Up @@ -138,6 +209,15 @@ const TacheCharts = ({ data }: { data: Tache[] }) => {

const t = useTranslations("StatsPage");

const tooltipMapping = {
deltaMenus: t("charts.labels.menus"),
deltaRepas: t("charts.labels.repas"),
deltaCategories: t("charts.labels.categories"),
deltaPlats: t("charts.labels.plats"),
deltaCompositions: t("charts.labels.compositions"),
requetes: t("charts.labels.requetes"),
};

return (
<div className="space-y-6">
{/* Chart for the menus added over time */}
Expand Down Expand Up @@ -180,7 +260,7 @@ const TacheCharts = ({ data }: { data: Tache[] }) => {
}}
/>
<YAxis />
<Tooltip />
<Tooltip content={<CustomTooltip locale={locale as "en" | "fr"} tooltipMapping={tooltipMapping} active={false} payload={undefined} label="" />} />
<Legend />
<Bar
dataKey="deltaMenus"
Expand Down Expand Up @@ -233,31 +313,35 @@ const TacheCharts = ({ data }: { data: Tache[] }) => {
}}
/>
<YAxis />
<Tooltip />
<Tooltip content={<CustomTooltip locale={locale as "en" | "fr"} tooltipMapping={tooltipMapping} active={false} payload={undefined} label="" />} />
<Legend />
<Line
type="monotone"
dataKey="deltaCompositions"
stroke="#82ca9d"
name={t("charts.labels.compositions")}
dot={(props: DotProps) => <CustomDot {...props} />}
/>
<Line
type="monotone"
dataKey="deltaCategories"
stroke="#ffc658"
name={t("charts.labels.categories")}
dot={(props: DotProps) => <CustomDot {...props} />}
/>
<Line
type="monotone"
dataKey="deltaRepas"
stroke="#ff0000"
name={t("charts.labels.repas")}
dot={(props: DotProps) => <CustomDot {...props} />}
/>
<Line
type="monotone"
dataKey="deltaPlats"
stroke="#8884d8"
name={t("charts.labels.plats")}
dot={(props: DotProps) => <CustomDot {...props} />}
/>
</ComposedChart>
</ResponsiveContainer>
Expand Down Expand Up @@ -305,13 +389,14 @@ const TacheCharts = ({ data }: { data: Tache[] }) => {
}}
/>
<YAxis />
<Tooltip />
<Tooltip content={<CustomTooltip locale={locale as "en" | "fr"} tooltipMapping={tooltipMapping} active={false} payload={undefined} label="" />} />
<Legend />
<Line
type="monotone"
dataKey="requetes"
stroke="#ee82ee"
name={t("charts.labels.requetes")}
dot={(props: DotProps) => <CustomDot {...props} />}
/>
</ComposedChart>
</ResponsiveContainer>
Expand Down

0 comments on commit ce544bb

Please sign in to comment.