import { useEffect, useState } from 'react' import { Lock, RefreshCw, RotateCcw } from 'lucide-react' import { api } from '../api/client' interface Cert { id: number; domain: string; status: string; issuedAt: string | null; expiresAt: string | null } export default function SSL() { const [certs, setCerts] = useState([]) const [loading, setLoading] = useState(false) const fetch = async () => { setLoading(true) try { const r = await api.get('/nixclient/ssl'); setCerts(r.data.data) } finally { setLoading(false) } } useEffect(() => { fetch() }, []) const renew = async (id: number) => { try { await api.post(`/nixclient/ssl/${id}/renew`); fetch() } catch (err: unknown) { alert((err as { response?: { data?: { error?: string } } })?.response?.data?.error ?? 'Renewal failed') } } const days = (d: string | null) => { if (!d) return null return Math.ceil((new Date(d).getTime() - Date.now()) / 86400000) } const statusColor: Record = { active: 'bg-emerald-500/10 text-emerald-400 border-emerald-500/20', pending: 'bg-amber-500/10 text-amber-400 border-amber-500/20', expired: 'bg-red-500/10 text-red-400 border-red-500/20', revoked: 'bg-[#1a2235] text-[#64748b] border-[#1e2d45]', } return (

SSL Certificates

Let's Encrypt certificates for your domains

{['Domain', 'Status', 'Expires', ''].map(h => )} {certs.map(c => { const d = days(c.expiresAt) return ( ) })} {!loading && certs.length === 0 && }
{h}
{c.domain} {c.status} {c.expiresAt ? {d !== null && d > 0 ? `${d} days` : 'Expired'} ({new Date(c.expiresAt).toLocaleDateString()}) : '—'} {c.status === 'active' && ( )}
No certificates. Contact your host to issue SSL.
) }