Skip to content

Commit c5a5451

Browse files
committed
fix(coding-plans): drop Churnkey cancellation path
Keep Coding Plans on direct cancellation and include review-driven React state and render cleanup for the related subscription surfaces.
1 parent e55122a commit c5a5451

11 files changed

Lines changed: 452 additions & 663 deletions

File tree

apps/web/src/app/admin/coding-plans/CodingPlansOperationsContent.tsx

Lines changed: 361 additions & 210 deletions
Large diffs are not rendered by default.

apps/web/src/components/organizations/byok/BYOKKeysManager.tsx

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client';
22

3-
import { useState } from 'react';
3+
import { useReducer, useState } from 'react';
44
import { useTRPC } from '@/lib/trpc/utils';
55
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
66
import { Button } from '@/components/Button';
@@ -156,15 +156,54 @@ type InstalledKeyWarningAction =
156156
| { type: 'update'; keyId: string }
157157
| { type: 'delete'; keyId: string; providerName: string };
158158

159+
type BYOKDialogState = {
160+
isDialogOpen: boolean;
161+
editingKeyId: string | null;
162+
selectedProvider: string;
163+
apiKey: string;
164+
showApiKey: boolean;
165+
awsCredentialError: string | null;
166+
installedKeyWarningAction: InstalledKeyWarningAction | null;
167+
};
168+
169+
const INITIAL_BYOK_DIALOG_STATE: BYOKDialogState = {
170+
isDialogOpen: false,
171+
editingKeyId: null,
172+
selectedProvider: '',
173+
apiKey: '',
174+
showApiKey: false,
175+
awsCredentialError: null,
176+
installedKeyWarningAction: null,
177+
};
178+
179+
function updateBYOKDialogState(state: BYOKDialogState, update: Partial<BYOKDialogState>) {
180+
return { ...state, ...update };
181+
}
182+
159183
export function BYOKKeysManager({ organizationId }: BYOKKeysManagerProps) {
160-
const [isDialogOpen, setIsDialogOpen] = useState(false);
161-
const [editingKeyId, setEditingKeyId] = useState<string | null>(null);
162-
const [selectedProvider, setSelectedProvider] = useState('');
163-
const [apiKey, setApiKey] = useState('');
164-
const [showApiKey, setShowApiKey] = useState(false);
165-
const [awsCredentialError, setAwsCredentialError] = useState<string | null>(null);
166-
const [installedKeyWarningAction, setInstalledKeyWarningAction] =
167-
useState<InstalledKeyWarningAction | null>(null);
184+
const [dialogState, updateDialogState] = useReducer(
185+
updateBYOKDialogState,
186+
INITIAL_BYOK_DIALOG_STATE
187+
);
188+
const {
189+
isDialogOpen,
190+
editingKeyId,
191+
selectedProvider,
192+
apiKey,
193+
showApiKey,
194+
awsCredentialError,
195+
installedKeyWarningAction,
196+
} = dialogState;
197+
const setIsDialogOpen = (isDialogOpen: boolean) => updateDialogState({ isDialogOpen });
198+
const setEditingKeyId = (editingKeyId: string | null) => updateDialogState({ editingKeyId });
199+
const setSelectedProvider = (selectedProvider: string) => updateDialogState({ selectedProvider });
200+
const setApiKey = (apiKey: string) => updateDialogState({ apiKey });
201+
const setShowApiKey = (showApiKey: boolean) => updateDialogState({ showApiKey });
202+
const setAwsCredentialError = (awsCredentialError: string | null) =>
203+
updateDialogState({ awsCredentialError });
204+
const setInstalledKeyWarningAction = (
205+
installedKeyWarningAction: InstalledKeyWarningAction | null
206+
) => updateDialogState({ installedKeyWarningAction });
168207

169208
const trpc = useTRPC();
170209
const queryClient = useQueryClient();

apps/web/src/components/subscriptions/AvailableProductCard.tsx

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import Link from 'next/link';
22
import type { ReactNode } from 'react';
3-
import { ArrowRight } from 'lucide-react';
3+
import { ArrowRight, Check } from 'lucide-react';
44
import { Card } from '@/components/ui/card';
5+
import { Badge } from '@/components/ui/badge';
56
import { Button } from '@/components/ui/button';
67

78
export function AvailableProductCard({
@@ -16,9 +17,9 @@ export function AvailableProductCard({
1617
}: {
1718
icon: ReactNode;
1819
title: string;
19-
price: ReactNode;
20-
status?: ReactNode;
21-
features?: ReactNode;
20+
price: { amount: string; cadenceLabel: string };
21+
status?: string;
22+
features?: readonly string[];
2223
cta?: {
2324
label: string;
2425
href?: string;
@@ -52,12 +53,31 @@ export function AvailableProductCard({
5253
</div>
5354
<h3 className="truncate text-sm font-semibold">{title}</h3>
5455
</div>
55-
{status}
56+
{status ? (
57+
<Badge variant="secondary-outline" className="text-muted-foreground rounded-full px-3">
58+
{status}
59+
</Badge>
60+
) : null}
5661
</div>
5762

58-
<div className="mt-3">{price}</div>
63+
<div className="mt-3 flex items-baseline gap-1">
64+
<span className="text-2xl font-semibold text-white tabular-nums">{price.amount}</span>
65+
<span className="text-muted-foreground text-xs">{price.cadenceLabel}</span>
66+
</div>
5967

60-
{features ? <div className="mt-4 flex-1">{features}</div> : null}
68+
{features ? (
69+
<ul className="mt-4 grid flex-1 gap-x-8 gap-y-2 lg:grid-cols-2" aria-label="Plan benefits">
70+
{features.map(feature => (
71+
<li
72+
key={feature}
73+
className="text-muted-foreground flex items-start gap-2 text-xs leading-5"
74+
>
75+
<Check className="mt-0.5 size-4 shrink-0 text-emerald-400" aria-hidden />
76+
<span>{feature}</span>
77+
</li>
78+
))}
79+
</ul>
80+
) : null}
6181

6282
<div className="mt-4 pt-2">
6383
{action ?? (cta?.href && button ? <Link href={cta.href}>{button}</Link> : button)}

apps/web/src/components/subscriptions/coding-plans/CodingPlansGroup.tsx

Lines changed: 4 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import Link from 'next/link';
44
import { useState } from 'react';
55
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
6-
import { Check, CircleCheck, Code2 } from 'lucide-react';
6+
import { CircleCheck, Code2 } from 'lucide-react';
77
import { toast } from 'sonner';
88
import {
99
AlertDialog,
@@ -16,7 +16,6 @@ import {
1616
AlertDialogTitle,
1717
} from '@/components/ui/alert-dialog';
1818
import { Alert, AlertDescription } from '@/components/ui/alert';
19-
import { Badge } from '@/components/ui/badge';
2019
import { AvailableProductCard } from '@/components/subscriptions/AvailableProductCard';
2120
import { SubscriptionCard } from '@/components/subscriptions/SubscriptionCard';
2221
import { SubscriptionGroup } from '@/components/subscriptions/SubscriptionGroup';
@@ -302,34 +301,9 @@ function CodingPlanOfferCard({
302301
<AvailableProductCard
303302
icon={<CodingPlanIcon providerName={plan.providerName} />}
304303
title={`${plan.providerName} ${plan.name}`}
305-
price={
306-
<div className="flex items-baseline gap-1">
307-
<span className="text-2xl font-semibold text-white tabular-nums">{price.amount}</span>
308-
<span className="text-muted-foreground text-xs">{price.cadenceLabel}</span>
309-
</div>
310-
}
311-
status={
312-
isSoldOut ? (
313-
<Badge variant="secondary-outline" className="text-muted-foreground rounded-full px-3">
314-
Sold out
315-
</Badge>
316-
) : null
317-
}
318-
features={
319-
plan.planId === 'minimax-token-plan-plus' ? (
320-
<ul className="grid gap-x-8 gap-y-2 lg:grid-cols-2" aria-label="Plan benefits">
321-
{TOKEN_PLAN_PLUS_BENEFITS.map(benefit => (
322-
<li
323-
key={benefit}
324-
className="text-muted-foreground flex items-start gap-2 text-xs leading-5"
325-
>
326-
<Check className="mt-0.5 size-4 shrink-0 text-emerald-400" aria-hidden />
327-
<span>{benefit}</span>
328-
</li>
329-
))}
330-
</ul>
331-
) : null
332-
}
304+
price={price}
305+
status={isSoldOut ? 'Sold out' : undefined}
306+
features={plan.planId === 'minimax-token-plan-plus' ? TOKEN_PLAN_PLUS_BENEFITS : undefined}
333307
cta={
334308
isSoldOut
335309
? {

apps/web/src/components/subscriptions/coding-plans/codingPlanChurnkeyCancelFlow.test.ts

Lines changed: 0 additions & 151 deletions
This file was deleted.

apps/web/src/components/subscriptions/coding-plans/codingPlanChurnkeyCancelFlow.ts

Lines changed: 0 additions & 58 deletions
This file was deleted.

0 commit comments

Comments
 (0)