import { action, json, query, useAction, useSubmission } from "@solidjs/router" import { createEffect, createMemo, createSignal, For, onCleanup, Show } from "solid-js" import { getRequestEvent } from "solid-js/web" import { Referral } from "@opencode-ai/console-core/referral.js" import { withActor } from "~/context/auth.withActor" import { Modal } from "~/component/modal" import { IconCheck, IconCopy } from "~/component/icon" import { useI18n } from "~/context/i18n" import { useLanguage } from "~/context/language" import { formatResetTime, liteResetTimeKeys } from "~/lib/format-reset-time" import { queryLiteSubscription } from "~/routes/workspace/[id]/go/lite-section" import { createReferralFromCookie } from "~/lib/referral-invite" import "./go-referral.css" type GoReferralSummary = Awaited> type GoReferralReward = GoReferralSummary["rewards"][number] type GoLiteSubscription = Awaited> type GoReferralUsagePreview = NonNullable>> type GoReferralUsagePreviewItem = GoReferralUsagePreview["rollingUsage"] const emptyUsagePreview = { rollingUsage: { beforePercent: 0, afterPercent: 0, resetInSec: 0 }, weeklyUsage: { beforePercent: 0, afterPercent: 0, resetInSec: 0 }, monthlyUsage: { beforePercent: 0, afterPercent: 0, resetInSec: 0 }, } satisfies GoReferralUsagePreview export const queryGoReferral = query(async (workspaceID: string) => { "use server" return withActor(async () => { await createReferralFromCookie() return Referral.summary() }, workspaceID) }, "go.referral.get") export const queryGoReferralUsagePreview = query(async (workspaceID: string, referralID?: string) => { "use server" if (!referralID) return null return withActor(() => Referral.usagePreview({ referralID }), workspaceID) }, "go.referral.usagePreview") export const applyGoReferralReward = action(async (workspaceID: string, referralID: string) => { "use server" return json(await withActor(() => Referral.applyReward({ referralID }), workspaceID), { revalidate: [queryGoReferral.key, queryGoReferralUsagePreview.key, queryLiteSubscription.key], }) }, "go.referral.reward.apply") function currentUsagePreview(usage: { resetInSec: number; usagePercent: number }) { return { beforePercent: usage.usagePercent, afterPercent: usage.usagePercent, resetInSec: usage.resetInSec, } } function formatCurrency(amount: number) { if (amount % 100 === 0) return `$${amount / 100}` return `$${(amount / 100).toFixed(2)}` } function formatDate(value: string | Date, locale: string) { return new Intl.DateTimeFormat(locale, { month: "short", day: "numeric", year: "numeric" }).format(new Date(value)) } function rewardDescriptionKey(source: GoReferralReward["source"]) { if (source === "invitee") return "workspace.referral.reward.description.invitee" as const return "workspace.referral.reward.description.inviter" as const } function rewardActionKey(reward: GoReferralReward, hasActiveGo: boolean) { if (reward.status === "applied") return "workspace.referral.reward.action.applied" as const if (reward.status === "pending" && reward.source === "inviter") return "workspace.referral.reward.source.pendingInviter" as const if (reward.status === "pending" || !hasActiveGo) return "workspace.referral.reward.action.subscribeUnlock" as const return "workspace.referral.reward.action.view" as const } function CopyInviteLink(props: { summary: GoReferralSummary }) { const i18n = useI18n() const [copied, setCopied] = createSignal(false) const event = getRequestEvent() const origin = event ? new URL(event.request.url).origin : typeof window === "object" ? window.location.origin : undefined const inviteUrl = createMemo(() => { const path = `/go?ref=${props.summary.referralCode}` if (!origin) return path return new URL(path, origin).toString() }) async function copy() { if (typeof navigator !== "object") return await navigator.clipboard.writeText(inviteUrl()) setCopied(true) window.setTimeout(() => setCopied(false), 1600) } return (
{inviteUrl()}
) } export function GoReferralSection(props: { workspaceID: string summary: GoReferralSummary lite: GoLiteSubscription | undefined }) { const i18n = useI18n() const language = useLanguage() const apply = useAction(applyGoReferralReward) const submission = useSubmission(applyGoReferralReward) const [selected, setSelected] = createSignal() const [preview, setPreview] = createSignal() const displayPreview = createMemo(() => { const loaded = preview() if (loaded) return loaded const current = props.lite if (!current) return emptyUsagePreview return { rollingUsage: currentUsagePreview(current.rollingUsage), weeklyUsage: currentUsagePreview(current.weeklyUsage), monthlyUsage: currentUsagePreview(current.monthlyUsage), } satisfies GoReferralUsagePreview }) createEffect(() => { const reward = selected() if (!reward) { setPreview(undefined) return } const request = { cancelled: false } setPreview(undefined) queryGoReferralUsagePreview(props.workspaceID, reward.id).then((result) => { if (request.cancelled) return setPreview(result) }) onCleanup(() => { request.cancelled = true }) }) async function onApply() { const reward = selected() if (!reward) return await apply(props.workspaceID, reward.id) setSelected(undefined) } return ( <>

{i18n.t("workspace.referral.overview.title")}

{i18n.t("workspace.referral.overview.subtitle")}

  1. {i18n.t("workspace.referral.instructions.share")}
  2. {i18n.t("workspace.referral.instructions.subscribe")}
  3. {i18n.t("workspace.referral.instructions.claim")}

{i18n.t("workspace.referral.rewards.title")}

{i18n.t("workspace.referral.rewards.description")}

{(reward) => { const earnedAt = () => formatDate(reward.timeCreated, language.tag(language.locale())) return ( ) }}
{i18n.t("workspace.referral.table.reward")} {i18n.t("workspace.referral.table.referral")} {i18n.t("workspace.referral.table.date")}
{formatCurrency(reward.amount)} {i18n.t(rewardDescriptionKey(reward.source), { email: reward.email ?? "" })} {earnedAt()}
setSelected(undefined)} title={i18n.t("workspace.referral.apply.confirmTitle")} >

{i18n.t("workspace.referral.apply.confirmBody", { amount: formatCurrency(selected()?.amount ?? 0), })}

) } function GoReferralUsagePreview(props: { preview: GoReferralUsagePreview }) { const i18n = useI18n() return (
) } function GoReferralUsagePreviewRow(props: { label: string; usage: GoReferralUsagePreviewItem }) { const i18n = useI18n() return (
{props.label} {props.usage.beforePercent}% {props.usage.afterPercent}%
{i18n.t("workspace.lite.subscription.resetsIn")}{" "} {formatResetTime(props.usage.resetInSec, i18n, liteResetTimeKeys)}
) }