Преглед изворни кода

redirect to subscription page (#35)

Bernt Christian Egeland пре 6 месеци
родитељ
комит
e8a785f6c1

+ 1 - 1
src/app/(public)/auth/sign-in/sign-in-form.tsx

@@ -152,7 +152,7 @@ function SignInFormInner({ registrationDisabled }: { registrationDisabled: boole
       {!registrationDisabled && (
         <p className="mt-6 text-center text-sm text-muted-foreground">
           {t('noAccount')}{' '}
-          <Link href="/auth/sign-up" className="font-medium text-primary hover:underline">
+          <Link href={`/auth/sign-up${searchParams.get('redirect') ? `?redirect=${encodeURIComponent(searchParams.get('redirect')!)}` : ''}`} className="font-medium text-primary hover:underline">
             {t('createOne')}
           </Link>
         </p>

+ 11 - 2
src/app/(public)/auth/sign-up/page.tsx

@@ -1,5 +1,7 @@
 import { redirect } from 'next/navigation'
+import { headers } from 'next/headers'
 import { db } from '@/lib/db'
+import { auth } from '@/lib/auth'
 import { SignUpForm } from './sign-up-form'
 
 export const dynamic = 'force-dynamic'
@@ -7,10 +9,17 @@ export const dynamic = 'force-dynamic'
 export default async function SignUpPage({
   searchParams,
 }: {
-  searchParams: Promise<{ invite?: string }>
+  searchParams: Promise<{ invite?: string; redirect?: string }>
 }) {
   const params = await searchParams
   const inviteToken = params.invite
+  const redirectTo = params.redirect
+
+  // If already authenticated, redirect to the target or home
+  const session = await auth.api.getSession({ headers: await headers() })
+  if (session?.user?.id) {
+    redirect(redirectTo || '/')
+  }
 
   // If there's an invite token, skip the registration-disabled check
   if (!inviteToken) {
@@ -30,5 +39,5 @@ export default async function SignUpPage({
   })
   const emailVerificationRequired = verificationSetting?.value === 'true'
 
-  return <SignUpForm inviteToken={inviteToken} emailVerificationRequired={emailVerificationRequired} />
+  return <SignUpForm inviteToken={inviteToken} emailVerificationRequired={emailVerificationRequired} redirectTo={redirectTo} />
 }

+ 4 - 4
src/app/(public)/auth/sign-up/sign-up-form.tsx

@@ -11,7 +11,7 @@ import { Label } from '@/components/ui/label'
 import { Gauge, Loader2, XCircle } from 'lucide-react'
 import { acceptInvitation } from '@/features/team/Actions/acceptInvitation'
 
-export function SignUpForm({ inviteToken, emailVerificationRequired }: { inviteToken?: string; emailVerificationRequired?: boolean }) {
+export function SignUpForm({ inviteToken, emailVerificationRequired, redirectTo }: { inviteToken?: string; emailVerificationRequired?: boolean; redirectTo?: string }) {
   const t = useTranslations('auth.signUp')
   const tc = useTranslations('common')
   const [name, setName] = useState('')
@@ -43,18 +43,18 @@ export function SignUpForm({ inviteToken, emailVerificationRequired }: { inviteT
         const acceptResult = await acceptInvitation({ token: inviteToken })
         if (acceptResult.success) {
           // Invited users have a known email — skip verification, go straight to dashboard
-          router.push('/')
+          router.push(redirectTo || '/')
           router.refresh()
         } else {
           setError(acceptResult.error || t('errors.invitationFailed'))
-          router.push('/onboarding')
+          router.push(redirectTo ? `/onboarding?redirect=${encodeURIComponent(redirectTo)}` : '/onboarding')
           router.refresh()
         }
       } else if (emailVerificationRequired) {
         router.push('/auth/verify-email')
         router.refresh()
       } else {
-        router.push('/onboarding')
+        router.push(redirectTo ? `/onboarding?redirect=${encodeURIComponent(redirectTo)}` : '/onboarding')
         router.refresh()
       }
     } catch {

+ 8 - 2
src/app/(public)/onboarding/page.tsx

@@ -4,7 +4,13 @@ import { auth } from "@/lib/auth";
 import { db } from "@/lib/db";
 import { OnboardingForm } from "@/features/onboarding/Components/OnboardingForm";
 
-export default async function OnboardingPage() {
+export default async function OnboardingPage({
+  searchParams,
+}: {
+  searchParams: Promise<{ redirect?: string }>
+}) {
+  const params = await searchParams
+  const redirectTo = params.redirect
   const session = await auth.api.getSession({ headers: await headers() });
 
   if (!session?.user?.id) {
@@ -27,7 +33,7 @@ export default async function OnboardingPage() {
         <div className="absolute -top-40 -right-40 h-96 w-96 rounded-full bg-primary/10 blur-3xl" />
         <div className="absolute -bottom-40 -left-40 h-96 w-96 rounded-full bg-primary/5 blur-3xl" />
       </div>
-      <OnboardingForm />
+      <OnboardingForm redirectTo={redirectTo} />
     </div>
   );
 }

+ 2 - 2
src/features/onboarding/Components/OnboardingForm.tsx

@@ -9,7 +9,7 @@ import { useGlassModal } from "@/components/glass-modal";
 import { Gauge, Loader2 } from "lucide-react";
 import { createOnboardingOrg } from "../Actions/createOnboardingOrg";
 
-export function OnboardingForm() {
+export function OnboardingForm({ redirectTo }: { redirectTo?: string }) {
   const [workshopName, setWorkshopName] = useState("");
   const [loading, setLoading] = useState(false);
   const router = useRouter();
@@ -24,7 +24,7 @@ export function OnboardingForm() {
       if (!result.success) {
         modal.open("error", "Setup Failed", result.error || "Could not create workshop");
       } else {
-        router.push("/");
+        router.push(redirectTo || "/");
         router.refresh();
       }
     } catch {