import { createEffect, createMemo, createResource, createSignal, For, Show } from "solid-js" import PageContainer from "@/components/PageContainer" import LoadingState from "@/components/LoadingState" import PaymentDialog from "@/components/PaymentDialog" import useMinLoading from "@/components/useMinLoading" import { updateActiveTenant, useTenant } from "@/lib/hooks" import { createPortalSession, listTenantInvoices, type Invoice } from "@/lib/api" import { account } from "@/lib/state" export default function Account() { const [tenant, { refetch: refetchTenant }] = useTenant() const [invoices, { refetch: refetchInvoices }] = createResource(() => listTenantInvoices(account()!.pubkey)) const [nwcUrl, setNwcUrl] = createSignal("") const [saving, setSaving] = createSignal(false) const [error, setError] = createSignal("") const [selectedInvoice, setSelectedInvoice] = createSignal() const [portalLoading, setPortalLoading] = createSignal(false) const invoicesLoading = useMinLoading(() => invoices.loading) const hasBillingChanges = createMemo(() => { const current = tenant()?.nwc_url?.trim() ?? "" const next = nwcUrl().trim() return current !== next }) createEffect(() => { setNwcUrl(tenant()?.nwc_url ?? "") }) async function saveBilling() { setError("") setSaving(true) try { const next = nwcUrl().trim() await updateActiveTenant({ nwc_url: next }) await refetchTenant() } catch (e) { setError(e instanceof Error ? e.message : "Failed to update billing") } finally { setSaving(false) } } function handleInvoiceDialogClose() { setSelectedInvoice(undefined) void refetchInvoices() } async function openPortal() { setPortalLoading(true) try { const { url } = await createPortalSession(account()!.pubkey, window.location.href) window.location.href = url } catch (e) { setError(e instanceof Error ? e.message : "Failed to open billing portal") } finally { setPortalLoading(false) } } function logout() { localStorage.clear() window.location.href = "/" } const invoiceStatusStyles: Record = { draft: "bg-gray-100 text-gray-500 border-gray-200", open: "bg-yellow-50 text-yellow-700 border-yellow-200", paid: "bg-green-50 text-green-700 border-green-200", void: "bg-gray-100 text-gray-500 border-gray-200", uncollectible: "bg-red-50 text-red-700 border-red-200", } return (

My Account

Account Status

tenant

Recurring Billing

Enable automatic payments by providing your Nostr Wallet Connect URL.

setNwcUrl(e.currentTarget.value)} placeholder="nostr+walletconnect://..." class="flex-1 border border-gray-300 rounded-lg px-3 py-2" />

{tenant()!.nwc_error}

{error()}

Invoice History

0} fallback={

No invoices yet.

}>
    {(invoice) => { const isOpen = () => invoice.status === "open" const statusStyle = () => invoiceStatusStyles[invoice.status] ?? "bg-gray-100 text-gray-500 border-gray-200" const periodLabel = () => { const start = new Date(invoice.period_start * 1000) const end = new Date(invoice.period_end * 1000) return `${start.toLocaleDateString()} – ${end.toLocaleDateString()}` } return (
  • isOpen() && setSelectedInvoice(invoice)} title={isOpen() ? "Click to pay this invoice" : undefined} >
    ${(invoice.amount_due / 100).toFixed(2)}

    {periodLabel()}

    Pay now {invoice.status}
  • ) }}
{(invoice) => ( )}
) }