import { useCallback, useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import { Plus, RefreshCw, AlertTriangle, CircleAlert, Info, Link2Off } from "lucide-react";
import { api } from "../api.js";
import { useAuth } from "../App.jsx";
import { Badge, Button, cx, Empty, ErrorNote, fmt, fmtDate, Panel, Spark, Spinner, Stat, StatCell, StatRow, timeAgo } from "../ui.jsx";
import AddClientDialog from "./AddClientDialog.jsx";
import GettingStarted from "../GettingStarted.jsx";
const LEVEL = {
bad: { icon: CircleAlert, cls: "text-bad" },
warn: { icon: AlertTriangle, cls: "text-warn" },
info: { icon: Info, cls: "text-brand" },
};
export default function Overview() {
const { isAdmin } = useAuth();
const nav = useNavigate();
const [data, setData] = useState(null);
const [error, setError] = useState(null);
const [refreshing, setRefreshing] = useState(false);
const [adding, setAdding] = useState(false);
const load = useCallback(() => api("/api/overview").then(setData).catch(setError), []);
useEffect(() => { load(); }, [load]);
// While any client is refreshing, poll so numbers fill in as they arrive.
const anyRefreshing = refreshing || data?.clients.some((c) => c.refreshing);
useEffect(() => {
if (!anyRefreshing) return;
const t = setInterval(load, 6000);
return () => clearInterval(t);
}, [anyRefreshing, load]);
const refreshAll = async () => {
setRefreshing(true);
await api("/api/refresh-all", { method: "POST" }).catch(setError);
setTimeout(load, 1500);
setTimeout(() => setRefreshing(false), 20000);
};
if (!data && !error) return
Instagram and Facebook, last 28 days{oldest ? ` · numbers as of ${timeAgo(oldest)}` : ""}
| Client | Followers | Reached | Posts | Last post | Reach per post | Last audit |
|---|---|---|---|---|---|---|
|
{c.name}
{c.linked ? (c.igUsername ? `@${c.igUsername}` : "Facebook only") : (
|
{fmt(c.igFollowers)} | {fmt(c.igReach28)} | {fmt(c.postsLast28)} | {c.refreshing ? ( updating… ) : c.daysSinceLastPost == null ? ( — ) : ( = 14 ? "text-bad font-medium" : c.daysSinceLastPost >= 7 ? "text-warn font-medium" : "text-ink-2")}> {c.daysSinceLastPost === 0 ? "today" : `${c.daysSinceLastPost}d ago`} )} |
{c.lastAuditAt ? fmtDate(c.lastAuditAt) : |