"use client"; import { useState } from "react"; import type { ChangeEvent } from "react"; import type { FormEvent } from "react"; import { formatDateTime } from "@/lib/dates"; type Instance = { id: string; name: string; base_url: string; auth_type: "api_key" | "basic"; status: string; error_message: string | null; last_connected_at: string | null; last_sync_at: string | null; last_sync_status: string | null; last_sync_error: string | null; last_sync_subscriptions: number; last_sync_domains: number; }; type Subscription = { id: string; name: string | null; status: string | null; plesk_subscription_id: string; plesk_instance_id: string; }; type Domain = { id: string; plesk_instance_id: string; subscription_id: string | null; subscription_name?: string | null; domain_name: string; status: string | null; hosting_type: string | null; source_created_at: string | null; aliases_count: number | null; updated_at: string; }; type Props = { instances: Instance[]; subscriptions: Subscription[]; domains: Domain[]; autoSyncByInstance: Record< string, { status: string; created_at: string; error_message: string | null } >; }; function getDomainStatusBadge(status: string | null) { const normalized = (status ?? "unknown").toLowerCase(); if (normalized.includes("suspend") || normalized.includes("disabled")) { return "bg-rose-100 text-rose-700"; } if (normalized.includes("expired")) { return "bg-amber-100 text-amber-700"; } if (normalized.includes("active") || normalized.includes("enabled")) { return "bg-emerald-100 text-emerald-700"; } if (normalized.includes("ok")) { return "bg-emerald-100 text-emerald-700"; } return "bg-slate-100 text-slate-600"; } function formatDomainStatusLabel(status: string | null) { const normalized = (status ?? "unknown").toLowerCase(); if (normalized.includes("suspend")) return "Suspended"; if (normalized.includes("disabled")) return "Disabled"; if (normalized.includes("expired")) return "Expired"; if ( normalized.includes("active") || normalized.includes("ok") || normalized.includes("enabled") ) { return "Active"; } return "Unknown"; } function isDomainSuspended(status: string | null) { const normalized = (status ?? "unknown").toLowerCase(); return normalized.includes("suspend") || normalized.includes("disabled"); } function isDomainActive(status: string | null) { const normalized = (status ?? "unknown").toLowerCase(); return ( normalized.includes("active") || normalized.includes("ok") || normalized.includes("enabled") ); } function getDomainHref(domainName: string) { const normalized = domainName.trim(); if (/^https?:\/\//i.test(normalized)) return normalized; return `https://${normalized}`; } export function DashboardControls({ instances, subscriptions, domains, autoSyncByInstance, }: Props) { const [instanceName, setInstanceName] = useState(""); const [baseUrl, setBaseUrl] = useState(""); const [authType, setAuthType] = useState<"api_key" | "basic">("api_key"); const [apiKey, setApiKey] = useState(""); const [username, setUsername] = useState(""); const [password, setPassword] = useState(""); const [actionSubId, setActionSubId] = useState(subscriptions[0]?.id ?? ""); const [actionType, setActionType] = useState<"suspend" | "unsuspend">( "suspend", ); const [domainSearch, setDomainSearch] = useState(""); const [domainStatus, setDomainStatus] = useState("all"); const [message, setMessage] = useState(null); const [loading, setLoading] = useState(false); const healthCounts = instances.reduce( (acc, instance) => { if (instance.status === "connected") acc.connected += 1; else if (instance.status === "syncing") acc.syncing += 1; else acc.error += 1; return acc; }, { connected: 0, syncing: 0, error: 0 }, ); const domainStatusOptions = Array.from( new Set( domains.map((domain) => (domain.status ?? "unknown").toLowerCase()), ), ).sort(); const filteredDomains = domains.filter((domain) => { const normalizedStatus = (domain.status ?? "unknown").toLowerCase(); const statusMatches = domainStatus === "all" || normalizedStatus === domainStatus; const term = domainSearch.trim().toLowerCase(); const searchMatches = !term || domain.domain_name.toLowerCase().includes(term) || (domain.hosting_type ?? "").toLowerCase().includes(term); return statusMatches && searchMatches; }); async function runRequest(url: string, body?: unknown) { const response = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json" }, body: body ? JSON.stringify(body) : undefined, }); const payload = await response.json().catch(() => ({})); if (!response.ok) { throw new Error(payload.error ?? "Request failed"); } return payload; } async function onCreateInstance(event: FormEvent) { event.preventDefault(); setLoading(true); setMessage(null); try { await runRequest("/api/plesk/instances", { name: instanceName, base_url: baseUrl, auth_type: authType, api_key: authType === "api_key" ? apiKey : undefined, username: authType === "basic" ? username : undefined, password: authType === "basic" ? password : undefined, }); setMessage("Plesk instance connected."); window.location.reload(); } catch (error) { setMessage( error instanceof Error ? error.message : "Could not connect instance", ); } finally { setLoading(false); } } async function onSync(instanceId: string) { setLoading(true); setMessage(null); try { const payload = await runRequest( `/api/plesk/instances/${instanceId}/sync`, ); setMessage("Plesk sync completed."); if (payload?.skipped) { setMessage(`Sync skipped (${payload.reason ?? "no reason"}).`); } else if ( payload?.domainsUpserted != null || payload?.subscriptionsUpserted != null ) { setMessage( `Plesk sync completed. Subscriptions: ${payload.subscriptionsUpserted ?? 0}, Domains: ${payload.domainsUpserted ?? 0}`, ); } window.location.reload(); } catch (error) { setMessage(error instanceof Error ? error.message : "Sync failed"); } finally { setLoading(false); } } async function onTestConnection(instanceId: string) { setLoading(true); setMessage(null); try { await runRequest(`/api/plesk/instances/${instanceId}/test`); setMessage("Connection test completed."); window.location.reload(); } catch (error) { setMessage( error instanceof Error ? error.message : "Connection test failed", ); } finally { setLoading(false); } } async function onSubscriptionAction() { if (!actionSubId) return; setLoading(true); setMessage(null); try { await runRequest(`/api/plesk/subscriptions/${actionSubId}/action`, { action: actionType, }); setMessage(`Subscription ${actionType} completed.`); window.location.reload(); } catch (error) { setMessage(error instanceof Error ? error.message : "Action failed"); } finally { setLoading(false); } } async function onDomainAction( domain: Domain, action: "suspend" | "unsuspend", ) { if (!domain.subscription_id) { setMessage( "Domain is not linked to a subscription yet. Run Sync Now (or backfill links) and try again.", ); return; } setLoading(true); setMessage(null); try { await runRequest(`/api/plesk/domains/${domain.id}/action`, { action, subscription_id: domain.subscription_id, }); setMessage("Domain action completed."); window.location.reload(); } catch (error) { setMessage( error instanceof Error ? error.message : "Domain action failed", ); } finally { setLoading(false); } } async function onCheckout() { setLoading(true); try { const payload = await runRequest("/api/stripe/checkout"); if (payload.url) window.location.href = payload.url; } finally { setLoading(false); } } async function onPortal() { setLoading(true); try { const payload = await runRequest("/api/stripe/portal"); if (payload.url) window.location.href = payload.url; } finally { setLoading(false); } } return (

Connected

{healthCounts.connected}

Syncing

{healthCounts.syncing}

Error/Other

{healthCounts.error}

Connect Plesk Instance

) => setInstanceName(e.target.value) } className="w-full rounded border border-slate-300 px-3 py-2 text-sm" placeholder="Instance name" /> ) => setBaseUrl(e.target.value) } className="w-full rounded border border-slate-300 px-3 py-2 text-sm" placeholder="https://plesk.example.com" /> {authType === "api_key" ? ( ) => setApiKey(e.target.value) } className="w-full rounded border border-slate-300 px-3 py-2 text-sm" placeholder="Plesk API key" /> ) : (
) => setUsername(e.target.value) } className="w-full rounded border border-slate-300 px-3 py-2 text-sm" placeholder="Plesk username" /> ) => setPassword(e.target.value) } className="w-full rounded border border-slate-300 px-3 py-2 text-sm" placeholder="Plesk password" />
)}

Plesk Instances

{instances.length === 0 ? (

No Plesk instances connected yet.

) : ( instances.map((instance) => (
{autoSyncByInstance[instance.id] ? ( Auto-sync {autoSyncByInstance[instance.id].status} ) : null}

{instance.name}

{instance.base_url}

Status:{" "} {instance.status}

Subscriptions: {instance.last_sync_subscriptions ?? 0}

Domains: {instance.last_sync_domains ?? 0}

Last sync status:{" "} {instance.last_sync_status ?? "unknown"}

Last sync time: {formatDateTime(instance.last_sync_at)}

Last connected:{" "} {instance.last_connected_at ? formatDateTime(instance.last_connected_at) : "never"}

{autoSyncByInstance[instance.id] ? (

Last auto-sync:{" "} {formatDateTime( autoSyncByInstance[instance.id].created_at, )}

) : null} {instance.error_message ? (

{instance.error_message}

) : null} {instance.last_sync_error ? (

Last sync error: {instance.last_sync_error}

) : null} {autoSyncByInstance[instance.id]?.error_message ? (

Auto-sync error:{" "} {autoSyncByInstance[instance.id].error_message}

) : null}
)) )}
{message ?

{message}

: null}
) => setDomainSearch(e.target.value) } className="mt-1 w-full rounded border border-slate-300 px-3 py-2 text-sm" placeholder="Search by domain or hosting type" />
{filteredDomains.length === 0 ? ( ) : ( filteredDomains.map((domain) => ( )) )}
Domain Subscription Status Hosting Created Aliases Last seen Actions
No domains found.
{domain.domain_name} {domain.subscription_id ? (

Subscription: {domain.subscription_name ?? "Linked"}

) : (

Subscription: Unlinked

)}
{formatDomainStatusLabel(domain.status)} {domain.hosting_type ?? "unknown"} {formatDateTime(domain.source_created_at)} {domain.aliases_count ?? 0} {formatDateTime(domain.updated_at)}
); }