import { Show, createSignal } from "solid-js"
import type { Relay, PlanId } from "@/lib/api"
import ConfirmDialog from "@/components/ConfirmDialog"
import Field from "@/components/Field"
import PricingTable from "@/components/PricingTable"
import ToggleButton from "@/components/ToggleButton"
import ToggleField from "@/components/ToggleField"
import RelayCardHeader from "@/components/relay/RelayCardHeader"
import PlanGatedToggle from "@/components/relay/PlanGatedToggle"
import { setToastMessage } from "@/lib/state"
import { useProfileMetadata } from "@/lib/hooks"
import { flagToBool } from "@/lib/relayFlags"
import { plans } from "@/lib/state"
function DetailSection(props: { title: string; children: any }) {
return (
{props.title}
{props.children}
)
}
function MembershipSection(props: { title: string; children: any }) {
return (
{props.title}
{props.children}
)
}
type RelayDetailCardProps = {
relay: Relay
currentMembers?: number
showTenant?: boolean
editHref?: string
onDeactivate?: () => void | Promise
onReactivate?: () => void | Promise
deactivating?: boolean
reactivating?: boolean
onTogglePublicJoin?: () => void
onToggleStripSignatures?: () => void
onToggleGroups?: () => void
onToggleManagement?: () => void
onToggleMediaStorage?: () => void
onToggleLivekitSupport?: () => void
onTogglePushNotifications?: () => void
onUpdatePlan?: (planId: PlanId) => Promise
enforcePlanLimits?: boolean
showPlanActions?: boolean
}
export default function RelayDetailCard(props: RelayDetailCardProps) {
const r = () => props.relay
const [planId, setPlanId] = createSignal(props.relay.plan_id)
const [pendingAction, setPendingAction] = createSignal<"deactivate" | "reactivate" | null>(null)
// Resolve the owning tenant's profile so the Tenant field can show a name and
// avatar instead of a raw pubkey. Only relevant in admin (showTenant) views.
// This subscription stays in the parent so the header doesn't double-subscribe.
const tenantProfile = useProfileMetadata(() => (props.showTenant ? props.relay.tenant_pubkey : undefined))
const memberLimitLabel = () => {
const p = plans().find(p => p.id === r().plan_id)
if (!p) return "?"
return p.members === null ? "∞" : String(p.members)
}
const planLimited = () => (props.enforcePlanLimits ?? true) && r().plan_id === "free"
const showPlanActions = () => props.showPlanActions ?? true
const actionBusy = () => pendingAction() === "deactivate" ? !!props.deactivating : pendingAction() === "reactivate" ? !!props.reactivating : false
const relayLabel = () => r().info_name || r().subdomain
const confirmTitle = () => pendingAction() === "deactivate" ? "Deactivate relay?" : "Reactivate relay?"
const confirmDescription = () => pendingAction() === "deactivate"
? `${relayLabel()} will be taken offline immediately.`
: `${relayLabel()} will come back online and start accepting connections.`
const confirmDetails = () => pendingAction() === "deactivate"
? [
"All client connections will be dropped immediately.",
"Members will be unable to read from or publish to the relay.",
"Scheduled and automated tasks (billing, syncing) will be paused.",
"All relay data, settings, and members are preserved, nothing is deleted.",
"You can reactivate at any time from this page.",
]
: undefined
const confirmLabel = () => pendingAction() === "deactivate" ? "Yes, deactivate" : "Yes, reactivate"
const confirmBusyLabel = () => pendingAction() === "deactivate" ? "Deactivating..." : "Reactivating..."
const confirmTone = () => pendingAction() === "deactivate" ? "danger" : "primary"
async function changePlanId(planId: PlanId) {
setPlanId(planId)
try {
await props.onUpdatePlan?.(planId)
setToastMessage(`Plan updated to ${planId}`, "success")
} catch {
// error is handled by the caller
}
}
function openActionDialog(action: "deactivate" | "reactivate") {
setPendingAction(action)
}
function closeActionDialog() {
if (actionBusy()) return
setPendingAction(null)
}
async function confirmAction() {
const action = pendingAction()
if (!action) return
if (action === "deactivate") {
await props.onDeactivate?.()
} else {
await props.onReactivate?.()
}
setPendingAction(null)
}
return (
openActionDialog("deactivate") : undefined}
onRequestReactivate={props.onReactivate ? () => openActionDialog("reactivate") : undefined}
/>
{props.currentMembers ?? "—"}
{memberLimitLabel()}
{r().plan_id}
}
>
)
}