feat(cloud): display unavailable plans without checkout actions

This commit is contained in:
RockChinQ
2026-10-16 17:11:00 +08:00
parent aabcaedf15
commit ececcb8749
11 changed files with 40 additions and 1 deletions
@@ -430,7 +430,20 @@ export default function CloudPlansDialog({
<div className="flex-1">
<Benefits plan={plan} spaceURL={spaceURL} />
</div>
{downgradeBlocked ? null : !canManage ? (
{plan.subscription_disabled && (
<p className="mt-4 text-xs text-muted-foreground">
{t('cloudPlans.subscriptionUnavailableHint')}
</p>
)}
{plan.subscription_disabled && !current ? (
<Button
className="mt-6 w-full"
variant="outline"
disabled
>
{t('cloudPlans.subscriptionUnavailable')}
</Button>
) : downgradeBlocked ? null : !canManage ? (
<Button
className="mt-6 w-full"
variant="outline"
@@ -13,6 +13,7 @@ export interface PublicCloudPlan {
limits: Record<string, number>;
features: string[];
is_active: boolean;
subscription_disabled?: boolean;
sort_order: number;
highlight: boolean;
chat_history_retention_days: number;
+3
View File
@@ -2,6 +2,9 @@ import slackSetup from './slack-setup/en-US';
import pipelineMigration from './pipeline-migration/en-US';
const enUS = {
cloudPlans: {
subscriptionUnavailable: 'Not available to subscribe',
subscriptionUnavailableHint:
'This plan is not accepting new subscriptions. Please choose another plan. Existing subscriptions and scheduled automatic renewals are unaffected.',
platformNames: {
qqofficial: 'QQ Official API',
dingtalk: 'DingTalk',
+3
View File
@@ -1,6 +1,9 @@
import pipelineMigration from './pipeline-migration/es-ES';
const esES = {
cloudPlans: {
subscriptionUnavailable: 'Suscripción no disponible',
subscriptionUnavailableHint:
'Este plan no acepta nuevas suscripciones. Elige otro plan. Las suscripciones existentes y sus renovaciones automáticas no se ven afectadas.',
platformNames: {
qqofficial: 'QQ Official API',
dingtalk: 'DingTalk',
+3
View File
@@ -2,6 +2,9 @@ import slackSetup from './slack-setup/ja-JP';
import pipelineMigration from './pipeline-migration/ja-JP';
const jaJP = {
cloudPlans: {
subscriptionUnavailable: '現在お申し込みできません',
subscriptionUnavailableHint:
'このプランは新規申込を停止しています。他のプランをお選びください。既存の契約と自動更新には影響しません。',
platformNames: {
qqofficial: 'QQ公式API',
dingtalk: 'DingTalk',
+3
View File
@@ -1,6 +1,9 @@
import pipelineMigration from './pipeline-migration/ru-RU';
const ruRU = {
cloudPlans: {
subscriptionUnavailable: 'Подписка недоступна',
subscriptionUnavailableHint:
'Этот план не принимает новые подписки. Выберите другой план. Текущие подписки и автоматические продления не затронуты.',
platformNames: {
qqofficial: 'QQ Official API',
dingtalk: 'DingTalk',
+3
View File
@@ -1,6 +1,9 @@
import pipelineMigration from './pipeline-migration/th-TH';
const thTH = {
cloudPlans: {
subscriptionUnavailable: 'ยังไม่เปิดรับการสมัคร',
subscriptionUnavailableHint:
'แผนนี้ยังไม่รับการสมัครใหม่ โปรดเลือกแผนอื่น การสมัครเดิมและการต่ออายุอัตโนมัติจะไม่ได้รับผลกระทบ',
platformNames: {
qqofficial: 'QQ Official API',
dingtalk: 'DingTalk',
+3
View File
@@ -1,6 +1,9 @@
import pipelineMigration from './pipeline-migration/vi-VN';
const viVN = {
cloudPlans: {
subscriptionUnavailable: 'Chưa thể đăng ký',
subscriptionUnavailableHint:
'Gói này hiện không nhận đăng ký mới. Vui lòng chọn gói khác. Đăng ký hiện có và gia hạn tự động không bị ảnh hưởng.',
platformNames: {
qqofficial: 'QQ Official API',
dingtalk: 'DingTalk',
+3
View File
@@ -2,6 +2,9 @@ import slackSetup from './slack-setup/zh-Hans';
import pipelineMigration from './pipeline-migration/zh-Hans';
const zhHans = {
cloudPlans: {
subscriptionUnavailable: '暂不可订阅',
subscriptionUnavailableHint:
'此计划暂不接受新的订阅,请选择其他计划。已有订阅和已签约的自动续费不受影响。',
platformNames: {
qqofficial: 'QQ 官方 API',
dingtalk: '钉钉',
+3
View File
@@ -2,6 +2,9 @@ import slackSetup from './slack-setup/zh-Hant';
import pipelineMigration from './pipeline-migration/zh-Hant';
const zhHant = {
cloudPlans: {
subscriptionUnavailable: '暫不可訂閱',
subscriptionUnavailableHint:
'此方案暫不接受新訂閱,請選擇其他方案。既有訂閱和已簽約的自動續費不受影響。',
platformNames: {
qqofficial: 'QQ 官方 API',
dingtalk: '釘釘',
+1
View File
@@ -85,6 +85,7 @@ test('public catalog fetch omits cookies and authorization, hides inactive plans
price_usd: '5',
price_jpy: '800',
is_active: true,
subscription_disabled: true,
};
t.mock.method(globalThis, 'fetch', async (u, o) => {
url = u;