From 75cae81f75ad3058fbace67e0674aef30b9021c7 Mon Sep 17 00:00:00 2001 From: Frank Date: Wed, 11 Mar 2026 03:12:11 -0400 Subject: zen: add Go page --- packages/console/app/src/i18n/ar.ts | 7 +- packages/console/app/src/i18n/br.ts | 7 +- packages/console/app/src/i18n/da.ts | 7 +- packages/console/app/src/i18n/de.ts | 7 +- packages/console/app/src/i18n/en.ts | 7 +- packages/console/app/src/i18n/es.ts | 7 +- packages/console/app/src/i18n/fr.ts | 7 +- packages/console/app/src/i18n/it.ts | 7 +- packages/console/app/src/i18n/ja.ts | 7 +- packages/console/app/src/i18n/ko.ts | 7 +- packages/console/app/src/i18n/no.ts | 7 +- packages/console/app/src/i18n/pl.ts | 7 +- packages/console/app/src/i18n/ru.ts | 7 +- packages/console/app/src/i18n/th.ts | 7 +- packages/console/app/src/i18n/tr.ts | 7 +- packages/console/app/src/i18n/zh.ts | 7 +- packages/console/app/src/i18n/zht.ts | 7 +- packages/console/app/src/routes/go/index.tsx | 2 +- packages/console/app/src/routes/workspace/[id].tsx | 6 + .../src/routes/workspace/[id]/billing/index.tsx | 4 - .../workspace/[id]/billing/lite-section.module.css | 190 ------------- .../routes/workspace/[id]/billing/lite-section.tsx | 286 -------------------- .../app/src/routes/workspace/[id]/go/index.tsx | 11 + .../workspace/[id]/go/lite-section.module.css | 190 +++++++++++++ .../src/routes/workspace/[id]/go/lite-section.tsx | 296 +++++++++++++++++++++ 25 files changed, 572 insertions(+), 532 deletions(-) delete mode 100644 packages/console/app/src/routes/workspace/[id]/billing/lite-section.module.css delete mode 100644 packages/console/app/src/routes/workspace/[id]/billing/lite-section.tsx create mode 100644 packages/console/app/src/routes/workspace/[id]/go/index.tsx create mode 100644 packages/console/app/src/routes/workspace/[id]/go/lite-section.module.css create mode 100644 packages/console/app/src/routes/workspace/[id]/go/lite-section.tsx (limited to 'packages/console/app') diff --git a/packages/console/app/src/i18n/ar.ts b/packages/console/app/src/i18n/ar.ts index a17530920..5a03eea09 100644 --- a/packages/console/app/src/i18n/ar.ts +++ b/packages/console/app/src/i18n/ar.ts @@ -411,6 +411,7 @@ export const dict = { "black.subscribe.success.chargeNotice": "سيتم خصم المبلغ من بطاقتك عند تفعيل اشتراكك", "workspace.nav.zen": "Zen", + "workspace.nav.go": "Go", "workspace.nav.usage": "الاستخدام", "workspace.nav.apiKeys": "مفاتيح API", "workspace.nav.members": "الأعضاء", @@ -617,7 +618,7 @@ export const dict = { "workspace.lite.time.minute": "دقيقة", "workspace.lite.time.minutes": "دقائق", "workspace.lite.time.fewSeconds": "بضع ثوان", - "workspace.lite.subscription.title": "اشتراك Go", + "workspace.lite.title": "OpenCode Go", "workspace.lite.subscription.message": "أنت مشترك في OpenCode Go.", "workspace.lite.subscription.manage": "إدارة الاشتراك", "workspace.lite.subscription.rollingUsage": "الاستخدام المتجدد", @@ -627,10 +628,10 @@ export const dict = { "workspace.lite.subscription.useBalance": "استخدم رصيدك المتوفر بعد الوصول إلى حدود الاستخدام", "workspace.lite.subscription.selectProvider": 'اختر "OpenCode Go" كمزود في إعدادات opencode الخاصة بك لاستخدام نماذج Go.', - "workspace.lite.other.title": "اشتراك Go", + "workspace.lite.black.message": + 'أنت مشترك حاليًا في OpenCode Black أو في قائمة الانتظار. يرجى إلغاء الاشتراك أولاً إذا كنت ترغب في التبديل إلى Go.', "workspace.lite.other.message": "عضو آخر في مساحة العمل هذه مشترك بالفعل في OpenCode Go. يمكن لعضو واحد فقط لكل مساحة عمل الاشتراك.", - "workspace.lite.promo.title": "OpenCode Go", "workspace.lite.promo.description": "OpenCode Go هو اشتراك بسعر $10 شهريًا يوفر وصولاً موثوقًا إلى نماذج البرمجة المفتوحة الشائعة مع حدود استخدام سخية.", "workspace.lite.promo.modelsTitle": "ما يتضمنه", diff --git a/packages/console/app/src/i18n/br.ts b/packages/console/app/src/i18n/br.ts index f395db9f4..da79d2e66 100644 --- a/packages/console/app/src/i18n/br.ts +++ b/packages/console/app/src/i18n/br.ts @@ -418,6 +418,7 @@ export const dict = { "black.subscribe.success.chargeNotice": "Seu cartão será cobrado quando sua assinatura for ativada", "workspace.nav.zen": "Zen", + "workspace.nav.go": "Go", "workspace.nav.usage": "Uso", "workspace.nav.apiKeys": "Chaves de API", "workspace.nav.members": "Membros", @@ -626,7 +627,7 @@ export const dict = { "workspace.lite.time.minute": "minuto", "workspace.lite.time.minutes": "minutos", "workspace.lite.time.fewSeconds": "alguns segundos", - "workspace.lite.subscription.title": "Assinatura Go", + "workspace.lite.title": "OpenCode Go", "workspace.lite.subscription.message": "Você assina o OpenCode Go.", "workspace.lite.subscription.manage": "Gerenciar Assinatura", "workspace.lite.subscription.rollingUsage": "Uso Contínuo", @@ -636,10 +637,10 @@ export const dict = { "workspace.lite.subscription.useBalance": "Use seu saldo disponível após atingir os limites de uso", "workspace.lite.subscription.selectProvider": 'Selecione "OpenCode Go" como provedor na sua configuração do opencode para usar os modelos Go.', - "workspace.lite.other.title": "Assinatura Go", + "workspace.lite.black.message": + 'Você está atualmente inscrito no OpenCode Black ou na lista de espera. Por favor, cancele a assinatura primeiro se desejar mudar para o Go.', "workspace.lite.other.message": "Outro membro neste workspace já assina o OpenCode Go. Apenas um membro por workspace pode assinar.", - "workspace.lite.promo.title": "OpenCode Go", "workspace.lite.promo.description": "O OpenCode Go é uma assinatura de $10 por mês que fornece acesso confiável a modelos abertos de codificação populares com limites de uso generosos.", "workspace.lite.promo.modelsTitle": "O que está incluído", diff --git a/packages/console/app/src/i18n/da.ts b/packages/console/app/src/i18n/da.ts index 6e2af12af..5fa9e2b8c 100644 --- a/packages/console/app/src/i18n/da.ts +++ b/packages/console/app/src/i18n/da.ts @@ -414,6 +414,7 @@ export const dict = { "black.subscribe.success.chargeNotice": "Dit kort vil blive debiteret, når dit abonnement er aktiveret", "workspace.nav.zen": "Zen", + "workspace.nav.go": "Go", "workspace.nav.usage": "Brug", "workspace.nav.apiKeys": "API-nøgler", "workspace.nav.members": "Medlemmer", @@ -622,7 +623,7 @@ export const dict = { "workspace.lite.time.minute": "minut", "workspace.lite.time.minutes": "minutter", "workspace.lite.time.fewSeconds": "et par sekunder", - "workspace.lite.subscription.title": "Go-abonnement", + "workspace.lite.title": "OpenCode Go", "workspace.lite.subscription.message": "Du abonnerer på OpenCode Go.", "workspace.lite.subscription.manage": "Administrer abonnement", "workspace.lite.subscription.rollingUsage": "Løbende forbrug", @@ -632,10 +633,10 @@ export const dict = { "workspace.lite.subscription.useBalance": "Brug din tilgængelige saldo, når du har nået forbrugsgrænserne", "workspace.lite.subscription.selectProvider": 'Vælg "OpenCode Go" som udbyder i din opencode-konfiguration for at bruge Go-modeller.', - "workspace.lite.other.title": "Go-abonnement", + "workspace.lite.black.message": + 'Du abonnerer i øjeblikket på OpenCode Black eller er på venteliste. Afmeld venligst først, hvis du vil skifte til Go.', "workspace.lite.other.message": "Et andet medlem i dette workspace abonnerer allerede på OpenCode Go. Kun ét medlem pr. workspace kan abonnere.", - "workspace.lite.promo.title": "OpenCode Go", "workspace.lite.promo.description": "OpenCode Go er et abonnement til $10 om måneden, der giver pålidelig adgang til populære åbne kodningsmodeller med generøse forbrugsgrænser.", "workspace.lite.promo.modelsTitle": "Hvad er inkluderet", diff --git a/packages/console/app/src/i18n/de.ts b/packages/console/app/src/i18n/de.ts index 87094a28f..29bebc908 100644 --- a/packages/console/app/src/i18n/de.ts +++ b/packages/console/app/src/i18n/de.ts @@ -417,6 +417,7 @@ export const dict = { "black.subscribe.success.chargeNotice": "Deine Karte wird belastet, sobald dein Abonnement aktiviert ist", "workspace.nav.zen": "Zen", + "workspace.nav.go": "Go", "workspace.nav.usage": "Nutzung", "workspace.nav.apiKeys": "API Keys", "workspace.nav.members": "Mitglieder", @@ -625,7 +626,7 @@ export const dict = { "workspace.lite.time.minute": "Minute", "workspace.lite.time.minutes": "Minuten", "workspace.lite.time.fewSeconds": "einige Sekunden", - "workspace.lite.subscription.title": "Go-Abonnement", + "workspace.lite.title": "OpenCode Go", "workspace.lite.subscription.message": "Du hast OpenCode Go abonniert.", "workspace.lite.subscription.manage": "Abo verwalten", "workspace.lite.subscription.rollingUsage": "Fortlaufende Nutzung", @@ -635,10 +636,10 @@ export const dict = { "workspace.lite.subscription.useBalance": "Nutze dein verfügbares Guthaben, nachdem die Nutzungslimits erreicht sind", "workspace.lite.subscription.selectProvider": 'Wähle "OpenCode Go" als Anbieter in deiner opencode-Konfiguration, um Go-Modelle zu verwenden.', - "workspace.lite.other.title": "Go-Abonnement", + "workspace.lite.black.message": + 'Du hast derzeit OpenCode Black abonniert oder stehst auf der Warteliste. Bitte kündige zuerst, wenn du zu Go wechseln möchtest.', "workspace.lite.other.message": "Ein anderes Mitglied in diesem Workspace hat OpenCode Go bereits abonniert. Nur ein Mitglied pro Workspace kann abonnieren.", - "workspace.lite.promo.title": "OpenCode Go", "workspace.lite.promo.description": "OpenCode Go ist ein Abonnement für $10 pro Monat, das zuverlässigen Zugriff auf beliebte offene Coding-Modelle mit großzügigen Nutzungslimits bietet.", "workspace.lite.promo.modelsTitle": "Was enthalten ist", diff --git a/packages/console/app/src/i18n/en.ts b/packages/console/app/src/i18n/en.ts index 1f1773dd4..dca14bb87 100644 --- a/packages/console/app/src/i18n/en.ts +++ b/packages/console/app/src/i18n/en.ts @@ -411,6 +411,7 @@ export const dict = { "black.subscribe.success.chargeNotice": "Your card will be charged when your subscription is activated", "workspace.nav.zen": "Zen", + "workspace.nav.go": "Go", "workspace.nav.usage": "Usage", "workspace.nav.apiKeys": "API Keys", "workspace.nav.members": "Members", @@ -619,7 +620,7 @@ export const dict = { "workspace.lite.time.minute": "minute", "workspace.lite.time.minutes": "minutes", "workspace.lite.time.fewSeconds": "a few seconds", - "workspace.lite.subscription.title": "Go Subscription", + "workspace.lite.title": "OpenCode Go", "workspace.lite.subscription.message": "You are subscribed to OpenCode Go.", "workspace.lite.subscription.manage": "Manage Subscription", "workspace.lite.subscription.rollingUsage": "Rolling Usage", @@ -629,10 +630,10 @@ export const dict = { "workspace.lite.subscription.useBalance": "Use your available balance after reaching the usage limits", "workspace.lite.subscription.selectProvider": 'Select "OpenCode Go" as the provider in your opencode configuration to use Go models.', - "workspace.lite.other.title": "Go Subscription", + "workspace.lite.black.message": + "You're currently subscribed to OpenCode Black or on the waitlist. Please unsubscribe first if you'd like to switch to Go.", "workspace.lite.other.message": "Another member in this workspace is already subscribed to OpenCode Go. Only one member per workspace can subscribe.", - "workspace.lite.promo.title": "OpenCode Go", "workspace.lite.promo.description": "OpenCode Go is a $10 per month subscription that provides reliable access to popular open coding models with generous usage limits.", "workspace.lite.promo.modelsTitle": "What's Included", diff --git a/packages/console/app/src/i18n/es.ts b/packages/console/app/src/i18n/es.ts index 19a9842d5..f1a95b2be 100644 --- a/packages/console/app/src/i18n/es.ts +++ b/packages/console/app/src/i18n/es.ts @@ -419,6 +419,7 @@ export const dict = { "black.subscribe.success.chargeNotice": "Tu tarjeta se cargará cuando tu suscripción se active", "workspace.nav.zen": "Zen", + "workspace.nav.go": "Go", "workspace.nav.usage": "Uso", "workspace.nav.apiKeys": "Claves API", "workspace.nav.members": "Miembros", @@ -627,7 +628,7 @@ export const dict = { "workspace.lite.time.minute": "minuto", "workspace.lite.time.minutes": "minutos", "workspace.lite.time.fewSeconds": "unos pocos segundos", - "workspace.lite.subscription.title": "Suscripción Go", + "workspace.lite.title": "OpenCode Go", "workspace.lite.subscription.message": "Estás suscrito a OpenCode Go.", "workspace.lite.subscription.manage": "Gestionar Suscripción", "workspace.lite.subscription.rollingUsage": "Uso Continuo", @@ -637,10 +638,10 @@ export const dict = { "workspace.lite.subscription.useBalance": "Usa tu saldo disponible después de alcanzar los límites de uso", "workspace.lite.subscription.selectProvider": 'Selecciona "OpenCode Go" como proveedor en tu configuración de opencode para usar los modelos Go.', - "workspace.lite.other.title": "Suscripción Go", + "workspace.lite.black.message": + 'Actualmente estás suscrito a OpenCode Black o estás en la lista de espera. Por favor, cancela la suscripción primero si deseas cambiar a Go.', "workspace.lite.other.message": "Otro miembro de este espacio de trabajo ya está suscrito a OpenCode Go. Solo un miembro por espacio de trabajo puede suscribirse.", - "workspace.lite.promo.title": "OpenCode Go", "workspace.lite.promo.description": "OpenCode Go es una suscripción de $10 al mes que proporciona acceso confiable a modelos de codificación abiertos populares con generosos límites de uso.", "workspace.lite.promo.modelsTitle": "Qué incluye", diff --git a/packages/console/app/src/i18n/fr.ts b/packages/console/app/src/i18n/fr.ts index cf6d5e95b..7e2ff66db 100644 --- a/packages/console/app/src/i18n/fr.ts +++ b/packages/console/app/src/i18n/fr.ts @@ -419,6 +419,7 @@ export const dict = { "black.subscribe.success.chargeNotice": "Votre carte sera débitée lorsque votre abonnement sera activé", "workspace.nav.zen": "Zen", + "workspace.nav.go": "Go", "workspace.nav.usage": "Utilisation", "workspace.nav.apiKeys": "Clés API", "workspace.nav.members": "Membres", @@ -631,7 +632,7 @@ export const dict = { "workspace.lite.time.minute": "minute", "workspace.lite.time.minutes": "minutes", "workspace.lite.time.fewSeconds": "quelques secondes", - "workspace.lite.subscription.title": "Abonnement Go", + "workspace.lite.title": "OpenCode Go", "workspace.lite.subscription.message": "Vous êtes abonné à OpenCode Go.", "workspace.lite.subscription.manage": "Gérer l'abonnement", "workspace.lite.subscription.rollingUsage": "Utilisation glissante", @@ -642,10 +643,10 @@ export const dict = { "Utilisez votre solde disponible après avoir atteint les limites d'utilisation", "workspace.lite.subscription.selectProvider": 'Sélectionnez "OpenCode Go" comme fournisseur dans votre configuration opencode pour utiliser les modèles Go.', - "workspace.lite.other.title": "Abonnement Go", + "workspace.lite.black.message": + "Vous êtes actuellement abonné à OpenCode Black ou sur liste d'attente. Veuillez d'abord vous désabonner si vous souhaitez passer à Go.", "workspace.lite.other.message": "Un autre membre de cet espace de travail est déjà abonné à OpenCode Go. Un seul membre par espace de travail peut s'abonner.", - "workspace.lite.promo.title": "OpenCode Go", "workspace.lite.promo.description": "OpenCode Go est un abonnement à 10 $ par mois qui offre un accès fiable aux modèles de codage ouverts populaires avec des limites d'utilisation généreuses.", "workspace.lite.promo.modelsTitle": "Ce qui est inclus", diff --git a/packages/console/app/src/i18n/it.ts b/packages/console/app/src/i18n/it.ts index b967f078c..c579a4863 100644 --- a/packages/console/app/src/i18n/it.ts +++ b/packages/console/app/src/i18n/it.ts @@ -417,6 +417,7 @@ export const dict = { "black.subscribe.success.chargeNotice": "La tua carta verrà addebitata quando il tuo abbonamento sarà attivato", "workspace.nav.zen": "Zen", + "workspace.nav.go": "Go", "workspace.nav.usage": "Utilizzo", "workspace.nav.apiKeys": "Chiavi API", "workspace.nav.members": "Membri", @@ -625,7 +626,7 @@ export const dict = { "workspace.lite.time.minute": "minuto", "workspace.lite.time.minutes": "minuti", "workspace.lite.time.fewSeconds": "pochi secondi", - "workspace.lite.subscription.title": "Abbonamento Go", + "workspace.lite.title": "OpenCode Go", "workspace.lite.subscription.message": "Sei abbonato a OpenCode Go.", "workspace.lite.subscription.manage": "Gestisci Abbonamento", "workspace.lite.subscription.rollingUsage": "Utilizzo Continuativo", @@ -635,10 +636,10 @@ export const dict = { "workspace.lite.subscription.useBalance": "Usa il tuo saldo disponibile dopo aver raggiunto i limiti di utilizzo", "workspace.lite.subscription.selectProvider": 'Seleziona "OpenCode Go" come provider nella tua configurazione opencode per utilizzare i modelli Go.', - "workspace.lite.other.title": "Abbonamento Go", + "workspace.lite.black.message": + "Attualmente sei abbonato a OpenCode Black o sei in lista d'attesa. Annulla l'iscrizione prima se desideri passare a Go.", "workspace.lite.other.message": "Un altro membro in questo workspace è già abbonato a OpenCode Go. Solo un membro per workspace può abbonarsi.", - "workspace.lite.promo.title": "OpenCode Go", "workspace.lite.promo.description": "OpenCode Go è un abbonamento a $10 al mese che fornisce un accesso affidabile a popolari modelli di coding aperti con generosi limiti di utilizzo.", "workspace.lite.promo.modelsTitle": "Cosa è incluso", diff --git a/packages/console/app/src/i18n/ja.ts b/packages/console/app/src/i18n/ja.ts index 759d5e7c7..020f68005 100644 --- a/packages/console/app/src/i18n/ja.ts +++ b/packages/console/app/src/i18n/ja.ts @@ -416,6 +416,7 @@ export const dict = { "black.subscribe.success.chargeNotice": "サブスクリプションが有効化された時点でカードに請求されます", "workspace.nav.zen": "Zen", + "workspace.nav.go": "Go", "workspace.nav.usage": "利用", "workspace.nav.apiKeys": "APIキー", "workspace.nav.members": "メンバー", @@ -625,7 +626,7 @@ export const dict = { "workspace.lite.time.minute": "分", "workspace.lite.time.minutes": "分", "workspace.lite.time.fewSeconds": "数秒", - "workspace.lite.subscription.title": "Goサブスクリプション", + "workspace.lite.title": "OpenCode Go", "workspace.lite.subscription.message": "あなたは OpenCode Go を購読しています。", "workspace.lite.subscription.manage": "サブスクリプションの管理", "workspace.lite.subscription.rollingUsage": "ローリング利用量", @@ -635,10 +636,10 @@ export const dict = { "workspace.lite.subscription.useBalance": "利用限度額に達したら利用可能な残高を使用する", "workspace.lite.subscription.selectProvider": "Go モデルを使用するには、opencode の設定で「OpenCode Go」をプロバイダーとして選択してください。", - "workspace.lite.other.title": "Goサブスクリプション", + "workspace.lite.black.message": + '現在 OpenCode Black を購読中、またはウェイティングリストに登録されています。Go に切り替える場合は、先に登録を解除してください。', "workspace.lite.other.message": "このワークスペースの別のメンバーが既に OpenCode Go を購読しています。ワークスペースにつき1人のメンバーのみが購読できます。", - "workspace.lite.promo.title": "OpenCode Go", "workspace.lite.promo.description": "OpenCode Goは月額$10のサブスクリプションプランで、人気のオープンコーディングモデルへの安定したアクセスを十分な利用枠で提供します。", "workspace.lite.promo.modelsTitle": "含まれるもの", diff --git a/packages/console/app/src/i18n/ko.ts b/packages/console/app/src/i18n/ko.ts index 9a5237f33..b5c6efc44 100644 --- a/packages/console/app/src/i18n/ko.ts +++ b/packages/console/app/src/i18n/ko.ts @@ -410,6 +410,7 @@ export const dict = { "black.subscribe.success.chargeNotice": "구독이 활성화되면 카드에 청구됩니다", "workspace.nav.zen": "Zen", + "workspace.nav.go": "Go", "workspace.nav.usage": "사용량", "workspace.nav.apiKeys": "API 키", "workspace.nav.members": "멤버", @@ -617,7 +618,7 @@ export const dict = { "workspace.lite.time.minute": "분", "workspace.lite.time.minutes": "분", "workspace.lite.time.fewSeconds": "몇 초", - "workspace.lite.subscription.title": "Go 구독", + "workspace.lite.title": "OpenCode Go", "workspace.lite.subscription.message": "현재 OpenCode Go를 구독 중입니다.", "workspace.lite.subscription.manage": "구독 관리", "workspace.lite.subscription.rollingUsage": "롤링 사용량", @@ -627,10 +628,10 @@ export const dict = { "workspace.lite.subscription.useBalance": "사용 한도 도달 후에는 보유 잔액 사용", "workspace.lite.subscription.selectProvider": 'Go 모델을 사용하려면 opencode 설정에서 "OpenCode Go"를 공급자로 선택하세요.', - "workspace.lite.other.title": "Go 구독", + "workspace.lite.black.message": + '현재 OpenCode Black을 구독 중이거나 대기 명단에 등록되어 있습니다. Go로 전환하려면 먼저 구독을 취소해 주세요.', "workspace.lite.other.message": "이 워크스페이스의 다른 멤버가 이미 OpenCode Go를 구독 중입니다. 워크스페이스당 한 명의 멤버만 구독할 수 있습니다.", - "workspace.lite.promo.title": "OpenCode Go", "workspace.lite.promo.description": "OpenCode Go는 넉넉한 사용 한도와 함께 인기 있는 오픈 코딩 모델에 대한 안정적인 액세스를 제공하는 월 $10의 구독입니다.", "workspace.lite.promo.modelsTitle": "포함 내역", diff --git a/packages/console/app/src/i18n/no.ts b/packages/console/app/src/i18n/no.ts index fa44e535e..31dc8ee10 100644 --- a/packages/console/app/src/i18n/no.ts +++ b/packages/console/app/src/i18n/no.ts @@ -415,6 +415,7 @@ export const dict = { "black.subscribe.success.chargeNotice": "Kortet ditt vil bli belastet når abonnementet aktiveres", "workspace.nav.zen": "Zen", + "workspace.nav.go": "Go", "workspace.nav.usage": "Bruk", "workspace.nav.apiKeys": "API-nøkler", "workspace.nav.members": "Medlemmer", @@ -623,7 +624,7 @@ export const dict = { "workspace.lite.time.minute": "minutt", "workspace.lite.time.minutes": "minutter", "workspace.lite.time.fewSeconds": "noen få sekunder", - "workspace.lite.subscription.title": "Go-abonnement", + "workspace.lite.title": "OpenCode Go", "workspace.lite.subscription.message": "Du abonnerer på OpenCode Go.", "workspace.lite.subscription.manage": "Administrer abonnement", "workspace.lite.subscription.rollingUsage": "Løpende bruk", @@ -633,10 +634,10 @@ export const dict = { "workspace.lite.subscription.useBalance": "Bruk din tilgjengelige saldo etter å ha nådd bruksgrensene", "workspace.lite.subscription.selectProvider": 'Velg "OpenCode Go" som leverandør i opencode-konfigurasjonen din for å bruke Go-modeller.', - "workspace.lite.other.title": "Go-abonnement", + "workspace.lite.black.message": + 'Du abonnerer for øyeblikket på OpenCode Black eller står på venteliste. Vennligst avslutt abonnementet først hvis du vil bytte til Go.', "workspace.lite.other.message": "Et annet medlem i dette arbeidsområdet abonnerer allerede på OpenCode Go. Kun ett medlem per arbeidsområde kan abonnere.", - "workspace.lite.promo.title": "OpenCode Go", "workspace.lite.promo.description": "OpenCode Go er et abonnement til $10 per måned som gir pålitelig tilgang til populære åpne kodemodeller med rause bruksgrenser.", "workspace.lite.promo.modelsTitle": "Hva som er inkludert", diff --git a/packages/console/app/src/i18n/pl.ts b/packages/console/app/src/i18n/pl.ts index 7c7300ab9..dde32158a 100644 --- a/packages/console/app/src/i18n/pl.ts +++ b/packages/console/app/src/i18n/pl.ts @@ -416,6 +416,7 @@ export const dict = { "black.subscribe.success.chargeNotice": "Twoja karta zostanie obciążona po aktywacji subskrypcji", "workspace.nav.zen": "Zen", + "workspace.nav.go": "Go", "workspace.nav.usage": "Użycie", "workspace.nav.apiKeys": "Klucze API", "workspace.nav.members": "Członkowie", @@ -624,7 +625,7 @@ export const dict = { "workspace.lite.time.minute": "minuta", "workspace.lite.time.minutes": "minut(y)", "workspace.lite.time.fewSeconds": "kilka sekund", - "workspace.lite.subscription.title": "Subskrypcja Go", + "workspace.lite.title": "OpenCode Go", "workspace.lite.subscription.message": "Subskrybujesz OpenCode Go.", "workspace.lite.subscription.manage": "Zarządzaj subskrypcją", "workspace.lite.subscription.rollingUsage": "Użycie kroczące", @@ -634,10 +635,10 @@ export const dict = { "workspace.lite.subscription.useBalance": "Użyj dostępnego salda po osiągnięciu limitów użycia", "workspace.lite.subscription.selectProvider": 'Wybierz "OpenCode Go" jako dostawcę w konfiguracji opencode, aby używać modeli Go.', - "workspace.lite.other.title": "Subskrypcja Go", + "workspace.lite.black.message": + 'Obecnie subskrybujesz OpenCode Black lub jesteś na liście oczekujących. Jeśli chcesz przejść na Go, najpierw anuluj subskrypcję.', "workspace.lite.other.message": "Inny członek tego obszaru roboczego już subskrybuje OpenCode Go. Tylko jeden członek na obszar roboczy może subskrybować.", - "workspace.lite.promo.title": "OpenCode Go", "workspace.lite.promo.description": "OpenCode Go to subskrypcja za $10 miesięcznie, która zapewnia niezawodny dostęp do popularnych otwartych modeli do kodowania z hojnymi limitami użycia.", "workspace.lite.promo.modelsTitle": "Co zawiera", diff --git a/packages/console/app/src/i18n/ru.ts b/packages/console/app/src/i18n/ru.ts index 77e36bc99..4a84e91cc 100644 --- a/packages/console/app/src/i18n/ru.ts +++ b/packages/console/app/src/i18n/ru.ts @@ -421,6 +421,7 @@ export const dict = { "black.subscribe.success.chargeNotice": "С вашей карты будет списана оплата при активации подписки", "workspace.nav.zen": "Zen", + "workspace.nav.go": "Go", "workspace.nav.usage": "Использование", "workspace.nav.apiKeys": "API Ключи", "workspace.nav.members": "Участники", @@ -630,7 +631,7 @@ export const dict = { "workspace.lite.time.minute": "минута", "workspace.lite.time.minutes": "минут", "workspace.lite.time.fewSeconds": "несколько секунд", - "workspace.lite.subscription.title": "Подписка Go", + "workspace.lite.title": "OpenCode Go", "workspace.lite.subscription.message": "Вы подписаны на OpenCode Go.", "workspace.lite.subscription.manage": "Управление подпиской", "workspace.lite.subscription.rollingUsage": "Скользящее использование", @@ -640,10 +641,10 @@ export const dict = { "workspace.lite.subscription.useBalance": "Использовать доступный баланс после достижения лимитов", "workspace.lite.subscription.selectProvider": 'Выберите "OpenCode Go" в качестве провайдера в настройках opencode для использования моделей Go.', - "workspace.lite.other.title": "Подписка Go", + "workspace.lite.black.message": + 'Вы подписаны на OpenCode Black или находитесь в списке ожидания. Пожалуйста, сначала отмените подписку, если хотите перейти на Go.', "workspace.lite.other.message": "Другой участник в этом рабочем пространстве уже подписан на OpenCode Go. Только один участник в рабочем пространстве может оформить подписку.", - "workspace.lite.promo.title": "OpenCode Go", "workspace.lite.promo.description": "OpenCode Go — это подписка за $10 в месяц, которая предоставляет надежный доступ к популярным открытым моделям для кодинга с щедрыми лимитами использования.", "workspace.lite.promo.modelsTitle": "Что включено", diff --git a/packages/console/app/src/i18n/th.ts b/packages/console/app/src/i18n/th.ts index 9d1e92fa8..aabfea257 100644 --- a/packages/console/app/src/i18n/th.ts +++ b/packages/console/app/src/i18n/th.ts @@ -413,6 +413,7 @@ export const dict = { "black.subscribe.success.chargeNotice": "บัตรของคุณจะถูกเรียกเก็บเงินเมื่อการสมัครสมาชิกของคุณถูกเปิดใช้งาน", "workspace.nav.zen": "Zen", + "workspace.nav.go": "Go", "workspace.nav.usage": "การใช้งาน", "workspace.nav.apiKeys": "API Keys", "workspace.nav.members": "สมาชิก", @@ -621,7 +622,7 @@ export const dict = { "workspace.lite.time.minute": "นาที", "workspace.lite.time.minutes": "นาที", "workspace.lite.time.fewSeconds": "ไม่กี่วินาที", - "workspace.lite.subscription.title": "การสมัครสมาชิก Go", + "workspace.lite.title": "OpenCode Go", "workspace.lite.subscription.message": "คุณได้สมัครสมาชิก OpenCode Go แล้ว", "workspace.lite.subscription.manage": "จัดการการสมัครสมาชิก", "workspace.lite.subscription.rollingUsage": "การใช้งานแบบหมุนเวียน", @@ -631,10 +632,10 @@ export const dict = { "workspace.lite.subscription.useBalance": "ใช้ยอดคงเหลือของคุณหลังจากถึงขีดจำกัดการใช้งาน", "workspace.lite.subscription.selectProvider": 'เลือก "OpenCode Go" เป็นผู้ให้บริการในการตั้งค่า opencode ของคุณเพื่อใช้โมเดล Go', - "workspace.lite.other.title": "การสมัครสมาชิก Go", + "workspace.lite.black.message": + 'ขณะนี้คุณสมัครสมาชิก OpenCode Black หรืออยู่ในรายการรอ โปรดยกเลิกการสมัครก่อนหากต้องการเปลี่ยนไปใช้ Go', "workspace.lite.other.message": "สมาชิกคนอื่นใน Workspace นี้ได้สมัคร OpenCode Go แล้ว สามารถสมัครได้เพียงหนึ่งคนต่อหนึ่ง Workspace เท่านั้น", - "workspace.lite.promo.title": "OpenCode Go", "workspace.lite.promo.description": "OpenCode Go เป็นการสมัครสมาชิกราคา 10 ดอลลาร์ต่อเดือน ที่ให้การเข้าถึงโมเดลโอเพนโค้ดดิงยอดนิยมได้อย่างเสถียร ด้วยขีดจำกัดการใช้งานที่ครอบคลุม", "workspace.lite.promo.modelsTitle": "สิ่งที่รวมอยู่ด้วย", diff --git a/packages/console/app/src/i18n/tr.ts b/packages/console/app/src/i18n/tr.ts index 84ad9a7e3..6d6e414d1 100644 --- a/packages/console/app/src/i18n/tr.ts +++ b/packages/console/app/src/i18n/tr.ts @@ -418,6 +418,7 @@ export const dict = { "black.subscribe.success.chargeNotice": "Aboneliğiniz aktive edildiğinde kartınızdan ödeme alınacaktır", "workspace.nav.zen": "Zen", + "workspace.nav.go": "Go", "workspace.nav.usage": "Kullanım", "workspace.nav.apiKeys": "API Anahtarları", "workspace.nav.members": "Üyeler", @@ -626,7 +627,7 @@ export const dict = { "workspace.lite.time.minute": "dakika", "workspace.lite.time.minutes": "dakika", "workspace.lite.time.fewSeconds": "birkaç saniye", - "workspace.lite.subscription.title": "Go Aboneliği", + "workspace.lite.title": "OpenCode Go", "workspace.lite.subscription.message": "OpenCode Go abonesisiniz.", "workspace.lite.subscription.manage": "Aboneliği Yönet", "workspace.lite.subscription.rollingUsage": "Devam Eden Kullanım", @@ -636,10 +637,10 @@ export const dict = { "workspace.lite.subscription.useBalance": "Kullanım limitlerine ulaştıktan sonra mevcut bakiyenizi kullanın", "workspace.lite.subscription.selectProvider": 'Go modellerini kullanmak için opencode yapılandırmanızda "OpenCode Go"\'yu sağlayıcı olarak seçin.', - "workspace.lite.other.title": "Go Aboneliği", + "workspace.lite.black.message": + "Şu anda OpenCode Black abonesisiniz veya bekleme listesindesiniz. Go'ya geçmek istiyorsanız lütfen önce aboneliğinizi iptal edin.", "workspace.lite.other.message": "Bu çalışma alanındaki başka bir üye zaten OpenCode Go abonesi. Çalışma alanı başına yalnızca bir üye abone olabilir.", - "workspace.lite.promo.title": "OpenCode Go", "workspace.lite.promo.description": "OpenCode Go, cömert kullanım limitleriyle popüler açık kodlama modellerine güvenilir erişim sağlayan aylık 10$'lık bir aboneliktir.", "workspace.lite.promo.modelsTitle": "Neler Dahil", diff --git a/packages/console/app/src/i18n/zh.ts b/packages/console/app/src/i18n/zh.ts index a3527ae3e..ccb3a554d 100644 --- a/packages/console/app/src/i18n/zh.ts +++ b/packages/console/app/src/i18n/zh.ts @@ -396,6 +396,7 @@ export const dict = { "black.subscribe.success.chargeNotice": "您的卡将在订阅激活时扣费", "workspace.nav.zen": "Zen", + "workspace.nav.go": "Go", "workspace.nav.usage": "使用量", "workspace.nav.apiKeys": "API 密钥", "workspace.nav.members": "成员", @@ -601,7 +602,7 @@ export const dict = { "workspace.lite.time.minute": "分钟", "workspace.lite.time.minutes": "分钟", "workspace.lite.time.fewSeconds": "几秒钟", - "workspace.lite.subscription.title": "Go 订阅", + "workspace.lite.title": "OpenCode Go", "workspace.lite.subscription.message": "您已订阅 OpenCode Go。", "workspace.lite.subscription.manage": "管理订阅", "workspace.lite.subscription.rollingUsage": "滚动用量", @@ -611,9 +612,9 @@ export const dict = { "workspace.lite.subscription.useBalance": "达到使用限额后使用您的可用余额", "workspace.lite.subscription.selectProvider": "在你的 opencode 配置中选择「OpenCode Go」作为提供商,即可使用 Go 模型。", - "workspace.lite.other.title": "Go 订阅", + "workspace.lite.black.message": + '您当前已订阅 OpenCode Black 或在候补名单中。如需切换到 Go,请先取消订阅。', "workspace.lite.other.message": "此工作区中的另一位成员已经订阅了 OpenCode Go。每个工作区只有一名成员可以订阅。", - "workspace.lite.promo.title": "OpenCode Go", "workspace.lite.promo.description": "OpenCode Go 是一个每月 $10 的订阅计划,提供对主流开源编码模型的稳定访问,并配备充足的使用额度。", "workspace.lite.promo.modelsTitle": "包含模型", diff --git a/packages/console/app/src/i18n/zht.ts b/packages/console/app/src/i18n/zht.ts index 1167d5a6c..bd12783e2 100644 --- a/packages/console/app/src/i18n/zht.ts +++ b/packages/console/app/src/i18n/zht.ts @@ -397,6 +397,7 @@ export const dict = { "black.subscribe.success.chargeNotice": "你的卡片將在訂閱啟用時扣款", "workspace.nav.zen": "Zen", + "workspace.nav.go": "Go", "workspace.nav.usage": "使用量", "workspace.nav.apiKeys": "API 金鑰", "workspace.nav.members": "成員", @@ -602,7 +603,7 @@ export const dict = { "workspace.lite.time.minute": "分鐘", "workspace.lite.time.minutes": "分鐘", "workspace.lite.time.fewSeconds": "幾秒", - "workspace.lite.subscription.title": "Go 訂閱", + "workspace.lite.title": "OpenCode Go", "workspace.lite.subscription.message": "您已訂閱 OpenCode Go。", "workspace.lite.subscription.manage": "管理訂閱", "workspace.lite.subscription.rollingUsage": "滾動使用量", @@ -612,9 +613,9 @@ export const dict = { "workspace.lite.subscription.useBalance": "達到使用限制後使用您的可用餘額", "workspace.lite.subscription.selectProvider": "在您的 opencode 設定中選擇「OpenCode Go」作為提供商,即可使用 Go 模型。", - "workspace.lite.other.title": "Go 訂閱", + "workspace.lite.black.message": + '您目前已訂閱 OpenCode Black 或在候補名單中。若要切換至 Go,請先取消訂閱。', "workspace.lite.other.message": "此工作區中的另一位成員已訂閱 OpenCode Go。每個工作區只能有一位成員訂閱。", - "workspace.lite.promo.title": "OpenCode Go", "workspace.lite.promo.description": "OpenCode Go 是一個每月 $10 的訂閱方案,提供對主流開放原始碼編碼模型的穩定存取,並配備充足的使用額度。", "workspace.lite.promo.modelsTitle": "包含模型", diff --git a/packages/console/app/src/routes/go/index.tsx b/packages/console/app/src/routes/go/index.tsx index dcd909ab4..8f1930bd7 100644 --- a/packages/console/app/src/routes/go/index.tsx +++ b/packages/console/app/src/routes/go/index.tsx @@ -205,7 +205,7 @@ function LimitsGraph(props: { href: string }) { export default function Home() { const workspaceID = createAsync(() => checkLoggedIn()) - const subscribeUrl = createMemo(() => (workspaceID() ? `/workspace/${workspaceID()}/billing` : "/auth")) + const subscribeUrl = createMemo(() => (workspaceID() ? `/workspace/${workspaceID()}/go` : "/auth")) const i18n = useI18n() const language = useLanguage() return ( diff --git a/packages/console/app/src/routes/workspace/[id].tsx b/packages/console/app/src/routes/workspace/[id].tsx index a36368fd0..7a8e1616f 100644 --- a/packages/console/app/src/routes/workspace/[id].tsx +++ b/packages/console/app/src/routes/workspace/[id].tsx @@ -19,6 +19,9 @@ export default function WorkspaceLayout(props: RouteSectionProps) { {i18n.t("workspace.nav.zen")} + + {i18n.t("workspace.nav.go")} + {i18n.t("workspace.nav.usage")} @@ -44,6 +47,9 @@ export default function WorkspaceLayout(props: RouteSectionProps) { {i18n.t("workspace.nav.zen")} + + {i18n.t("workspace.nav.go")} + {i18n.t("workspace.nav.usage")} 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 e039a09ef..4a7dc2488 100644 --- a/packages/console/app/src/routes/workspace/[id]/billing/index.tsx +++ b/packages/console/app/src/routes/workspace/[id]/billing/index.tsx @@ -3,7 +3,6 @@ import { BillingSection } from "./billing-section" import { ReloadSection } from "./reload-section" import { PaymentSection } from "./payment-section" import { BlackSection } from "./black-section" -import { LiteSection } from "./lite-section" import { createMemo, Show } from "solid-js" import { createAsync, useParams } from "@solidjs/router" import { queryBillingInfo, querySessionInfo } from "../../common" @@ -21,9 +20,6 @@ export default function () { - - - diff --git a/packages/console/app/src/routes/workspace/[id]/billing/lite-section.module.css b/packages/console/app/src/routes/workspace/[id]/billing/lite-section.module.css deleted file mode 100644 index 76d9bcfb0..000000000 --- a/packages/console/app/src/routes/workspace/[id]/billing/lite-section.module.css +++ /dev/null @@ -1,190 +0,0 @@ -.root { - [data-slot="title-row"] { - display: flex; - justify-content: space-between; - align-items: center; - gap: var(--space-4); - } - - [data-slot="usage"] { - display: flex; - gap: var(--space-6); - margin-top: var(--space-4); - - @media (max-width: 40rem) { - flex-direction: column; - gap: var(--space-4); - } - } - - [data-slot="usage-item"] { - flex: 1; - display: flex; - flex-direction: column; - gap: var(--space-2); - } - - [data-slot="usage-header"] { - display: flex; - justify-content: space-between; - align-items: baseline; - } - - [data-slot="usage-label"] { - font-size: var(--font-size-md); - font-weight: 500; - color: var(--color-text); - } - - [data-slot="usage-value"] { - font-size: var(--font-size-sm); - color: var(--color-text-muted); - } - - [data-slot="progress"] { - height: 8px; - background-color: var(--color-bg-surface); - border-radius: var(--border-radius-sm); - overflow: hidden; - } - - [data-slot="progress-bar"] { - height: 100%; - background-color: var(--color-accent); - border-radius: var(--border-radius-sm); - transition: width 0.3s ease; - } - - [data-slot="reset-time"] { - font-size: var(--font-size-sm); - color: var(--color-text-muted); - } - - [data-slot="setting-row"] { - display: flex; - align-items: center; - justify-content: space-between; - gap: var(--space-3); - margin-top: var(--space-4); - - p { - font-size: var(--font-size-sm); - line-height: 1.5; - color: var(--color-text-secondary); - margin: 0; - } - } - - [data-slot="toggle-label"] { - position: relative; - display: inline-block; - width: 2.5rem; - height: 1.5rem; - cursor: pointer; - flex-shrink: 0; - - input { - opacity: 0; - width: 0; - height: 0; - } - - span { - position: absolute; - inset: 0; - background-color: #ccc; - border: 1px solid #bbb; - border-radius: 1.5rem; - transition: all 0.3s ease; - cursor: pointer; - - &::before { - content: ""; - position: absolute; - top: 50%; - left: 0.125rem; - width: 1.25rem; - height: 1.25rem; - background-color: white; - border: 1px solid #ddd; - border-radius: 50%; - transform: translateY(-50%); - transition: all 0.3s ease; - } - } - - input:checked + span { - background-color: #21ad0e; - border-color: #148605; - - &::before { - transform: translateX(1rem) translateY(-50%); - } - } - - &:hover span { - box-shadow: 0 0 0 2px rgba(34, 197, 94, 0.2); - } - - input:checked:hover + span { - box-shadow: 0 0 0 2px rgba(34, 197, 94, 0.3); - } - - &:has(input:disabled) { - cursor: not-allowed; - } - - input:disabled + span { - opacity: 0.5; - cursor: not-allowed; - } - } - - [data-slot="beta-notice"] { - padding: var(--space-3) var(--space-4); - border: 1px solid var(--color-border); - border-radius: var(--border-radius-sm); - background-color: var(--color-bg-surface); - font-size: var(--font-size-sm); - color: var(--color-text-secondary); - line-height: 1.5; - margin-top: var(--space-3); - - a { - color: var(--color-accent); - text-decoration: none; - } - } - - [data-slot="other-message"] { - font-size: var(--font-size-sm); - color: var(--color-text-muted); - line-height: 1.5; - } - - [data-slot="promo-description"] { - font-size: var(--font-size-md); - color: var(--color-text-secondary); - line-height: 1.5; - margin-top: var(--space-2); - } - - [data-slot="promo-models-title"] { - font-size: var(--font-size-md); - font-weight: 600; - margin-top: var(--space-4); - } - - [data-slot="promo-models"] { - margin: var(--space-2) 0 0 var(--space-4); - padding: 0; - font-size: var(--font-size-md); - color: var(--color-text-secondary); - line-height: 1.4; - } - - [data-slot="subscribe-button"] { - align-self: flex-start; - margin-top: var(--space-4); - } -} diff --git a/packages/console/app/src/routes/workspace/[id]/billing/lite-section.tsx b/packages/console/app/src/routes/workspace/[id]/billing/lite-section.tsx deleted file mode 100644 index f67775d79..000000000 --- a/packages/console/app/src/routes/workspace/[id]/billing/lite-section.tsx +++ /dev/null @@ -1,286 +0,0 @@ -import { action, useParams, useAction, useSubmission, json, query, createAsync } from "@solidjs/router" -import { createStore } from "solid-js/store" -import { Show } from "solid-js" -import { Billing } from "@opencode-ai/console-core/billing.js" -import { Database, eq, and, isNull } from "@opencode-ai/console-core/drizzle/index.js" -import { BillingTable, LiteTable } from "@opencode-ai/console-core/schema/billing.sql.js" -import { Actor } from "@opencode-ai/console-core/actor.js" -import { Subscription } from "@opencode-ai/console-core/subscription.js" -import { LiteData } from "@opencode-ai/console-core/lite.js" -import { withActor } from "~/context/auth.withActor" -import { queryBillingInfo } from "../../common" -import styles from "./lite-section.module.css" -import { useI18n } from "~/context/i18n" -import { useLanguage } from "~/context/language" -import { formError } from "~/lib/form-error" - -const queryLiteSubscription = query(async (workspaceID: string) => { - "use server" - return withActor(async () => { - const row = await Database.use((tx) => - tx - .select({ - userID: LiteTable.userID, - rollingUsage: LiteTable.rollingUsage, - weeklyUsage: LiteTable.weeklyUsage, - monthlyUsage: LiteTable.monthlyUsage, - timeRollingUpdated: LiteTable.timeRollingUpdated, - timeWeeklyUpdated: LiteTable.timeWeeklyUpdated, - timeMonthlyUpdated: LiteTable.timeMonthlyUpdated, - timeCreated: LiteTable.timeCreated, - lite: BillingTable.lite, - }) - .from(BillingTable) - .innerJoin(LiteTable, eq(LiteTable.workspaceID, BillingTable.workspaceID)) - .where(and(eq(LiteTable.workspaceID, Actor.workspace()), isNull(LiteTable.timeDeleted))) - .then((r) => r[0]), - ) - if (!row) return null - - const limits = LiteData.getLimits() - const mine = row.userID === Actor.userID() - - return { - mine, - useBalance: row.lite?.useBalance ?? false, - rollingUsage: Subscription.analyzeRollingUsage({ - limit: limits.rollingLimit, - window: limits.rollingWindow, - usage: row.rollingUsage ?? 0, - timeUpdated: row.timeRollingUpdated ?? new Date(), - }), - weeklyUsage: Subscription.analyzeWeeklyUsage({ - limit: limits.weeklyLimit, - usage: row.weeklyUsage ?? 0, - timeUpdated: row.timeWeeklyUpdated ?? new Date(), - }), - monthlyUsage: Subscription.analyzeMonthlyUsage({ - limit: limits.monthlyLimit, - usage: row.monthlyUsage ?? 0, - timeUpdated: row.timeMonthlyUpdated ?? new Date(), - timeSubscribed: row.timeCreated, - }), - } - }, workspaceID) -}, "lite.subscription.get") - -function formatResetTime(seconds: number, i18n: ReturnType) { - const days = Math.floor(seconds / 86400) - if (days >= 1) { - const hours = Math.floor((seconds % 86400) / 3600) - return `${days} ${days === 1 ? i18n.t("workspace.lite.time.day") : i18n.t("workspace.lite.time.days")} ${hours} ${hours === 1 ? i18n.t("workspace.lite.time.hour") : i18n.t("workspace.lite.time.hours")}` - } - const hours = Math.floor(seconds / 3600) - const minutes = Math.floor((seconds % 3600) / 60) - if (hours >= 1) - return `${hours} ${hours === 1 ? i18n.t("workspace.lite.time.hour") : i18n.t("workspace.lite.time.hours")} ${minutes} ${minutes === 1 ? i18n.t("workspace.lite.time.minute") : i18n.t("workspace.lite.time.minutes")}` - if (minutes === 0) return i18n.t("workspace.lite.time.fewSeconds") - return `${minutes} ${minutes === 1 ? i18n.t("workspace.lite.time.minute") : i18n.t("workspace.lite.time.minutes")}` -} - -const createLiteCheckoutUrl = action(async (workspaceID: string, successUrl: string, cancelUrl: string) => { - "use server" - return json( - await withActor( - () => - Billing.generateLiteCheckoutUrl({ successUrl, cancelUrl }) - .then((data) => ({ error: undefined, data })) - .catch((e) => ({ - error: e.message as string, - data: undefined, - })), - workspaceID, - ), - { revalidate: [queryBillingInfo.key, queryLiteSubscription.key] }, - ) -}, "liteCheckoutUrl") - -const createSessionUrl = action(async (workspaceID: string, returnUrl: string) => { - "use server" - return json( - await withActor( - () => - Billing.generateSessionUrl({ returnUrl }) - .then((data) => ({ error: undefined, data })) - .catch((e) => ({ - error: e.message as string, - data: undefined, - })), - workspaceID, - ), - { revalidate: [queryBillingInfo.key, queryLiteSubscription.key] }, - ) -}, "liteSessionUrl") - -const setLiteUseBalance = action(async (form: FormData) => { - "use server" - const workspaceID = form.get("workspaceID")?.toString() - if (!workspaceID) return { error: formError.workspaceRequired } - const useBalance = form.get("useBalance")?.toString() === "true" - - return json( - await withActor(async () => { - await Database.use((tx) => - tx - .update(BillingTable) - .set({ - lite: useBalance ? { useBalance: true } : {}, - }) - .where(eq(BillingTable.workspaceID, workspaceID)), - ) - return { error: undefined } - }, workspaceID).catch((e) => ({ error: e.message as string })), - { revalidate: [queryBillingInfo.key, queryLiteSubscription.key] }, - ) -}, "setLiteUseBalance") - -export function LiteSection() { - const params = useParams() - const i18n = useI18n() - const language = useLanguage() - const lite = createAsync(() => queryLiteSubscription(params.id!)) - const sessionAction = useAction(createSessionUrl) - const sessionSubmission = useSubmission(createSessionUrl) - const checkoutAction = useAction(createLiteCheckoutUrl) - const checkoutSubmission = useSubmission(createLiteCheckoutUrl) - const useBalanceSubmission = useSubmission(setLiteUseBalance) - const [store, setStore] = createStore({ - redirecting: false, - }) - - async function onClickSession() { - const result = await sessionAction(params.id!, window.location.href) - if (result.data) { - setStore("redirecting", true) - window.location.href = result.data - } - } - - async function onClickSubscribe() { - const result = await checkoutAction(params.id!, window.location.href, window.location.href) - if (result.data) { - setStore("redirecting", true) - window.location.href = result.data - } - } - - return ( - <> - - {(sub) => ( -
-
-

{i18n.t("workspace.lite.subscription.title")}

-
-

{i18n.t("workspace.lite.subscription.message")}

- -
-
-
- {i18n.t("workspace.lite.subscription.selectProvider")}{" "} - - {i18n.t("common.learnMore")} - - . -
-
-
-
- {i18n.t("workspace.lite.subscription.rollingUsage")} - {sub().rollingUsage.usagePercent}% -
-
-
-
- - {i18n.t("workspace.lite.subscription.resetsIn")}{" "} - {formatResetTime(sub().rollingUsage.resetInSec, i18n)} - -
-
-
- {i18n.t("workspace.lite.subscription.weeklyUsage")} - {sub().weeklyUsage.usagePercent}% -
-
-
-
- - {i18n.t("workspace.lite.subscription.resetsIn")} {formatResetTime(sub().weeklyUsage.resetInSec, i18n)} - -
-
-
- {i18n.t("workspace.lite.subscription.monthlyUsage")} - {sub().monthlyUsage.usagePercent}% -
-
-
-
- - {i18n.t("workspace.lite.subscription.resetsIn")}{" "} - {formatResetTime(sub().monthlyUsage.resetInSec, i18n)} - -
-
-
-

{i18n.t("workspace.lite.subscription.useBalance")}

- - - -
-
- )} -
- -
-
-

{i18n.t("workspace.lite.other.title")}

-
-

{i18n.t("workspace.lite.other.message")}

-
-
- -
-
-

{i18n.t("workspace.lite.promo.title")}

-
-

{i18n.t("workspace.lite.promo.description")}

-

{i18n.t("workspace.lite.promo.modelsTitle")}

-
    -
  • Kimi K2.5
  • -
  • GLM-5
  • -
  • MiniMax M2.5
  • -
-

{i18n.t("workspace.lite.promo.footer")}

- -
-
- - ) -} diff --git a/packages/console/app/src/routes/workspace/[id]/go/index.tsx b/packages/console/app/src/routes/workspace/[id]/go/index.tsx new file mode 100644 index 000000000..116938a12 --- /dev/null +++ b/packages/console/app/src/routes/workspace/[id]/go/index.tsx @@ -0,0 +1,11 @@ +import { LiteSection } from "./lite-section" + +export default function () { + return ( +
+
+ +
+
+ ) +} diff --git a/packages/console/app/src/routes/workspace/[id]/go/lite-section.module.css b/packages/console/app/src/routes/workspace/[id]/go/lite-section.module.css new file mode 100644 index 000000000..76d9bcfb0 --- /dev/null +++ b/packages/console/app/src/routes/workspace/[id]/go/lite-section.module.css @@ -0,0 +1,190 @@ +.root { + [data-slot="title-row"] { + display: flex; + justify-content: space-between; + align-items: center; + gap: var(--space-4); + } + + [data-slot="usage"] { + display: flex; + gap: var(--space-6); + margin-top: var(--space-4); + + @media (max-width: 40rem) { + flex-direction: column; + gap: var(--space-4); + } + } + + [data-slot="usage-item"] { + flex: 1; + display: flex; + flex-direction: column; + gap: var(--space-2); + } + + [data-slot="usage-header"] { + display: flex; + justify-content: space-between; + align-items: baseline; + } + + [data-slot="usage-label"] { + font-size: var(--font-size-md); + font-weight: 500; + color: var(--color-text); + } + + [data-slot="usage-value"] { + font-size: var(--font-size-sm); + color: var(--color-text-muted); + } + + [data-slot="progress"] { + height: 8px; + background-color: var(--color-bg-surface); + border-radius: var(--border-radius-sm); + overflow: hidden; + } + + [data-slot="progress-bar"] { + height: 100%; + background-color: var(--color-accent); + border-radius: var(--border-radius-sm); + transition: width 0.3s ease; + } + + [data-slot="reset-time"] { + font-size: var(--font-size-sm); + color: var(--color-text-muted); + } + + [data-slot="setting-row"] { + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--space-3); + margin-top: var(--space-4); + + p { + font-size: var(--font-size-sm); + line-height: 1.5; + color: var(--color-text-secondary); + margin: 0; + } + } + + [data-slot="toggle-label"] { + position: relative; + display: inline-block; + width: 2.5rem; + height: 1.5rem; + cursor: pointer; + flex-shrink: 0; + + input { + opacity: 0; + width: 0; + height: 0; + } + + span { + position: absolute; + inset: 0; + background-color: #ccc; + border: 1px solid #bbb; + border-radius: 1.5rem; + transition: all 0.3s ease; + cursor: pointer; + + &::before { + content: ""; + position: absolute; + top: 50%; + left: 0.125rem; + width: 1.25rem; + height: 1.25rem; + background-color: white; + border: 1px solid #ddd; + border-radius: 50%; + transform: translateY(-50%); + transition: all 0.3s ease; + } + } + + input:checked + span { + background-color: #21ad0e; + border-color: #148605; + + &::before { + transform: translateX(1rem) translateY(-50%); + } + } + + &:hover span { + box-shadow: 0 0 0 2px rgba(34, 197, 94, 0.2); + } + + input:checked:hover + span { + box-shadow: 0 0 0 2px rgba(34, 197, 94, 0.3); + } + + &:has(input:disabled) { + cursor: not-allowed; + } + + input:disabled + span { + opacity: 0.5; + cursor: not-allowed; + } + } + + [data-slot="beta-notice"] { + padding: var(--space-3) var(--space-4); + border: 1px solid var(--color-border); + border-radius: var(--border-radius-sm); + background-color: var(--color-bg-surface); + font-size: var(--font-size-sm); + color: var(--color-text-secondary); + line-height: 1.5; + margin-top: var(--space-3); + + a { + color: var(--color-accent); + text-decoration: none; + } + } + + [data-slot="other-message"] { + font-size: var(--font-size-sm); + color: var(--color-text-muted); + line-height: 1.5; + } + + [data-slot="promo-description"] { + font-size: var(--font-size-md); + color: var(--color-text-secondary); + line-height: 1.5; + margin-top: var(--space-2); + } + + [data-slot="promo-models-title"] { + font-size: var(--font-size-md); + font-weight: 600; + margin-top: var(--space-4); + } + + [data-slot="promo-models"] { + margin: var(--space-2) 0 0 var(--space-4); + padding: 0; + font-size: var(--font-size-md); + color: var(--color-text-secondary); + line-height: 1.4; + } + + [data-slot="subscribe-button"] { + align-self: flex-start; + margin-top: var(--space-4); + } +} diff --git a/packages/console/app/src/routes/workspace/[id]/go/lite-section.tsx b/packages/console/app/src/routes/workspace/[id]/go/lite-section.tsx new file mode 100644 index 000000000..282411e8c --- /dev/null +++ b/packages/console/app/src/routes/workspace/[id]/go/lite-section.tsx @@ -0,0 +1,296 @@ +import { action, useParams, useAction, useSubmission, json, query, createAsync } from "@solidjs/router" +import { createStore } from "solid-js/store" +import { createMemo, Show } from "solid-js" +import { Billing } from "@opencode-ai/console-core/billing.js" +import { Database, eq, and, isNull } from "@opencode-ai/console-core/drizzle/index.js" +import { BillingTable, LiteTable } from "@opencode-ai/console-core/schema/billing.sql.js" +import { Actor } from "@opencode-ai/console-core/actor.js" +import { Subscription } from "@opencode-ai/console-core/subscription.js" +import { LiteData } from "@opencode-ai/console-core/lite.js" +import { withActor } from "~/context/auth.withActor" +import { queryBillingInfo } from "../../common" +import styles from "./lite-section.module.css" +import { useI18n } from "~/context/i18n" +import { useLanguage } from "~/context/language" +import { formError } from "~/lib/form-error" + +const queryLiteSubscription = query(async (workspaceID: string) => { + "use server" + return withActor(async () => { + const row = await Database.use((tx) => + tx + .select({ + userID: LiteTable.userID, + rollingUsage: LiteTable.rollingUsage, + weeklyUsage: LiteTable.weeklyUsage, + monthlyUsage: LiteTable.monthlyUsage, + timeRollingUpdated: LiteTable.timeRollingUpdated, + timeWeeklyUpdated: LiteTable.timeWeeklyUpdated, + timeMonthlyUpdated: LiteTable.timeMonthlyUpdated, + timeCreated: LiteTable.timeCreated, + lite: BillingTable.lite, + }) + .from(BillingTable) + .innerJoin(LiteTable, eq(LiteTable.workspaceID, BillingTable.workspaceID)) + .where(and(eq(LiteTable.workspaceID, Actor.workspace()), isNull(LiteTable.timeDeleted))) + .then((r) => r[0]), + ) + if (!row) return null + + const limits = LiteData.getLimits() + const mine = row.userID === Actor.userID() + + return { + mine, + useBalance: row.lite?.useBalance ?? false, + rollingUsage: Subscription.analyzeRollingUsage({ + limit: limits.rollingLimit, + window: limits.rollingWindow, + usage: row.rollingUsage ?? 0, + timeUpdated: row.timeRollingUpdated ?? new Date(), + }), + weeklyUsage: Subscription.analyzeWeeklyUsage({ + limit: limits.weeklyLimit, + usage: row.weeklyUsage ?? 0, + timeUpdated: row.timeWeeklyUpdated ?? new Date(), + }), + monthlyUsage: Subscription.analyzeMonthlyUsage({ + limit: limits.monthlyLimit, + usage: row.monthlyUsage ?? 0, + timeUpdated: row.timeMonthlyUpdated ?? new Date(), + timeSubscribed: row.timeCreated, + }), + } + }, workspaceID) +}, "lite.subscription.get") + +function formatResetTime(seconds: number, i18n: ReturnType) { + const days = Math.floor(seconds / 86400) + if (days >= 1) { + const hours = Math.floor((seconds % 86400) / 3600) + return `${days} ${days === 1 ? i18n.t("workspace.lite.time.day") : i18n.t("workspace.lite.time.days")} ${hours} ${hours === 1 ? i18n.t("workspace.lite.time.hour") : i18n.t("workspace.lite.time.hours")}` + } + const hours = Math.floor(seconds / 3600) + const minutes = Math.floor((seconds % 3600) / 60) + if (hours >= 1) + return `${hours} ${hours === 1 ? i18n.t("workspace.lite.time.hour") : i18n.t("workspace.lite.time.hours")} ${minutes} ${minutes === 1 ? i18n.t("workspace.lite.time.minute") : i18n.t("workspace.lite.time.minutes")}` + if (minutes === 0) return i18n.t("workspace.lite.time.fewSeconds") + return `${minutes} ${minutes === 1 ? i18n.t("workspace.lite.time.minute") : i18n.t("workspace.lite.time.minutes")}` +} + +const createLiteCheckoutUrl = action(async (workspaceID: string, successUrl: string, cancelUrl: string) => { + "use server" + return json( + await withActor( + () => + Billing.generateLiteCheckoutUrl({ successUrl, cancelUrl }) + .then((data) => ({ error: undefined, data })) + .catch((e) => ({ + error: e.message as string, + data: undefined, + })), + workspaceID, + ), + { revalidate: [queryBillingInfo.key, queryLiteSubscription.key] }, + ) +}, "liteCheckoutUrl") + +const createSessionUrl = action(async (workspaceID: string, returnUrl: string) => { + "use server" + return json( + await withActor( + () => + Billing.generateSessionUrl({ returnUrl }) + .then((data) => ({ error: undefined, data })) + .catch((e) => ({ + error: e.message as string, + data: undefined, + })), + workspaceID, + ), + { revalidate: [queryBillingInfo.key, queryLiteSubscription.key] }, + ) +}, "liteSessionUrl") + +const setLiteUseBalance = action(async (form: FormData) => { + "use server" + const workspaceID = form.get("workspaceID")?.toString() + if (!workspaceID) return { error: formError.workspaceRequired } + const useBalance = form.get("useBalance")?.toString() === "true" + + return json( + await withActor(async () => { + await Database.use((tx) => + tx + .update(BillingTable) + .set({ + lite: useBalance ? { useBalance: true } : {}, + }) + .where(eq(BillingTable.workspaceID, workspaceID)), + ) + return { error: undefined } + }, workspaceID).catch((e) => ({ error: e.message as string })), + { revalidate: [queryBillingInfo.key, queryLiteSubscription.key] }, + ) +}, "setLiteUseBalance") + +export function LiteSection() { + const params = useParams() + const i18n = useI18n() + const language = useLanguage() + const billingInfo = createAsync(() => queryBillingInfo(params.id!)) + const isBlack = createMemo(() => billingInfo()?.subscriptionID || billingInfo()?.timeSubscriptionBooked) + const lite = createAsync(() => queryLiteSubscription(params.id!)) + const sessionAction = useAction(createSessionUrl) + const sessionSubmission = useSubmission(createSessionUrl) + const checkoutAction = useAction(createLiteCheckoutUrl) + const checkoutSubmission = useSubmission(createLiteCheckoutUrl) + const useBalanceSubmission = useSubmission(setLiteUseBalance) + const [store, setStore] = createStore({ + redirecting: false, + }) + + async function onClickSession() { + const result = await sessionAction(params.id!, window.location.href) + if (result.data) { + setStore("redirecting", true) + window.location.href = result.data + } + } + + async function onClickSubscribe() { + const result = await checkoutAction(params.id!, window.location.href, window.location.href) + if (result.data) { + setStore("redirecting", true) + window.location.href = result.data + } + } + + return ( + <> + +
+
+

{i18n.t("workspace.lite.title")}

+
+

{i18n.t("workspace.lite.black.message")}

+
+
+ + {(sub) => ( +
+
+

{i18n.t("workspace.lite.title")}

+
+

{i18n.t("workspace.lite.subscription.message")}

+ +
+
+
+ {i18n.t("workspace.lite.subscription.selectProvider")}{" "} + + {i18n.t("common.learnMore")} + + . +
+
+
+
+ {i18n.t("workspace.lite.subscription.rollingUsage")} + {sub().rollingUsage.usagePercent}% +
+
+
+
+ + {i18n.t("workspace.lite.subscription.resetsIn")}{" "} + {formatResetTime(sub().rollingUsage.resetInSec, i18n)} + +
+
+
+ {i18n.t("workspace.lite.subscription.weeklyUsage")} + {sub().weeklyUsage.usagePercent}% +
+
+
+
+ + {i18n.t("workspace.lite.subscription.resetsIn")} {formatResetTime(sub().weeklyUsage.resetInSec, i18n)} + +
+
+
+ {i18n.t("workspace.lite.subscription.monthlyUsage")} + {sub().monthlyUsage.usagePercent}% +
+
+
+
+ + {i18n.t("workspace.lite.subscription.resetsIn")}{" "} + {formatResetTime(sub().monthlyUsage.resetInSec, i18n)} + +
+
+
+

{i18n.t("workspace.lite.subscription.useBalance")}

+ + + +
+
+ )} +
+ +
+
+

{i18n.t("workspace.lite.title")}

+
+

{i18n.t("workspace.lite.other.message")}

+
+
+ +
+
+

{i18n.t("workspace.lite.title")}

+
+

{i18n.t("workspace.lite.promo.description")}

+

{i18n.t("workspace.lite.promo.modelsTitle")}

+
    +
  • Kimi K2.5
  • +
  • GLM-5
  • +
  • MiniMax M2.5
  • +
+

{i18n.t("workspace.lite.promo.footer")}

+ +
+
+ + ) +} -- cgit v1.2.3