Add OTP sign-in option + Account Linking (#276)
* feat(accounts): allow linking email password * feat(auth): add OTP sign-in * refactor(accounts): remove 'sonner' dependency and update toast imports * feat(supabase): enable analytics and configure database seeding * feat(auth): update email templates and add OTP template * feat(auth): add last sign in method hints * feat(config): add devIndicators position to bottom-right * feat(auth): implement comprehensive last authentication method tracking tests
This commit is contained in:
committed by
GitHub
parent
856e9612c4
commit
9033155fcd
78
packages/features/auth/src/hooks/use-last-auth-method.ts
Normal file
78
packages/features/auth/src/hooks/use-last-auth-method.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
'use client';
|
||||
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
|
||||
import type { AuthMethod, LastAuthMethod } from '../utils/last-auth-method';
|
||||
import {
|
||||
clearLastAuthMethod,
|
||||
getLastAuthMethod,
|
||||
saveLastAuthMethod,
|
||||
} from '../utils/last-auth-method';
|
||||
|
||||
export function useLastAuthMethod() {
|
||||
const [lastAuthMethod, setLastAuthMethod] = useState<LastAuthMethod | null>(
|
||||
getLastAuthMethod(),
|
||||
);
|
||||
|
||||
// Save a new auth method - memoized to prevent unnecessary re-renders
|
||||
const recordAuthMethod = useCallback(
|
||||
(
|
||||
method: AuthMethod,
|
||||
options?: {
|
||||
provider?: string;
|
||||
email?: string;
|
||||
},
|
||||
) => {
|
||||
const authMethod: LastAuthMethod = {
|
||||
method,
|
||||
provider: options?.provider,
|
||||
email: options?.email,
|
||||
timestamp: Date.now(),
|
||||
};
|
||||
|
||||
saveLastAuthMethod(authMethod);
|
||||
setLastAuthMethod(authMethod);
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
// Clear the stored auth method - memoized to prevent unnecessary re-renders
|
||||
const clearAuthMethod = useCallback(() => {
|
||||
clearLastAuthMethod();
|
||||
setLastAuthMethod(null);
|
||||
}, []);
|
||||
|
||||
// Compute derived values using useMemo for performance
|
||||
const derivedData = useMemo(() => {
|
||||
if (!lastAuthMethod) {
|
||||
return {
|
||||
hasLastMethod: false,
|
||||
methodType: null,
|
||||
providerName: null,
|
||||
isOAuth: false,
|
||||
};
|
||||
}
|
||||
|
||||
const isOAuth = lastAuthMethod.method === 'oauth';
|
||||
|
||||
const providerName =
|
||||
isOAuth && lastAuthMethod.provider
|
||||
? lastAuthMethod.provider.charAt(0).toUpperCase() +
|
||||
lastAuthMethod.provider.slice(1)
|
||||
: null;
|
||||
|
||||
return {
|
||||
hasLastMethod: true,
|
||||
methodType: lastAuthMethod.method,
|
||||
providerName,
|
||||
isOAuth,
|
||||
};
|
||||
}, [lastAuthMethod]);
|
||||
|
||||
return {
|
||||
lastAuthMethod,
|
||||
recordAuthMethod,
|
||||
clearAuthMethod,
|
||||
...derivedData,
|
||||
};
|
||||
}
|
||||
@@ -7,6 +7,8 @@ import { useRouter } from 'next/navigation';
|
||||
import { useAppEvents } from '@kit/shared/events';
|
||||
import { useSignUpWithEmailAndPassword } from '@kit/supabase/hooks/use-sign-up-with-email-password';
|
||||
|
||||
import { useLastAuthMethod } from './use-last-auth-method';
|
||||
|
||||
type SignUpCredentials = {
|
||||
email: string;
|
||||
password: string;
|
||||
@@ -33,6 +35,7 @@ export function usePasswordSignUpFlow({
|
||||
const router = useRouter();
|
||||
const signUpMutation = useSignUpWithEmailAndPassword();
|
||||
const appEvents = useAppEvents();
|
||||
const { recordAuthMethod } = useLastAuthMethod();
|
||||
|
||||
const signUp = useCallback(
|
||||
async (credentials: SignUpCredentials) => {
|
||||
@@ -47,6 +50,9 @@ export function usePasswordSignUpFlow({
|
||||
captchaToken,
|
||||
});
|
||||
|
||||
// Record last auth method
|
||||
recordAuthMethod('password', { email: credentials.email });
|
||||
|
||||
// emit event to track sign up
|
||||
appEvents.emit({
|
||||
type: 'user.signedUp',
|
||||
@@ -58,6 +64,7 @@ export function usePasswordSignUpFlow({
|
||||
// Update URL with success status. This is useful for password managers
|
||||
// to understand that the form was submitted successfully.
|
||||
const url = new URL(window.location.href);
|
||||
|
||||
url.searchParams.set('status', 'success');
|
||||
router.replace(url.pathname + url.search);
|
||||
|
||||
@@ -66,6 +73,7 @@ export function usePasswordSignUpFlow({
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
||||
throw error;
|
||||
} finally {
|
||||
resetCaptchaToken?.();
|
||||
|
||||
Reference in New Issue
Block a user