forked from coracle/caravel
Add dunning
This commit is contained in:
@@ -45,7 +45,7 @@ export default function AppShell(props: { children?: any }) {
|
||||
|
||||
createEffect(async () => {
|
||||
const t = tenant()
|
||||
if (!t?.past_due_at) {
|
||||
if (!t?.churned_at) {
|
||||
setPastDueInvoice(undefined)
|
||||
return
|
||||
}
|
||||
@@ -158,9 +158,9 @@ export default function AppShell(props: { children?: any }) {
|
||||
</aside>
|
||||
|
||||
<div class="md:pl-[260px] min-h-screen pb-20 md:pb-0">
|
||||
<Show when={tenant()?.past_due_at}>
|
||||
<Show when={tenant()?.churned_at}>
|
||||
<div class="bg-red-600 text-white px-4 py-3 text-sm flex items-center justify-between">
|
||||
<span>Your account has an overdue balance.</span>
|
||||
<span>Your account is past due and some relays are paused. Update your payment method to restore service.</span>
|
||||
<Show when={pastDueInvoice()}>
|
||||
<button
|
||||
type="button"
|
||||
|
||||
@@ -98,9 +98,9 @@ export type Tenant = {
|
||||
nwc_is_set: boolean
|
||||
created_at: number
|
||||
stripe_customer_id: string
|
||||
stripe_subscription_id: string | null
|
||||
past_due_at: number | null
|
||||
nwc_error: string | null
|
||||
stripe_error: string | null
|
||||
churned_at: number | null
|
||||
}
|
||||
|
||||
export type Invoice = {
|
||||
@@ -142,8 +142,6 @@ export async function makeAuth(): Promise<string | undefined> {
|
||||
kind: 27235,
|
||||
content: "",
|
||||
created_at: Math.floor(now / 1000),
|
||||
// Intentional session-style auth: sign the API base URL once, then reuse
|
||||
// the header briefly to avoid prompting the signer on every request.
|
||||
tags: [["u", API_URL]],
|
||||
})
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ export const reactivateRelayById = (id: string) => reactivateRelay(id)
|
||||
|
||||
export async function tenantNeedsPaymentSetup(): Promise<boolean> {
|
||||
const tenant = await getTenant(account()!.pubkey)
|
||||
return !tenant.nwc_is_set && !tenant.stripe_subscription_id
|
||||
return !tenant.nwc_is_set
|
||||
}
|
||||
|
||||
export async function getLatestOpenInvoice(): Promise<Invoice | null> {
|
||||
|
||||
@@ -142,8 +142,16 @@ export default function Account() {
|
||||
{saving() ? "Saving..." : "Save"}
|
||||
</button>
|
||||
</div>
|
||||
<Show when={tenant()?.churned_at}>
|
||||
<p class="mb-4 rounded-lg border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700">
|
||||
Your account is past due and some relays have been paused. Update your payment method below to restore service.
|
||||
</p>
|
||||
</Show>
|
||||
<Show when={tenant()?.nwc_error}>
|
||||
<p class="mt-3 text-sm text-red-600">{tenant()!.nwc_error}</p>
|
||||
<p class="mt-3 text-sm text-red-600">Lightning auto-payment failed: {tenant()!.nwc_error}</p>
|
||||
</Show>
|
||||
<Show when={tenant()?.stripe_error}>
|
||||
<p class="mt-3 text-sm text-red-600">Card auto-payment failed: {tenant()!.stripe_error}</p>
|
||||
</Show>
|
||||
<Show when={error()}>
|
||||
<p class="mt-3 text-sm text-red-600">{error()}</p>
|
||||
|
||||
@@ -14,8 +14,8 @@ export default function AdminTenantDetail() {
|
||||
const [relays] = useAdminTenantRelays(tenantId)
|
||||
const loading = useMinLoading(() => tenant.loading || relays.loading)
|
||||
|
||||
const pastDueLabel = () => {
|
||||
const ts = tenant()?.past_due_at
|
||||
const churnedLabel = () => {
|
||||
const ts = tenant()?.churned_at
|
||||
if (!ts) return null
|
||||
return new Date(ts * 1000).toLocaleString()
|
||||
}
|
||||
@@ -34,7 +34,7 @@ export default function AdminTenantDetail() {
|
||||
<dl class="grid gap-y-3 text-sm">
|
||||
<div class="flex gap-2">
|
||||
<dt class="text-gray-500">Status:</dt>
|
||||
<dd class="font-medium uppercase tracking-wide">{t().past_due_at ? "past due" : "active"}</dd>
|
||||
<dd class="font-medium uppercase tracking-wide">{t().churned_at ? "delinquent" : "active"}</dd>
|
||||
</div>
|
||||
<Show when={t().stripe_customer_id}>
|
||||
<div class="flex gap-2">
|
||||
@@ -42,10 +42,10 @@ export default function AdminTenantDetail() {
|
||||
<dd class="font-mono text-xs">{t().stripe_customer_id}</dd>
|
||||
</div>
|
||||
</Show>
|
||||
<Show when={pastDueLabel()}>
|
||||
<Show when={churnedLabel()}>
|
||||
<div class="flex gap-2">
|
||||
<dt class="text-gray-500">Past Due Since:</dt>
|
||||
<dd class="text-red-600 font-medium">{pastDueLabel()}</dd>
|
||||
<dt class="text-gray-500">Delinquent Since:</dt>
|
||||
<dd class="text-red-600 font-medium">{churnedLabel()}</dd>
|
||||
</div>
|
||||
</Show>
|
||||
<Show when={t().nwc_error}>
|
||||
@@ -54,6 +54,12 @@ export default function AdminTenantDetail() {
|
||||
<dd class="text-red-600">{t().nwc_error}</dd>
|
||||
</div>
|
||||
</Show>
|
||||
<Show when={t().stripe_error}>
|
||||
<div class="flex gap-2">
|
||||
<dt class="text-gray-500">Stripe Error:</dt>
|
||||
<dd class="text-red-600">{t().stripe_error}</dd>
|
||||
</div>
|
||||
</Show>
|
||||
</dl>
|
||||
)}
|
||||
</Show>
|
||||
|
||||
Reference in New Issue
Block a user