fix: Social — solo posts IG y barras de evolución visibles con delta

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
4Ventures
2026-09-28 17:57:56 +02:00
parent 87c887294d
commit c0707ffc1b

View File

@@ -277,23 +277,39 @@ function MiniBars({
}
const max = Math.max(1, ...pts.map((p) => p.value));
return (
<div className="flex items-end gap-0.5 h-24 w-full">
{pts.map((p) => (
<div
key={p.day}
className="flex-1 min-w-0"
title={`${p.day}: ${n(p.value)}`}
>
<div className="flex items-end gap-0.5 h-28 w-full">
{pts.map((p) => {
const pct = Math.max(6, Math.round((p.value / max) * 100));
return (
<div
className={`w-full rounded-t ${color} hover:opacity-90`}
style={{ height: `${Math.max(4, (p.value / max) * 100)}%` }}
/>
</div>
))}
key={p.day}
className="flex-1 min-w-0 h-full flex flex-col justify-end"
title={`${p.day}: ${n(p.value)}`}
>
<div
className={`w-full rounded-t ${color}`}
style={{ height: `${pct}%` }}
/>
</div>
);
})}
</div>
);
}
function seriesDelta(series?: DayPoint[]): {
abs: number;
pct: number | null;
up: boolean;
} | null {
if (!series || series.length < 2) return null;
const first = series[0].value;
const last = series[series.length - 1].value;
const abs = last - first;
const pct = first !== 0 ? (100 * abs) / Math.abs(first) : null;
return { abs, pct, up: abs >= 0 };
}
function ChartCard({
title,
hint,
@@ -307,6 +323,7 @@ function ChartCard({
total?: number | null;
color: string;
}) {
const delta = seriesDelta(series);
return (
<div className="rounded-xl border border-gray-200 bg-white p-4 space-y-2">
<div className="flex items-start justify-between gap-2">
@@ -316,7 +333,22 @@ function ChartCard({
</p>
{hint ? <p className="text-[10px] text-gray-400 mt-0.5">{hint}</p> : null}
</div>
<p className="text-lg font-bold text-gray-900 tabular-nums">{n(total)}</p>
<div className="text-right">
<p className="text-lg font-bold text-gray-900 tabular-nums">{n(total)}</p>
{delta ? (
<p
className={`text-[10px] font-semibold tabular-nums ${
delta.up ? 'text-emerald-600' : 'text-rose-600'
}`}
>
{delta.up ? '↑' : '↓'} {n(Math.abs(delta.abs))}
{delta.pct != null
? ` (${delta.pct > 0 ? '+' : ''}${delta.pct.toFixed(0)}%)`
: ''}
<span className="text-gray-400 font-normal"> inicio→fin</span>
</p>
) : null}
</div>
</div>
<MiniBars series={series} color={color} />
{series && series.length > 1 ? (
@@ -345,9 +377,6 @@ export default function SocialDashboard({
warning?: string;
}>({});
const [posts, setPosts] = useState<SocialPost[]>([]);
const [feedFilter, setFeedFilter] = useState<'all' | 'instagram' | 'facebook'>(
'all'
);
const [err, setErr] = useState<string | null>(null);
useEffect(() => {
@@ -375,10 +404,10 @@ export default function SocialDashboard({
const by = useMemo(() => new Map(integs.map((i) => [i.provider, i])), [integs]);
const ig = metrics.instagram;
const fb = metrics.facebook;
const visiblePosts =
feedFilter === 'all'
? posts
: posts.filter((p) => p.platform === feedFilter);
const visiblePosts = useMemo(
() => posts.filter((p) => p.platform === 'instagram'),
[posts]
);
const kpiCards = [
{
@@ -606,8 +635,8 @@ export default function SocialDashboard({
Evolución diaria · {rangeLabel}
</h3>
<p className="text-xs text-gray-500 mt-0.5">
Totales del periodo arriba a la derecha de cada gráfica. Globales
(seguidores/publicaciones) en las KPI.
Barras = valor diario. Flecha = cambio del primer al último día
del periodo. Totales arriba a la derecha.
</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-3">
@@ -618,38 +647,18 @@ export default function SocialDashboard({
</section>
<section className="space-y-3">
<div className="flex flex-wrap items-center justify-between gap-2">
<div>
<h3 className="text-sm font-semibold text-gray-900">
Contenido publicado
Publicaciones Instagram
</h3>
<div className="flex gap-1">
{(
[
['all', 'Todo'],
['instagram', 'IG'],
['facebook', 'FB'],
] as const
).map(([id, lbl]) => (
<button
key={id}
type="button"
onClick={() => setFeedFilter(id)}
className={`px-2.5 py-1 rounded-lg text-[11px] font-semibold ${
feedFilter === id
? 'bg-gray-900 text-white'
: 'bg-gray-100 text-gray-600'
}`}
>
{lbl}
</button>
))}
</div>
<p className="text-xs text-gray-500 mt-0.5">
Solo IG (feed, reels y carruseles). Sin posts de Facebook.
</p>
</div>
{visiblePosts.length === 0 ? (
<p className="text-sm text-gray-500 border border-dashed border-gray-200 rounded-xl px-4 py-10 text-center">
Sin posts en este periodo (o el token Meta no puede leer la
Página/IG).
Sin publicaciones de Instagram en este periodo.
</p>
) : (
<ul className="grid gap-4 sm:grid-cols-2 xl:grid-cols-3">