summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorFrank <[email protected]>2026-01-22 13:01:48 -0500
committerFrank <[email protected]>2026-01-22 13:02:28 -0500
commite17b8756412f293b2383c29583339eb0a7d25ce3 (patch)
tree5bb1c9f744f4836811e4cdead765ab2e6b6120d2
parenta890d51bbc6a5608ad5992c74ee49153775aceb3 (diff)
downloadopencode-e17b8756412f293b2383c29583339eb0a7d25ce3.tar.gz
opencode-e17b8756412f293b2383c29583339eb0a7d25ce3.zip
zen: cancel waitlist
-rw-r--r--packages/console/app/src/routes/black/subscribe/[plan].tsx2
-rw-r--r--packages/console/app/src/routes/workspace/[id]/billing/black-waitlist-section.module.css8
-rw-r--r--packages/console/app/src/routes/workspace/[id]/billing/black-waitlist-section.tsx57
-rw-r--r--packages/console/app/src/routes/workspace/[id]/billing/index.tsx6
4 files changed, 70 insertions, 3 deletions
diff --git a/packages/console/app/src/routes/black/subscribe/[plan].tsx b/packages/console/app/src/routes/black/subscribe/[plan].tsx
index b2b9b32e1..a7cf92a25 100644
--- a/packages/console/app/src/routes/black/subscribe/[plan].tsx
+++ b/packages/console/app/src/routes/black/subscribe/[plan].tsx
@@ -219,8 +219,6 @@ function IntentForm(props: { plan: PlanID; workspaceID: string; onSuccess: (data
return
}
- // TODO
- console.log(setupIntent)
if (setupIntent?.status === "succeeded") {
const pm = setupIntent.payment_method as PaymentMethod
diff --git a/packages/console/app/src/routes/workspace/[id]/billing/black-waitlist-section.module.css b/packages/console/app/src/routes/workspace/[id]/billing/black-waitlist-section.module.css
new file mode 100644
index 000000000..c189f0d64
--- /dev/null
+++ b/packages/console/app/src/routes/workspace/[id]/billing/black-waitlist-section.module.css
@@ -0,0 +1,8 @@
+.root {
+ [data-slot="title-row"] {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ gap: var(--space-4);
+ }
+}
diff --git a/packages/console/app/src/routes/workspace/[id]/billing/black-waitlist-section.tsx b/packages/console/app/src/routes/workspace/[id]/billing/black-waitlist-section.tsx
new file mode 100644
index 000000000..3ec9be395
--- /dev/null
+++ b/packages/console/app/src/routes/workspace/[id]/billing/black-waitlist-section.tsx
@@ -0,0 +1,57 @@
+import { action, useParams, useAction, useSubmission, json, createAsync } from "@solidjs/router"
+import { createStore } from "solid-js/store"
+import { Database, eq } from "@opencode-ai/console-core/drizzle/index.js"
+import { BillingTable } from "@opencode-ai/console-core/schema/billing.sql.js"
+import { withActor } from "~/context/auth.withActor"
+import { queryBillingInfo } from "../../common"
+import styles from "./black-waitlist-section.module.css"
+
+const cancelWaitlist = action(async (workspaceID: string) => {
+ "use server"
+ return json(
+ await withActor(async () => {
+ await Database.use((tx) =>
+ tx
+ .update(BillingTable)
+ .set({
+ subscriptionPlan: null,
+ timeSubscriptionBooked: null,
+ })
+ .where(eq(BillingTable.workspaceID, workspaceID)),
+ )
+ return { error: undefined }
+ }, workspaceID).catch((e) => ({ error: e.message as string })),
+ { revalidate: queryBillingInfo.key },
+ )
+}, "cancelWaitlist")
+
+export function BlackWaitlistSection() {
+ const params = useParams()
+ const billingInfo = createAsync(() => queryBillingInfo(params.id!))
+ const cancelAction = useAction(cancelWaitlist)
+ const cancelSubmission = useSubmission(cancelWaitlist)
+ const [store, setStore] = createStore({
+ cancelled: false,
+ })
+
+ async function onClickCancel() {
+ const result = await cancelAction(params.id!)
+ if (!result.error) {
+ setStore("cancelled", true)
+ }
+ }
+
+ return (
+ <section class={styles.root}>
+ <div data-slot="section-title">
+ <h2>Waitlist</h2>
+ <div data-slot="title-row">
+ <p>You are on the waitlist for the ${billingInfo()?.subscriptionPlan} per month OpenCode Black plan.</p>
+ <button data-color="danger" disabled={cancelSubmission.pending || store.cancelled} onClick={onClickCancel}>
+ {cancelSubmission.pending ? "Leaving..." : store.cancelled ? "Left" : "Leave Waitlist"}
+ </button>
+ </div>
+ </div>
+ </section>
+ )
+}
diff --git a/packages/console/app/src/routes/workspace/[id]/billing/index.tsx b/packages/console/app/src/routes/workspace/[id]/billing/index.tsx
index a252a0234..7fe4092be 100644
--- a/packages/console/app/src/routes/workspace/[id]/billing/index.tsx
+++ b/packages/console/app/src/routes/workspace/[id]/billing/index.tsx
@@ -3,6 +3,7 @@ import { BillingSection } from "./billing-section"
import { ReloadSection } from "./reload-section"
import { PaymentSection } from "./payment-section"
import { BlackSection } from "./black-section"
+import { BlackWaitlistSection } from "./black-waitlist-section"
import { Show } from "solid-js"
import { createAsync, useParams } from "@solidjs/router"
import { queryBillingInfo, querySessionInfo } from "../../common"
@@ -16,9 +17,12 @@ export default function () {
<div data-page="workspace-[id]">
<div data-slot="sections">
<Show when={sessionInfo()?.isAdmin}>
- <Show when={billingInfo()?.subscriptionID || billingInfo()?.timeSubscriptionBooked}>
+ <Show when={billingInfo()?.subscriptionID}>
<BlackSection />
</Show>
+ <Show when={billingInfo()?.timeSubscriptionBooked}>
+ <BlackWaitlistSection />
+ </Show>
<BillingSection />
<Show when={billingInfo()?.customerID}>
<ReloadSection />