import { useCallback, useEffect, useState } from "react";
import { Link } from "wouter";
import { ArrowLeft, Pause, Play, RefreshCw, Shield, Trash2 } from "lucide-react";
import { api } from "@/api";
import type { DomainCheck, DomainView, Subdomain } from "@/types";
import { DomainDialog } from "@/components/DomainDialog";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import { t } from "@/i18n";
function Row({ k, v, mono }: { k: string; v: React.ReactNode; mono?: boolean }) {
if (v === undefined || v === null || v === "") return null;
return (
{k}
{v}
);
}
function Section({ title, children }: { title: string; children: React.ReactNode }) {
return (
);
}
function fmtDate(iso: string | null | undefined) {
if (!iso) return "—";
return new Date(iso).toLocaleDateString(undefined, { year: "numeric", month: "short", day: "numeric" });
}
export function DomainDetailPage({ id }: { id: string }) {
const [d, setD] = useState(null);
const [checks, setChecks] = useState([]);
const [subs, setSubs] = useState([]);
const [dlgOpen, setDlgOpen] = useState(false);
const [refreshing, setRefreshing] = useState(false);
const [subScanning, setSubScanning] = useState(false);
const load = useCallback(async () => {
const [{ data: dv }, { data: ck }, { data: sb }] = await Promise.all([
api.GET("/api/domains/{id}", { params: { path: { id } } }),
api.GET("/api/domains/{id}/checks", { params: { path: { id } } }),
api.GET("/api/domains/{id}/subdomains", { params: { path: { id } } }),
]);
if (dv) setD(dv);
if (ck) setChecks(ck);
if (sb) setSubs(sb);
}, [id]);
useEffect(() => { void load(); }, [load]);
if (!d) return {t("common.loading")};
const expiring = d.expiring || (d.daysUntilExpiry ?? Infinity) < 0;
return (
{t("nav.domains")}
{d.faviconUrl ?

: null}
{d.name}
{d.tld ? `.${d.tld}` : ""}
{d.dnssec === "signed" && dnssec}
{d.transferLock ? {t("domains.transferLock")} : null}
{d.privacyEnabled ? {t("domains.whoisPrivacy")} : null}
{d.autoRenew ? {t("domains.autoRenew")} : null}
{d.lookupError ? (
lookup: {d.lookupError}
) : null}
{t("domains.domainExpires")}
{d.daysUntilExpiry !== null && d.daysUntilExpiry !== undefined
? (d.daysUntilExpiry < 0 ? t("domains.expired") : `${d.daysUntilExpiry}d`)
: "—"}
{fmtDate(d.expiryDate)}
{t("domains.sslExpires")}
{d.sslDaysUntilExpiry !== null && d.sslDaysUntilExpiry !== undefined
? (d.sslDaysUntilExpiry < 0 ? t("domains.expired") : `${d.sslDaysUntilExpiry}d`)
: "—"}
{fmtDate(d.sslValidTo)}
{t("domains.registrar")}
{d.registrarName || "—"}
{d.caProvider || "—"}
{t("domains.providers")}
{d.dnsProvider || "—"}
{d.hostingProvider || d.emailProvider || "—"}
{d.statuses && d.statuses.length > 0 ?
: null}
{d.nameServers?.map((n) =>
)}
{d.mxRecords?.map((m) =>
)}
{d.ipv4?.map((a) =>
)}
{d.ipv6?.map((a) =>
)}
{d.cname ?
: null}
{d.txtRecords?.slice(0, 4).map((t, i) => 60 ? t.slice(0, 60) + "…" : t} mono />)}
{d.dnsProvider ?
: null}
{d.emailProvider ?
: null}
{d.sslAltNames && d.sslAltNames.length > 0 ? (
5 ? ` +${d.sslAltNames.length - 5}` : "")} mono />
) : null}
{Object.keys(d.headers ?? {}).length > 0 ? (
{t("domains.responseHeaders", { n: Object.keys(d.headers ?? {}).length })}
{Object.entries(d.headers ?? {}).map(([k, v]) => (
{k}
{v}
))}
) : null}
{t("domains.subdomains")}{subs.length > 0 ? ` (${subs.length})` : ""}
{subs.map((s) => (
| {s.name} |
{(s.ips ?? []).join(", ") || "—"}
|
{fmtDate(s.lastSeen)}
|
))}
{subs.length === 0 && (
|
{t("domains.noSubsFound")}
|
)}
{t("domains.checkHistory")}
{checks.map((c) => (
| {new Date(c.checkedAt ?? "").toLocaleString()} |
{t("domains.expPrefix")} {fmtDate(c.expiryDate)} |
{t("domains.sslPrefix")} {fmtDate(c.sslValidTo)} |
{(c.ipv4 ?? []).join(", ")} |
))}
{checks.length === 0 && (
| {t("domains.noSnapshots")} |
)}
);
}