zen: check balance on enable billing

This commit is contained in:
Frank
2025-09-25 17:47:50 -04:00
parent 6e712f9faf
commit f9117bcc7f

View File

@@ -4,6 +4,8 @@ import { Billing } from "@opencode/console-core/billing.js"
import { withActor } from "~/context/auth.withActor" import { withActor } from "~/context/auth.withActor"
import { IconCreditCard } from "~/component/icon" import { IconCreditCard } from "~/component/icon"
import styles from "./billing-section.module.css" import styles from "./billing-section.module.css"
import { Database, eq } from "@opencode/console-core/drizzle/index.js"
import { BillingTable } from "@opencode/console-core/schema/billing.sql.js"
const createCheckoutUrl = action(async (workspaceID: string, successUrl: string, cancelUrl: string) => { const createCheckoutUrl = action(async (workspaceID: string, successUrl: string, cancelUrl: string) => {
"use server" "use server"
@@ -17,12 +19,23 @@ const reload = action(async (form: FormData) => {
return json(await withActor(() => Billing.reload(), workspaceID), { revalidate: getBillingInfo.key }) return json(await withActor(() => Billing.reload(), workspaceID), { revalidate: getBillingInfo.key })
}, "billing.reload") }, "billing.reload")
const disableReload = action(async (form: FormData) => { const setReload = action(async (form: FormData) => {
"use server" "use server"
const workspaceID = form.get("workspaceID")?.toString() const workspaceID = form.get("workspaceID")?.toString()
if (!workspaceID) return { error: "Workspace ID is required" } if (!workspaceID) return { error: "Workspace ID is required" }
return json(await withActor(() => Billing.disableReload(), workspaceID), { revalidate: getBillingInfo.key }) const reload = form.get("reload")?.toString() === "true"
}, "billing.disableReload") return json(
await Database.use((tx) =>
tx
.update(BillingTable)
.set({
reload,
})
.where(eq(BillingTable.workspaceID, workspaceID)),
),
{ revalidate: getBillingInfo.key },
)
}, "billing.setReload")
const createSessionUrl = action(async (workspaceID: string, returnUrl: string) => { const createSessionUrl = action(async (workspaceID: string, returnUrl: string) => {
"use server" "use server"
@@ -44,7 +57,7 @@ export function BillingSection() {
const createCheckoutUrlSubmission = useSubmission(createCheckoutUrl) const createCheckoutUrlSubmission = useSubmission(createCheckoutUrl)
const createSessionUrlAction = useAction(createSessionUrl) const createSessionUrlAction = useAction(createSessionUrl)
const createSessionUrlSubmission = useSubmission(createSessionUrl) const createSessionUrlSubmission = useSubmission(createSessionUrl)
const disableReloadSubmission = useSubmission(disableReload) const setReloadSubmission = useSubmission(setReload)
const reloadSubmission = useSubmission(reload) const reloadSubmission = useSubmission(reload)
// DUMMY DATA FOR TESTING - UNCOMMENT ONE OF THE SCENARIOS BELOW // DUMMY DATA FOR TESTING - UNCOMMENT ONE OF THE SCENARIOS BELOW
@@ -89,6 +102,10 @@ export function BillingSection() {
return ((balanceInfo()?.balance ?? 0) / 100000000).toFixed(2) return ((balanceInfo()?.balance ?? 0) / 100000000).toFixed(2)
}) })
const hasBalance = createMemo(() => {
return (balanceInfo()?.balance ?? 0) > 0 && balanceAmount() !== "0.00"
})
return ( return (
<section class={styles.root}> <section class={styles.root}>
<div data-slot="section-title"> <div data-slot="section-title">
@@ -135,6 +152,9 @@ export function BillingSection() {
<div data-slot="button-row"> <div data-slot="button-row">
<Show <Show
when={balanceInfo()?.reload} when={balanceInfo()?.reload}
fallback={
<Show
when={hasBalance()}
fallback={ fallback={
<button <button
data-color="primary" data-color="primary"
@@ -150,6 +170,16 @@ export function BillingSection() {
{createCheckoutUrlSubmission.pending ? "Loading..." : "Enable Billing"} {createCheckoutUrlSubmission.pending ? "Loading..." : "Enable Billing"}
</button> </button>
} }
>
<form action={setReload} method="post" data-slot="create-form">
<input type="hidden" name="workspaceID" value={params.id} />
<input type="hidden" name="reload" value="true" />
<button data-color="primary" type="submit" disabled={setReloadSubmission.pending}>
{setReloadSubmission.pending ? "Enabling..." : "Enable Billing"}
</button>
</form>
</Show>
}
> >
<button <button
data-color="primary" data-color="primary"
@@ -164,10 +194,11 @@ export function BillingSection() {
> >
{createSessionUrlSubmission.pending ? "Loading..." : "Manage Payment Methods"} {createSessionUrlSubmission.pending ? "Loading..." : "Manage Payment Methods"}
</button> </button>
<form action={disableReload} method="post" data-slot="create-form"> <form action={setReload} method="post" data-slot="create-form">
<input type="hidden" name="workspaceID" value={params.id} /> <input type="hidden" name="workspaceID" value={params.id} />
<button data-color="ghost" type="submit" disabled={disableReloadSubmission.pending}> <input type="hidden" name="reload" value="false" />
{disableReloadSubmission.pending ? "Disabling..." : "Disable"} <button data-color="ghost" type="submit" disabled={setReloadSubmission.pending}>
{setReloadSubmission.pending ? "Disabling..." : "Disable"}
</button> </button>
</form> </form>
</Show> </Show>
@@ -176,7 +207,7 @@ export function BillingSection() {
<div data-slot="usage"> <div data-slot="usage">
<Show when={!balanceInfo()?.reload}> <Show when={!balanceInfo()?.reload}>
<Show <Show
when={!(balanceAmount() === "0.00" || balanceAmount() === "-0.00")} when={hasBalance()}
fallback={ fallback={
<p> <p>
We'll load <b>$20</b> (+$1.23 processing fee) and reload it when it reaches <b>$5</b>. We'll load <b>$20</b> (+$1.23 processing fee) and reload it when it reaches <b>$5</b>.