Skip to content

Commit 3ffcbe8

Browse files
committed
feat: redirect to checkout
1 parent e02e0d6 commit 3ffcbe8

File tree

6 files changed

+78
-15
lines changed

6 files changed

+78
-15
lines changed

apps/dashboard/app/(auth)/register/page.tsx

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
Mail,
1414
} from 'lucide-react';
1515
import Link from 'next/link';
16-
import { useRouter } from 'next/navigation';
16+
import { useRouter, useSearchParams } from 'next/navigation';
1717
import { Suspense, useState } from 'react';
1818
import { toast } from 'sonner';
1919
import { Button } from '@/components/ui/button';
@@ -31,6 +31,8 @@ import VisuallyHidden from '@/components/ui/visuallyhidden';
3131

3232
function RegisterPageContent() {
3333
const router = useRouter();
34+
const searchParams = useSearchParams();
35+
const selectedPlan = searchParams.get('plan');
3436
const [isLoading, setIsLoading] = useState(false);
3537
const [formData, setFormData] = useState({
3638
name: '',
@@ -85,6 +87,11 @@ function RegisterPageContent() {
8587
'Account created! Please check your email to verify your account.'
8688
);
8789
setRegistrationStep('verification-needed');
90+
91+
// Store plan selection for post-verification redirect
92+
if (selectedPlan) {
93+
localStorage.setItem('pendingPlanSelection', selectedPlan);
94+
}
8895
// router.push(`/verify?email=${encodeURIComponent(formData.email)}`);
8996
},
9097
},
@@ -129,8 +136,15 @@ function RegisterPageContent() {
129136
if (authToken) {
130137
localStorage.setItem('authToken', authToken);
131138
}
132-
toast.success('Login successful!');
133-
router.push('/home');
139+
toast.success('Registration successful!');
140+
141+
// Redirect to billing with plan selection if plan was specified
142+
if (selectedPlan) {
143+
localStorage.setItem('pendingPlanSelection', selectedPlan);
144+
router.push(`/billing?tab=plans&plan=${selectedPlan}`);
145+
} else {
146+
router.push('/home');
147+
}
134148
},
135149
onError: () => {
136150
toast.error('Login failed. Please try again.');

apps/dashboard/app/(main)/billing/components/plans-tab.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
import PricingTable from '@/components/autumn/pricing-table';
44

5-
export function PlansTab() {
6-
return <PricingTable />;
5+
interface PlansTabProps {
6+
selectedPlan?: string | null;
7+
}
8+
9+
export function PlansTab({ selectedPlan }: PlansTabProps) {
10+
return <PricingTable selectedPlan={selectedPlan} />;
711
}

apps/dashboard/app/(main)/billing/page.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export default function BillingPage() {
3434
const router = useRouter();
3535
const searchParams = useSearchParams();
3636
const activeTab = searchParams.get('tab') || 'overview';
37+
const selectedPlan = searchParams.get('plan');
3738

3839
const navigateToPlans = () => {
3940
router.push('/billing?tab=plans');
@@ -112,7 +113,7 @@ export default function BillingPage() {
112113
)}
113114
{activeTab === 'plans' && (
114115
<Suspense fallback={<ComponentSkeleton />}>
115-
<PlansTab />
116+
<PlansTab selectedPlan={selectedPlan} />
116117
</Suspense>
117118
)}
118119
{activeTab === 'history' && (

apps/dashboard/app/(main)/onboarding/page.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ import {
1111
SparkleIcon,
1212
UsersIcon,
1313
} from '@phosphor-icons/react';
14-
import { useState } from 'react';
14+
import { useRouter } from 'next/navigation';
15+
import { useEffect, useState } from 'react';
1516
import { CreateOrganizationDialog } from '@/components/organizations/create-organization-dialog';
1617
import { Badge } from '@/components/ui/badge';
1718
import { Button } from '@/components/ui/button';
@@ -209,6 +210,7 @@ function CompletionSection() {
209210
}
210211

211212
export default function OnboardingPage() {
213+
const router = useRouter();
212214
const [showCreateOrgDialog, setShowCreateOrgDialog] = useState(false);
213215
const [showCreateWebsiteDialog, setShowCreateWebsiteDialog] = useState(false);
214216

@@ -263,6 +265,15 @@ export default function OnboardingPage() {
263265
const currentStepIndex = steps.findIndex((step) => !step.completed);
264266
const allCompleted = currentStepIndex === -1;
265267

268+
// Check for pending plan selection and redirect to billing
269+
useEffect(() => {
270+
const pendingPlan = localStorage.getItem('pendingPlanSelection');
271+
if (pendingPlan && allCompleted) {
272+
localStorage.removeItem('pendingPlanSelection');
273+
router.push(`/billing?tab=plans&plan=${pendingPlan}`);
274+
}
275+
}, [allCompleted, router]);
276+
266277
return (
267278
<div className="container mx-auto max-w-4xl space-y-8 px-4 py-8">
268279
<WelcomeSection />

apps/dashboard/components/autumn/pricing-table.tsx

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,10 @@ const PricingTableSkeleton = () => (
3535

3636
export default function PricingTable({
3737
productDetails,
38+
selectedPlan,
3839
}: {
3940
productDetails?: ProductDetails[];
41+
selectedPlan?: string | null;
4042
}) {
4143
const { attach } = useCustomer();
4244
const [isAnnual, setIsAnnual] = useState(false);
@@ -158,6 +160,7 @@ export default function PricingTable({
158160
isAnnualToggle={isAnnual}
159161
multiInterval={multiInterval}
160162
products={products}
163+
selectedPlan={selectedPlan}
161164
setIsAnnualToggle={setIsAnnual}
162165
>
163166
{products
@@ -177,6 +180,7 @@ export default function PricingTable({
177180
? `Select recommended plan: ${plan.display?.name}`
178181
: `Select plan: ${plan.display?.name}`,
179182
}}
183+
isSelected={selectedPlan === plan.id}
180184
key={plan.id}
181185
productId={plan.id}
182186
/>
@@ -192,13 +196,15 @@ const PricingTableContext = createContext<{
192196
setIsAnnualToggle: (isAnnual: boolean) => void;
193197
products: Product[];
194198
showFeatures: boolean;
199+
selectedPlan?: string | null;
195200
}>({
196201
isAnnualToggle: false,
197202
setIsAnnualToggle: () => {
198203
throw new Error('setIsAnnualToggle is not implemented');
199204
},
200205
products: [],
201206
showFeatures: true,
207+
selectedPlan: null,
202208
});
203209

204210
export const usePricingTableContext = (componentName: string) => {
@@ -219,6 +225,7 @@ export const PricingTableContainer = ({
219225
isAnnualToggle,
220226
setIsAnnualToggle,
221227
multiInterval,
228+
selectedPlan,
222229
}: {
223230
children?: React.ReactNode;
224231
products?: Product[];
@@ -227,6 +234,7 @@ export const PricingTableContainer = ({
227234
isAnnualToggle: boolean;
228235
setIsAnnualToggle: (isAnnual: boolean) => void;
229236
multiInterval: boolean;
237+
selectedPlan?: string | null;
230238
}) => {
231239
if (!products) {
232240
throw new Error('products is required in <PricingTable />');
@@ -239,7 +247,13 @@ export const PricingTableContainer = ({
239247
const hasRecommended = products?.some((p) => p.display?.recommend_text);
240248
return (
241249
<PricingTableContext.Provider
242-
value={{ isAnnualToggle, setIsAnnualToggle, products, showFeatures }}
250+
value={{
251+
isAnnualToggle,
252+
setIsAnnualToggle,
253+
products,
254+
showFeatures,
255+
selectedPlan,
256+
}}
243257
>
244258
<div
245259
className={cn('flex flex-col items-center', hasRecommended && '!py-10')}
@@ -275,12 +289,14 @@ interface PricingCardProps {
275289
className?: string;
276290
onButtonClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
277291
buttonProps?: React.ComponentProps<'button'>;
292+
isSelected?: boolean;
278293
}
279294

280295
export const PricingCard = ({
281296
productId,
282297
className,
283298
buttonProps,
299+
isSelected = false,
284300
}: PricingCardProps) => {
285301
const { products, showFeatures } = usePricingTableContext('PricingCard');
286302

@@ -292,8 +308,17 @@ export const PricingCard = ({
292308

293309
const { name, display: productDisplay } = product;
294310

295-
const { buttonText } = getPricingTableContent(product);
311+
const { buttonText: defaultButtonText } = getPricingTableContent(product);
296312
const isRecommended = !!productDisplay?.recommend_text;
313+
const { selectedPlan } = usePricingTableContext('PricingCard');
314+
315+
// Customize button text for selected plans
316+
const buttonText =
317+
selectedPlan === productId ? (
318+
<span className="font-semibold">Complete Purchase →</span>
319+
) : (
320+
defaultButtonText
321+
);
297322
const mainPriceDisplay = product.properties?.is_free
298323
? {
299324
primary_text: 'Free',
@@ -345,6 +370,7 @@ export const PricingCard = ({
345370
'relative h-full w-full max-w-xl rounded-lg border py-6 text-foreground shadow-sm transition-all duration-300',
346371
isRecommended &&
347372
'lg:-translate-y-6 animate-recommended-glow border-primary bg-secondary/40 lg:h-[calc(100%+48px)] lg:shadow-lg dark:shadow-zinc-800/80',
373+
isSelected && 'border-primary bg-primary/5 ring-2 ring-primary/20',
348374
className
349375
)}
350376
>
@@ -360,9 +386,16 @@ export const PricingCard = ({
360386
<div className="h-full">
361387
<div className="flex flex-col">
362388
<div className="pb-4">
363-
<h2 className="truncate px-6 font-semibold text-2xl">
364-
{productDisplay?.name || name}
365-
</h2>
389+
<div className="flex items-center justify-between px-6">
390+
<h2 className="truncate font-semibold text-2xl">
391+
{productDisplay?.name || name}
392+
</h2>
393+
{isSelected && (
394+
<div className="ml-2 rounded-full bg-primary px-3 py-1 font-medium text-primary-foreground text-xs">
395+
Selected
396+
</div>
397+
)}
398+
</div>
366399
{productDisplay?.description && (
367400
<div className="h-8 px-6 text-muted-foreground text-sm">
368401
<p className="line-clamp-2">{productDisplay?.description}</p>
@@ -376,7 +409,7 @@ export const PricingCard = ({
376409
<div className="flex flex-col gap-1">
377410
<div className="flex items-center gap-2">
378411
<span className="text-muted-foreground text-xs line-through">
379-
$10.00
412+
$9.99
380413
</span>
381414
<span className="font-medium text-green-600">
382415
$2.00

apps/docs/app/(home)/pricing/_pricing/table.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export function PlansComparisonTable({ plans }: Props) {
4848
<div className="flex flex-col items-center gap-1">
4949
<div className="flex items-center gap-2">
5050
<span className="text-muted-foreground text-xs line-through">
51-
$10.00
51+
$9.99
5252
</span>
5353
<span className="font-medium text-green-600">
5454
$2.00
@@ -233,7 +233,7 @@ export function PlansComparisonTable({ plans }: Props) {
233233
>
234234
<SciFiButton asChild>
235235
<Link
236-
href="https://app.databuddy.cc/login"
236+
href={`https://app.databuddy.cc/register?plan=${p.id}`}
237237
rel="noopener noreferrer"
238238
target="_blank"
239239
>

0 commit comments

Comments
 (0)