diff --git a/apps/web/public/locales/en/auth.json b/apps/web/public/locales/en/auth.json index 18d879b1d..1da985cf3 100644 --- a/apps/web/public/locales/en/auth.json +++ b/apps/web/public/locales/en/auth.json @@ -76,6 +76,7 @@ "methodMagicLink": "email link", "methodOauth": "social sign-in", "methodOauthWithProvider": "{{provider}}", + "methodDefault": "another method", "existingAccountHint": "You previously signed in with {{method}}. Already have an account?", "errors": { "Invalid login credentials": "The credentials entered are invalid", diff --git a/packages/features/auth/src/components/existing-account-hint.tsx b/packages/features/auth/src/components/existing-account-hint.tsx index 9e043b404..281b94636 100644 --- a/packages/features/auth/src/components/existing-account-hint.tsx +++ b/packages/features/auth/src/components/existing-account-hint.tsx @@ -4,6 +4,7 @@ import { useMemo } from 'react'; import dynamic from 'next/dynamic'; import Link from 'next/link'; +import { useSearchParams } from 'next/navigation'; import { UserCheck } from 'lucide-react'; @@ -33,6 +34,14 @@ export function ExistingAccountHintImpl({ const { hasLastMethod, methodType, providerName, isOAuth } = useLastAuthMethod(); + const params = useSearchParams(); + + const isInvite = params.get('invite_token'); + + if (isInvite) { + signInPath = signInPath + '?invite_token=' + isInvite; + } + // Get the appropriate method description for the hint // This must be called before any conditional returns to follow Rules of Hooks const methodDescription = useMemo(() => { @@ -42,13 +51,13 @@ export function ExistingAccountHintImpl({ switch (methodType) { case 'password': - return 'email and password'; + return 'auth:methodPassword'; case 'otp': - return 'email verification'; + return 'auth:methodOtp'; case 'magic_link': - return 'email link'; + return 'auth:methodMagicLink'; default: - return 'another method'; + return 'auth:methodDefault'; } }, [methodType, isOAuth, providerName]); diff --git a/packages/features/auth/src/components/otp-sign-in-container.tsx b/packages/features/auth/src/components/otp-sign-in-container.tsx index 3f0883a9b..7890eb60f 100644 --- a/packages/features/auth/src/components/otp-sign-in-container.tsx +++ b/packages/features/auth/src/components/otp-sign-in-container.tsx @@ -34,17 +34,16 @@ import { AuthErrorAlert } from './auth-error-alert'; const EmailSchema = z.object({ email: z.string().email() }); const OtpSchema = z.object({ token: z.string().min(6).max(6) }); -export function OtpSignInContainer({ - onSignIn, - shouldCreateUser, -}: { - onSignIn?: (userId?: string) => void; +type OtpSignInContainerProps = { shouldCreateUser: boolean; -}) { + inviteToken?: string; +}; + +export function OtpSignInContainer(props: OtpSignInContainerProps) { const verifyMutation = useVerifyOtp(); const router = useRouter(); - const params = useSearchParams(); const { recordAuthMethod } = useLastAuthMethod(); + const params = useSearchParams(); const otpForm = useForm({ resolver: zodResolver(OtpSchema.merge(EmailSchema)), @@ -61,6 +60,9 @@ export function OtpSignInContainer({ const isEmailStep = !email; + const shouldCreateUser = + 'shouldCreateUser' in props && props.shouldCreateUser; + const handleVerifyOtp = async ({ token, email, @@ -68,7 +70,7 @@ export function OtpSignInContainer({ token: string; email: string; }) => { - const result = await verifyMutation.mutateAsync({ + await verifyMutation.mutateAsync({ type: 'email', email, token, @@ -77,14 +79,18 @@ export function OtpSignInContainer({ // Record successful OTP sign-in recordAuthMethod('otp', { email }); - if (onSignIn) { - return onSignIn(result?.user?.id); - } + // on sign ups we redirect to the app home + const inviteToken = props.inviteToken; + const next = params.get('next') ?? '/home'; - // on sign ups we redirect to the app home - if (shouldCreateUser) { - const next = params.get('next') ?? '/home'; + if (inviteToken) { + const params = new URLSearchParams({ + invite_token: inviteToken, + next, + }); + router.replace(`/join?${params.toString()}`); + } else { router.replace(next); } }; diff --git a/packages/features/auth/src/components/sign-in-methods-container.tsx b/packages/features/auth/src/components/sign-in-methods-container.tsx index 51772e318..475952218 100644 --- a/packages/features/auth/src/components/sign-in-methods-container.tsx +++ b/packages/features/auth/src/components/sign-in-methods-container.tsx @@ -74,7 +74,10 @@ export function SignInMethodsContainer(props: { - + diff --git a/packages/features/auth/src/components/sign-up-methods-container.tsx b/packages/features/auth/src/components/sign-up-methods-container.tsx index a11d552a0..38b949240 100644 --- a/packages/features/auth/src/components/sign-up-methods-container.tsx +++ b/packages/features/auth/src/components/sign-up-methods-container.tsx @@ -51,7 +51,10 @@ export function SignUpMethodsContainer(props: { - + diff --git a/packages/features/auth/src/hooks/use-sign-up-flow.ts b/packages/features/auth/src/hooks/use-sign-up-flow.ts index 88f182bbd..cda3427c9 100644 --- a/packages/features/auth/src/hooks/use-sign-up-flow.ts +++ b/packages/features/auth/src/hooks/use-sign-up-flow.ts @@ -87,6 +87,7 @@ export function usePasswordSignUpFlow({ router, onSignUp, resetCaptchaToken, + recordAuthMethod, ], );