"use client";
import { useEffect, useState } from "react";
import { Button } from "@/components/ui/button";
import { CheckCircle2, XCircle } from "lucide-react";
type DiagnosticsResponse = {
timestamp: string;
env: {
POSTGRES_URL: boolean;
BETTER_AUTH_SECRET: boolean;
GOOGLE_CLIENT_ID: boolean;
GOOGLE_CLIENT_SECRET: boolean;
OPENAI_API_KEY: boolean;
NEXT_PUBLIC_APP_URL: boolean;
};
database: {
connected: boolean;
schemaApplied: boolean;
error?: string;
};
auth: {
configured: boolean;
routeResponding: boolean | null;
};
ai: {
configured: boolean;
};
overallStatus: "ok" | "warn" | "error";
};
function StatusIcon({ ok }: { ok: boolean }) {
return ok ? (
) : (
);
}
export function SetupChecklist() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
async function load() {
setLoading(true);
setError(null);
try {
const res = await fetch("/api/diagnostics", { cache: "no-store" });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const json = (await res.json()) as DiagnosticsResponse;
setData(json);
} catch (e) {
setError(e instanceof Error ? e.message : "Failed to load diagnostics");
} finally {
setLoading(false);
}
}
useEffect(() => {
load();
}, []);
const steps = [
{
key: "env",
label: "Environment variables",
ok:
!!data?.env.POSTGRES_URL &&
!!data?.env.BETTER_AUTH_SECRET &&
!!data?.env.GOOGLE_CLIENT_ID &&
!!data?.env.GOOGLE_CLIENT_SECRET,
detail:
"Requires POSTGRES_URL, BETTER_AUTH_SECRET, GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET",
},
{
key: "db",
label: "Database connected & schema",
ok: !!data?.database.connected && !!data?.database.schemaApplied,
detail: data?.database.error
? `Error: ${data.database.error}`
: undefined,
},
{
key: "auth",
label: "Auth configured",
ok: !!data?.auth.configured,
detail:
data?.auth.routeResponding === false
? "Auth route not responding"
: undefined,
},
{
key: "ai",
label: "AI integration (optional)",
ok: !!data?.ai.configured,
detail: !data?.ai.configured
? "Set OPENAI_API_KEY for AI chat"
: undefined,
},
] as const;
const completed = steps.filter((s) => s.ok).length;
return (
Setup checklist
{completed}/{steps.length} completed
{error ?
{error}
: null}
{steps.map((s) => (
-
{s.label}
{s.detail ? (
{s.detail}
) : null}
))}
{data ? (
Last checked: {new Date(data.timestamp).toLocaleString()}
) : null}
);
}