import { A, createAsync, query, redirect, useSearchParams } from "@solidjs/router" import { Title } from "@solidjs/meta" import { createEffect, createSignal, For, onMount, Show } from "solid-js" import { loadStripe } from "@stripe/stripe-js" import { Elements, PaymentElement, useStripe, useElements } from "solid-stripe" import { config } from "~/config" import { PlanIcon, plans } from "./common" import { getActor } from "~/context/auth" import { withActor } from "~/context/auth.withActor" import { Actor } from "@opencode-ai/console-core/actor.js" import { and, Database, eq, isNull } from "@opencode-ai/console-core/drizzle/index.js" import { WorkspaceTable } from "@opencode-ai/console-core/schema/workspace.sql.js" import { UserTable } from "@opencode-ai/console-core/schema/user.sql.js" import { createList } from "solid-list" import { Modal } from "~/component/modal" const plansMap = Object.fromEntries(plans.map((p) => [p.id, p])) as Record const getWorkspaces = query(async () => { "use server" const actor = await getActor() if (actor.type === "public") throw redirect("/auth/authorize?continue=/black/subscribe") return withActor(async () => { return Database.use((tx) => tx .select({ id: WorkspaceTable.id, name: WorkspaceTable.name, slug: WorkspaceTable.slug, }) .from(UserTable) .innerJoin(WorkspaceTable, eq(UserTable.workspaceID, WorkspaceTable.id)) .where( and( eq(UserTable.accountID, Actor.account()), isNull(WorkspaceTable.timeDeleted), isNull(UserTable.timeDeleted), ), ), ) }) }, "black.subscribe.workspaces") function CheckoutForm(props: { plan: string; amount: number }) { const stripe = useStripe() const elements = useElements() const [error, setError] = createSignal(null) const [loading, setLoading] = createSignal(false) const handleSubmit = async (e: Event) => { e.preventDefault() if (!stripe() || !elements()) return setLoading(true) setError(null) const result = await elements()!.submit() if (result.error) { setError(result.error.message ?? "An error occurred") setLoading(false) return } const { error: confirmError } = await stripe()!.confirmSetup({ elements: elements()!, confirmParams: { return_url: `${window.location.origin}/black/success?plan=${props.plan}`, }, }) if (confirmError) { setError(confirmError.message ?? "An error occurred") } setLoading(false) } return (

{error()}

You will only be charged when your subscription is activated

) } export default function BlackSubscribe() { const workspaces = createAsync(() => getWorkspaces()) const [selectedWorkspace, setSelectedWorkspace] = createSignal(null) const [params] = useSearchParams() const plan = (params.plan as string) || "200" const planData = plansMap[plan] || plansMap["200"] const [clientSecret, setClientSecret] = createSignal(null) const [stripePromise] = createSignal(loadStripe(config.stripe.publishableKey)) // Auto-select if only one workspace createEffect(() => { const ws = workspaces() if (ws?.length === 1 && !selectedWorkspace()) { setSelectedWorkspace(ws[0].id) } }) // Keyboard navigation for workspace picker const { active, setActive, onKeyDown } = createList({ items: () => workspaces()?.map((w) => w.id) ?? [], initialActive: null, }) const handleSelectWorkspace = (id: string) => { setSelectedWorkspace(id) } onMount(async () => { const response = await fetch("/api/black/setup-intent", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ plan }), }) const data = await response.json() if (data.clientSecret) { setClientSecret(data.clientSecret) } }) let listRef: HTMLUListElement | undefined // Show workspace picker if multiple workspaces and none selected const showWorkspacePicker = () => { const ws = workspaces() return ws && ws.length > 1 && !selectedWorkspace() } return ( <> Subscribe to OpenCode Black

Subscribe to OpenCode Black

${planData.amount} per month {planData.multiplier}

Add payment method

Loading payment form...

} >
{/* Workspace picker modal */} {}} title="Select a workspace for this plan">
    { if (e.key === "Enter" && active()) { handleSelectWorkspace(active()!) } else { onKeyDown(e) } }} > {(workspace) => (
  • setActive(workspace.id)} onClick={() => handleSelectWorkspace(workspace.id)} > [*] {workspace.name || workspace.slug}
  • )}

Prices shown don't include applicable tax ยท Terms of Service

) }