summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorFrank <[email protected]>2025-09-25 17:47:50 -0400
committerFrank <[email protected]>2025-09-25 17:47:50 -0400
commitf9117bcc7f03a45458e20b6488881cf3ac0f877e (patch)
treef1ee97105c2b12aa9ab208d2ef62004afef80b79
parent6e712f9faf4e83c3e063ab2d2daeb7fd38194ca8 (diff)
downloadopencode-f9117bcc7f03a45458e20b6488881cf3ac0f877e.tar.gz
opencode-f9117bcc7f03a45458e20b6488881cf3ac0f877e.zip
zen: check balance on enable billing
-rw-r--r--packages/console/app/src/component/workspace/billing-section.tsx71
1 files changed, 51 insertions, 20 deletions
diff --git a/packages/console/app/src/component/workspace/billing-section.tsx b/packages/console/app/src/component/workspace/billing-section.tsx
index 7d297ed33..02cf8433e 100644
--- a/packages/console/app/src/component/workspace/billing-section.tsx
+++ b/packages/console/app/src/component/workspace/billing-section.tsx
@@ -4,6 +4,8 @@ import { Billing } from "@opencode/console-core/billing.js"
import { withActor } from "~/context/auth.withActor"
import { IconCreditCard } from "~/component/icon"
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) => {
"use server"
@@ -17,12 +19,23 @@ const reload = action(async (form: FormData) => {
return json(await withActor(() => Billing.reload(), workspaceID), { revalidate: getBillingInfo.key })
}, "billing.reload")
-const disableReload = action(async (form: FormData) => {
+const setReload = action(async (form: FormData) => {
"use server"
const workspaceID = form.get("workspaceID")?.toString()
if (!workspaceID) return { error: "Workspace ID is required" }
- return json(await withActor(() => Billing.disableReload(), workspaceID), { revalidate: getBillingInfo.key })
-}, "billing.disableReload")
+ const reload = form.get("reload")?.toString() === "true"
+ 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) => {
"use server"
@@ -44,7 +57,7 @@ export function BillingSection() {
const createCheckoutUrlSubmission = useSubmission(createCheckoutUrl)
const createSessionUrlAction = useAction(createSessionUrl)
const createSessionUrlSubmission = useSubmission(createSessionUrl)
- const disableReloadSubmission = useSubmission(disableReload)
+ const setReloadSubmission = useSubmission(setReload)
const reloadSubmission = useSubmission(reload)
// DUMMY DATA FOR TESTING - UNCOMMENT ONE OF THE SCENARIOS BELOW
@@ -89,6 +102,10 @@ export function BillingSection() {
return ((balanceInfo()?.balance ?? 0) / 100000000).toFixed(2)
})
+ const hasBalance = createMemo(() => {
+ return (balanceInfo()?.balance ?? 0) > 0 && balanceAmount() !== "0.00"
+ })
+
return (
<section class={styles.root}>
<div data-slot="section-title">
@@ -136,19 +153,32 @@ export function BillingSection() {
<Show
when={balanceInfo()?.reload}
fallback={
- <button
- data-color="primary"
- disabled={createCheckoutUrlSubmission.pending}
- onClick={async () => {
- const baseUrl = window.location.href
- const checkoutUrl = await createCheckoutUrlAction(params.id, baseUrl, baseUrl)
- if (checkoutUrl) {
- window.location.href = checkoutUrl
- }
- }}
+ <Show
+ when={hasBalance()}
+ fallback={
+ <button
+ data-color="primary"
+ disabled={createCheckoutUrlSubmission.pending}
+ onClick={async () => {
+ const baseUrl = window.location.href
+ const checkoutUrl = await createCheckoutUrlAction(params.id, baseUrl, baseUrl)
+ if (checkoutUrl) {
+ window.location.href = checkoutUrl
+ }
+ }}
+ >
+ {createCheckoutUrlSubmission.pending ? "Loading..." : "Enable Billing"}
+ </button>
+ }
>
- {createCheckoutUrlSubmission.pending ? "Loading..." : "Enable Billing"}
- </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
@@ -164,10 +194,11 @@ export function BillingSection() {
>
{createSessionUrlSubmission.pending ? "Loading..." : "Manage Payment Methods"}
</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} />
- <button data-color="ghost" type="submit" disabled={disableReloadSubmission.pending}>
- {disableReloadSubmission.pending ? "Disabling..." : "Disable"}
+ <input type="hidden" name="reload" value="false" />
+ <button data-color="ghost" type="submit" disabled={setReloadSubmission.pending}>
+ {setReloadSubmission.pending ? "Disabling..." : "Disable"}
</button>
</form>
</Show>
@@ -176,7 +207,7 @@ export function BillingSection() {
<div data-slot="usage">
<Show when={!balanceInfo()?.reload}>
<Show
- when={!(balanceAmount() === "0.00" || balanceAmount() === "-0.00")}
+ when={hasBalance()}
fallback={
<p>
We'll load <b>$20</b> (+$1.23 processing fee) and reload it when it reaches <b>$5</b>.