← back to Open Seo
src/client/features/ai-search/components/BrandLookupMentionTrendCard.tsx
96 lines
import { useMemo } from "react";
import {
CartesianGrid,
Line,
LineChart,
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
} from "recharts";
import { formatCount } from "@/client/features/ai-search/platformLabels";
import type { BrandLookupResult } from "@/types/schemas/ai-search";
type Props = {
result: BrandLookupResult;
};
export function BrandLookupMentionTrendCard({ result }: Props) {
const chartData = useMemo(
() =>
result.monthlyVolume.map((entry) => ({
label: `${entry.year}-${String(entry.month).padStart(2, "0")}`,
volume: entry.volume ?? 0,
})),
[result.monthlyVolume],
);
if (chartData.length === 0) {
return (
<div className="flex h-56 items-center justify-center text-sm text-base-content/60">
Not enough historical data yet.
</div>
);
}
return (
<div className="h-56">
<ResponsiveContainer width="100%" height="100%">
<LineChart
data={chartData}
margin={{ top: 12, right: 12, bottom: 4, left: 0 }}
>
<CartesianGrid
strokeDasharray="3 3"
stroke="currentColor"
opacity={0.12}
/>
<XAxis
dataKey="label"
tick={{ fontSize: 11, fill: "#888" }}
tickLine={false}
axisLine={false}
/>
<YAxis
tick={{ fontSize: 11, fill: "#888" }}
tickLine={false}
axisLine={false}
allowDecimals={false}
/>
<Tooltip
content={<MentionTooltip />}
cursor={{ stroke: "currentColor", strokeOpacity: 0.2 }}
/>
<Line
type="monotone"
dataKey="volume"
stroke="hsl(220 70% 50%)"
strokeWidth={2}
dot={false}
/>
</LineChart>
</ResponsiveContainer>
</div>
);
}
function MentionTooltip({
active,
payload,
label,
}: {
active?: boolean;
payload?: Array<{ value: number }>;
label?: string;
}) {
if (!active || !payload?.length) return null;
return (
<div className="rounded-md border border-base-300 bg-base-100 px-3 py-2 shadow-sm">
<p className="text-xs text-base-content/60">{label}</p>
<p className="text-sm font-medium tabular-nums">
{formatCount(payload[0].value)} mentions
</p>
</div>
);
}