Do some refactoring

This commit is contained in:
Jon Staab
2026-02-27 13:23:41 -08:00
parent 5d102ad215
commit 247a5c0ec0
12 changed files with 153 additions and 88 deletions
+14
View File
@@ -0,0 +1,14 @@
import { A } from "@solidjs/router"
type BackLinkProps = {
href: string
label: string
}
export default function BackLink(props: BackLinkProps) {
return (
<div class="flex items-center gap-2 mb-6">
<A href={props.href} class="text-gray-500 hover:text-gray-700"> {props.label}</A>
</div>
)
}
+12
View File
@@ -0,0 +1,12 @@
import type { JSX } from "solid-js"
type PageContainerProps = {
children: JSX.Element
size?: "narrow" | "wide"
}
export default function PageContainer(props: PageContainerProps) {
const maxWidthClass = () => (props.size === "narrow" ? "max-w-2xl" : "max-w-4xl")
return <div class={`${maxWidthClass()} mx-auto px-4 py-8`}>{props.children}</div>
}
+22
View File
@@ -0,0 +1,22 @@
import { Show } from "solid-js"
type ResourceStateProps = {
loading: boolean
error: unknown
loadingText: string
errorText: string
class?: string
}
export default function ResourceState(props: ResourceStateProps) {
return (
<>
<Show when={props.loading}>
<p class={`text-gray-500 ${props.class ?? ""}`.trim()}>{props.loadingText}</p>
</Show>
<Show when={props.error && !props.loading}>
<p class={`text-red-600 ${props.class ?? ""}`.trim()}>{props.errorText}</p>
</Show>
</>
)
}
+10 -5
View File
@@ -1,5 +1,7 @@
import { createMemo, createResource, createSignal, For, Show } from "solid-js" import { createMemo, createResource, createSignal, For, Show } from "solid-js"
import { getTenant, listTenantInvoices, updateTenantBilling } from "../lib/api" import { getTenant, listTenantInvoices, updateTenantBilling } from "../lib/api"
import PageContainer from "../components/PageContainer"
import ResourceState from "../components/ResourceState"
export default function Account() { export default function Account() {
const [tenant, { refetch: refetchTenant }] = createResource(getTenant) const [tenant, { refetch: refetchTenant }] = createResource(getTenant)
@@ -25,7 +27,7 @@ export default function Account() {
} }
return ( return (
<div class="max-w-4xl mx-auto px-4 py-8"> <PageContainer>
<h1 class="text-2xl font-bold text-gray-900 mb-6">My Account</h1> <h1 class="text-2xl font-bold text-gray-900 mb-6">My Account</h1>
<div class="space-y-6"> <div class="space-y-6">
@@ -40,9 +42,12 @@ export default function Account() {
)} )}
</Show> </Show>
</div> </div>
<Show when={tenant.loading}> <ResourceState
<p class="text-gray-500">Loading account...</p> loading={tenant.loading}
</Show> error={undefined}
loadingText="Loading account..."
errorText=""
/>
</section> </section>
<section class="bg-white border border-gray-200 rounded-xl p-6"> <section class="bg-white border border-gray-200 rounded-xl p-6">
@@ -106,6 +111,6 @@ export default function Account() {
</Show> </Show>
</section> </section>
</div> </div>
</div> </PageContainer>
) )
} }
+13 -11
View File
@@ -1,6 +1,9 @@
import { useParams, A } from "@solidjs/router" import { useParams, A } from "@solidjs/router"
import { createResource, createSignal, Show } from "solid-js" import { createResource, createSignal, Show } from "solid-js"
import { adminDeactivateRelay, adminGetRelay } from "../../lib/api" import { adminDeactivateRelay, adminGetRelay } from "../../lib/api"
import BackLink from "../../components/BackLink"
import PageContainer from "../../components/PageContainer"
import ResourceState from "../../components/ResourceState"
export default function AdminRelayDetail() { export default function AdminRelayDetail() {
const params = useParams() const params = useParams()
@@ -24,17 +27,16 @@ export default function AdminRelayDetail() {
} }
return ( return (
<div class="max-w-4xl mx-auto px-4 py-8"> <PageContainer>
<div class="flex items-center gap-2 mb-6"> <BackLink href="/admin/relays" label="Relays" />
<A href="/admin/relays" class="text-gray-500 hover:text-gray-700"> Relays</A>
</div>
<Show when={relay.loading}> <ResourceState
<p class="text-gray-500 mb-4">Loading relay...</p> loading={relay.loading}
</Show> error={relay.error}
<Show when={relay.error && !relay.loading}> loadingText="Loading relay..."
<p class="text-red-600 mb-4">Failed to load relay.</p> errorText="Failed to load relay."
</Show> class="mb-4"
/>
<Show when={relay()}> <Show when={relay()}>
{(r) => ( {(r) => (
@@ -69,6 +71,6 @@ export default function AdminRelayDetail() {
<Show when={error()}> <Show when={error()}>
<p class="mt-3 text-sm text-red-600">{error()}</p> <p class="mt-3 text-sm text-red-600">{error()}</p>
</Show> </Show>
</div> </PageContainer>
) )
} }
+13 -12
View File
@@ -1,9 +1,12 @@
import { A, useNavigate, useParams } from "@solidjs/router" import { useNavigate, useParams } from "@solidjs/router"
import { Show, createEffect, createResource, createSignal } from "solid-js" import { Show, createEffect, createResource, createSignal } from "solid-js"
import { adminGetRelay, adminUpdateRelay } from "../../lib/api" import { adminGetRelay, adminUpdateRelay } from "../../lib/api"
import RelayForm from "../../components/RelayForm" import RelayForm from "../../components/RelayForm"
import { RELAY_PLAN_IDS, type RelayPlanId } from "../../lib/relayPlans" import { RELAY_PLAN_IDS, type RelayPlanId } from "../../lib/relayPlans"
import { slugify } from "../../lib/slugify" import { slugify } from "../../lib/slugify"
import BackLink from "../../components/BackLink"
import PageContainer from "../../components/PageContainer"
import ResourceState from "../../components/ResourceState"
export default function AdminRelayEdit() { export default function AdminRelayEdit() {
const navigate = useNavigate() const navigate = useNavigate()
@@ -50,18 +53,16 @@ export default function AdminRelayEdit() {
} }
return ( return (
<div class="max-w-2xl mx-auto px-4 py-8"> <PageContainer size="narrow">
<div class="flex items-center gap-2 mb-6"> <BackLink href={`/admin/relays/${params.id}`} label="Back" />
<A href={`/admin/relays/${params.id}`} class="text-gray-500 hover:text-gray-700"> Back</A>
</div>
<h1 class="text-2xl font-bold text-gray-900 mb-6">Edit Relay (Admin)</h1> <h1 class="text-2xl font-bold text-gray-900 mb-6">Edit Relay (Admin)</h1>
<Show when={relay.loading}> <ResourceState
<p class="text-gray-500">Loading relay...</p> loading={relay.loading}
</Show> error={relay.error}
<Show when={relay.error && !relay.loading}> loadingText="Loading relay..."
<p class="text-red-600">Failed to load relay.</p> errorText="Failed to load relay."
</Show> />
<Show when={relay() && !relay.loading}> <Show when={relay() && !relay.loading}>
<RelayForm <RelayForm
@@ -83,6 +84,6 @@ export default function AdminRelayEdit() {
submittingLabel="Saving..." submittingLabel="Saving..."
/> />
</Show> </Show>
</div> </PageContainer>
) )
} }
+10 -8
View File
@@ -1,6 +1,8 @@
import { A } from "@solidjs/router" import { A } from "@solidjs/router"
import { createMemo, createResource, createSignal, For, Show } from "solid-js" import { createMemo, createResource, createSignal, For, Show } from "solid-js"
import { adminListRelays } from "../../lib/api" import { adminListRelays } from "../../lib/api"
import PageContainer from "../../components/PageContainer"
import ResourceState from "../../components/ResourceState"
export default function AdminRelays() { export default function AdminRelays() {
const [query, setQuery] = createSignal("") const [query, setQuery] = createSignal("")
@@ -19,7 +21,7 @@ export default function AdminRelays() {
}) })
return ( return (
<div class="max-w-4xl mx-auto px-4 py-8"> <PageContainer>
<h1 class="text-2xl font-bold text-gray-900 mb-6">All Relays</h1> <h1 class="text-2xl font-bold text-gray-900 mb-6">All Relays</h1>
<input <input
type="search" type="search"
@@ -29,12 +31,12 @@ export default function AdminRelays() {
class="w-full border border-gray-300 rounded-lg px-3 py-2 mb-6 focus:outline-none focus:ring-2 focus:ring-blue-500" class="w-full border border-gray-300 rounded-lg px-3 py-2 mb-6 focus:outline-none focus:ring-2 focus:ring-blue-500"
/> />
<Show when={relays.loading}> <ResourceState
<p class="text-gray-500">Loading relays...</p> loading={relays.loading}
</Show> error={relays.error}
<Show when={relays.error && !relays.loading}> loadingText="Loading relays..."
<p class="text-red-600">Failed to load relays.</p> errorText="Failed to load relays."
</Show> />
<Show when={(filtered().length ?? 0) > 0} fallback={<p class="text-gray-500">No relays found.</p>}> <Show when={(filtered().length ?? 0) > 0} fallback={<p class="text-gray-500">No relays found.</p>}>
<ul class="space-y-3"> <ul class="space-y-3">
<For each={filtered()}> <For each={filtered()}>
@@ -55,6 +57,6 @@ export default function AdminRelays() {
</For> </For>
</ul> </ul>
</Show> </Show>
</div> </PageContainer>
) )
} }
+13 -11
View File
@@ -1,6 +1,9 @@
import { useParams, A } from "@solidjs/router" import { useParams, A } from "@solidjs/router"
import { createResource, createSignal, For, Show } from "solid-js" import { createResource, createSignal, For, Show } from "solid-js"
import { adminGetTenant, adminUpdateTenantStatus } from "../../lib/api" import { adminGetTenant, adminUpdateTenantStatus } from "../../lib/api"
import BackLink from "../../components/BackLink"
import PageContainer from "../../components/PageContainer"
import ResourceState from "../../components/ResourceState"
export default function AdminTenantDetail() { export default function AdminTenantDetail() {
const params = useParams() const params = useParams()
@@ -24,18 +27,17 @@ export default function AdminTenantDetail() {
} }
return ( return (
<div class="max-w-4xl mx-auto px-4 py-8"> <PageContainer>
<div class="flex items-center gap-2 mb-6"> <BackLink href="/admin/tenants" label="Tenants" />
<A href="/admin/tenants" class="text-gray-500 hover:text-gray-700"> Tenants</A>
</div>
<h1 class="text-2xl font-bold text-gray-900 mb-6">Tenant {params.id}</h1> <h1 class="text-2xl font-bold text-gray-900 mb-6">Tenant {params.id}</h1>
<Show when={detail.loading}> <ResourceState
<p class="text-gray-500 mb-4">Loading tenant...</p> loading={detail.loading}
</Show> error={detail.error}
<Show when={detail.error && !detail.loading}> loadingText="Loading tenant..."
<p class="text-red-600 mb-4">Failed to load tenant.</p> errorText="Failed to load tenant."
</Show> class="mb-4"
/>
<div class="space-y-6"> <div class="space-y-6">
<section class="bg-white border border-gray-200 rounded-xl p-6"> <section class="bg-white border border-gray-200 rounded-xl p-6">
@@ -93,6 +95,6 @@ export default function AdminTenantDetail() {
<p class="text-sm text-red-600">{error()}</p> <p class="text-sm text-red-600">{error()}</p>
</Show> </Show>
</div> </div>
</div> </PageContainer>
) )
} }
+10 -8
View File
@@ -3,6 +3,8 @@ import { createEffect, createMemo, createResource, createSignal, For, onCleanup,
import { getProfilePicture } from "applesauce-core/helpers/profile" import { getProfilePicture } from "applesauce-core/helpers/profile"
import { adminListTenants } from "../../lib/api" import { adminListTenants } from "../../lib/api"
import { eventStore, primeProfiles } from "../../lib/nostr" import { eventStore, primeProfiles } from "../../lib/nostr"
import PageContainer from "../../components/PageContainer"
import ResourceState from "../../components/ResourceState"
function shortenPubkey(pubkey: string) { function shortenPubkey(pubkey: string) {
if (pubkey.length <= 16) return pubkey if (pubkey.length <= 16) return pubkey
@@ -48,7 +50,7 @@ export default function AdminTenants() {
}) })
return ( return (
<div class="max-w-4xl mx-auto px-4 py-8"> <PageContainer>
<h1 class="text-2xl font-bold text-gray-900 mb-6">Tenants</h1> <h1 class="text-2xl font-bold text-gray-900 mb-6">Tenants</h1>
<input <input
type="search" type="search"
@@ -58,12 +60,12 @@ export default function AdminTenants() {
class="w-full border border-gray-300 rounded-lg px-3 py-2 mb-6 focus:outline-none focus:ring-2 focus:ring-blue-500" class="w-full border border-gray-300 rounded-lg px-3 py-2 mb-6 focus:outline-none focus:ring-2 focus:ring-blue-500"
/> />
<Show when={tenants.loading}> <ResourceState
<p class="text-gray-500">Loading tenants...</p> loading={tenants.loading}
</Show> error={tenants.error}
<Show when={tenants.error && !tenants.loading}> loadingText="Loading tenants..."
<p class="text-red-600">Failed to load tenants.</p> errorText="Failed to load tenants."
</Show> />
<Show when={(filtered().length ?? 0) > 0} fallback={<p class="text-gray-500">No tenants found.</p>}> <Show when={(filtered().length ?? 0) > 0} fallback={<p class="text-gray-500">No tenants found.</p>}>
<ul class="space-y-3"> <ul class="space-y-3">
<For each={filtered()}> <For each={filtered()}>
@@ -96,6 +98,6 @@ export default function AdminTenants() {
</For> </For>
</ul> </ul>
</Show> </Show>
</div> </PageContainer>
) )
} }
+13 -12
View File
@@ -1,6 +1,9 @@
import { useParams, A } from "@solidjs/router" import { useParams, A } from "@solidjs/router"
import { createResource, createSignal, Show } from "solid-js" import { createResource, createSignal, Show } from "solid-js"
import { deactivateTenantRelay, getTenantRelay } from "../../lib/api" import { deactivateTenantRelay, getTenantRelay } from "../../lib/api"
import BackLink from "../../components/BackLink"
import PageContainer from "../../components/PageContainer"
import ResourceState from "../../components/ResourceState"
export default function RelayDetail() { export default function RelayDetail() {
const params = useParams() const params = useParams()
@@ -24,18 +27,16 @@ export default function RelayDetail() {
} }
return ( return (
<div class="max-w-4xl mx-auto px-4 py-8"> <PageContainer>
<div class="flex items-center gap-2 mb-6"> <BackLink href="/relays" label="Relays" />
<A href="/relays" class="text-gray-500 hover:text-gray-700"> Relays</A>
</div>
<Show when={relay.loading}> <ResourceState
<p class="text-gray-500 mb-4">Loading relay...</p> loading={relay.loading}
</Show> error={relay.error}
loadingText="Loading relay..."
<Show when={relay.error && !relay.loading}> errorText="Failed to load relay."
<p class="text-red-600 mb-4">Failed to load relay.</p> class="mb-4"
</Show> />
<Show when={relay()}> <Show when={relay()}>
{(loadedRelay) => ( {(loadedRelay) => (
@@ -67,6 +68,6 @@ export default function RelayDetail() {
<Show when={error()}> <Show when={error()}>
<p class="mt-3 text-sm text-red-600">{error()}</p> <p class="mt-3 text-sm text-red-600">{error()}</p>
</Show> </Show>
</div> </PageContainer>
) )
} }
+13 -12
View File
@@ -1,9 +1,12 @@
import { A, useNavigate, useParams } from "@solidjs/router" import { useNavigate, useParams } from "@solidjs/router"
import { Show, createEffect, createResource, createSignal } from "solid-js" import { Show, createEffect, createResource, createSignal } from "solid-js"
import { getTenantRelay, updateTenantRelay } from "../../lib/api" import { getTenantRelay, updateTenantRelay } from "../../lib/api"
import RelayForm from "../../components/RelayForm" import RelayForm from "../../components/RelayForm"
import { RELAY_PLAN_IDS, type RelayPlanId } from "../../lib/relayPlans" import { RELAY_PLAN_IDS, type RelayPlanId } from "../../lib/relayPlans"
import { slugify } from "../../lib/slugify" import { slugify } from "../../lib/slugify"
import BackLink from "../../components/BackLink"
import PageContainer from "../../components/PageContainer"
import ResourceState from "../../components/ResourceState"
export default function RelayEdit() { export default function RelayEdit() {
const navigate = useNavigate() const navigate = useNavigate()
@@ -50,18 +53,16 @@ export default function RelayEdit() {
} }
return ( return (
<div class="max-w-2xl mx-auto px-4 py-8"> <PageContainer size="narrow">
<div class="flex items-center gap-2 mb-6"> <BackLink href={`/relays/${params.id}`} label="Back" />
<A href={`/relays/${params.id}`} class="text-gray-500 hover:text-gray-700"> Back</A>
</div>
<h1 class="text-2xl font-bold text-gray-900 mb-6">Edit Relay</h1> <h1 class="text-2xl font-bold text-gray-900 mb-6">Edit Relay</h1>
<Show when={relay.loading}> <ResourceState
<p class="text-gray-500">Loading relay...</p> loading={relay.loading}
</Show> error={relay.error}
<Show when={relay.error && !relay.loading}> loadingText="Loading relay..."
<p class="text-red-600">Failed to load relay.</p> errorText="Failed to load relay."
</Show> />
<Show when={relay() && !relay.loading}> <Show when={relay() && !relay.loading}>
<RelayForm <RelayForm
@@ -83,6 +84,6 @@ export default function RelayEdit() {
submittingLabel="Saving..." submittingLabel="Saving..."
/> />
</Show> </Show>
</div> </PageContainer>
) )
} }
+10 -9
View File
@@ -1,6 +1,8 @@
import { A } from "@solidjs/router" import { A } from "@solidjs/router"
import { createMemo, createResource, createSignal, For, Show } from "solid-js" import { createMemo, createResource, createSignal, For, Show } from "solid-js"
import { listTenantRelays } from "../../lib/api" import { listTenantRelays } from "../../lib/api"
import PageContainer from "../../components/PageContainer"
import ResourceState from "../../components/ResourceState"
export default function RelayList() { export default function RelayList() {
const [relays] = createResource(listTenantRelays) const [relays] = createResource(listTenantRelays)
@@ -20,7 +22,7 @@ export default function RelayList() {
}) })
return ( return (
<div class="max-w-4xl mx-auto px-4 py-8"> <PageContainer>
<div class="flex items-center justify-between mb-6"> <div class="flex items-center justify-between mb-6">
<h1 class="text-2xl font-bold text-gray-900">My Relays</h1> <h1 class="text-2xl font-bold text-gray-900">My Relays</h1>
<A <A
@@ -53,13 +55,12 @@ export default function RelayList() {
</select> </select>
</div> </div>
<Show when={relays.loading}> <ResourceState
<p class="text-gray-500">Loading relays...</p> loading={relays.loading}
</Show> error={relays.error}
loadingText="Loading relays..."
<Show when={relays.error && !relays.loading}> errorText="Failed to load relays."
<p class="text-red-600">Failed to load relays.</p> />
</Show>
<Show when={(filtered().length ?? 0) > 0} fallback={<p class="text-gray-500">No relays match your filters.</p>}> <Show when={(filtered().length ?? 0) > 0} fallback={<p class="text-gray-500">No relays match your filters.</p>}>
<ul class="space-y-3"> <ul class="space-y-3">
@@ -83,6 +84,6 @@ export default function RelayList() {
</For> </For>
</ul> </ul>
</Show> </Show>
</div> </PageContainer>
) )
} }