website/hooks/useAuth.ts

179 lines
4.3 KiB
TypeScript

"use client";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { useRouter } from "next/navigation";
import { useCallback } from "react";
import {
loginUser,
registerUser,
verifyOtp,
resendOtp,
forgotPassword,
verifyPasswordResetOtp,
resetPassword,
refreshToken,
getStoredTokens,
getStoredUser,
storeTokens,
storeUser,
clearAuthData,
} from "@/lib/actions/auth";
import type {
LoginInput,
RegisterInput,
VerifyOtpInput,
ResendOtpInput,
ForgotPasswordInput,
VerifyPasswordResetOtpInput,
ResetPasswordInput,
} from "@/lib/schema/auth";
import type { User } from "@/lib/models/auth";
export function useAuth() {
const router = useRouter();
const queryClient = useQueryClient();
// Get current user from storage
const { data: user } = useQuery<User | null>({
queryKey: ["auth", "user"],
queryFn: () => getStoredUser(),
staleTime: Infinity,
});
// Check if user is authenticated
const isAuthenticated = !!user && !!getStoredTokens().access;
// Check if user is admin (check both is_admin and isAdmin)
const isAdmin = user?.is_admin === true || (user as any)?.isAdmin === true;
// Login mutation
const loginMutation = useMutation({
mutationFn: (input: LoginInput) => loginUser(input),
onSuccess: (data) => {
if (data.tokens && data.user) {
storeTokens(data.tokens);
storeUser(data.user);
queryClient.setQueryData(["auth", "user"], data.user);
queryClient.invalidateQueries({ queryKey: ["auth"] });
}
},
});
// Register mutation
const registerMutation = useMutation({
mutationFn: (input: RegisterInput) => registerUser(input),
});
// Verify OTP mutation
const verifyOtpMutation = useMutation({
mutationFn: (input: VerifyOtpInput) => verifyOtp(input),
onSuccess: (data) => {
if (data.tokens && data.user) {
storeTokens(data.tokens);
storeUser(data.user);
queryClient.setQueryData(["auth", "user"], data.user);
queryClient.invalidateQueries({ queryKey: ["auth"] });
}
},
});
// Resend OTP mutation
const resendOtpMutation = useMutation({
mutationFn: (input: ResendOtpInput) => resendOtp(input),
});
// Forgot password mutation
const forgotPasswordMutation = useMutation({
mutationFn: (input: ForgotPasswordInput) => forgotPassword(input),
});
// Verify password reset OTP mutation
const verifyPasswordResetOtpMutation = useMutation({
mutationFn: (input: VerifyPasswordResetOtpInput) => verifyPasswordResetOtp(input),
});
// Reset password mutation
const resetPasswordMutation = useMutation({
mutationFn: (input: ResetPasswordInput) => resetPassword(input),
});
// Refresh token mutation
const refreshTokenMutation = useMutation({
mutationFn: (refresh: string) => refreshToken({ refresh }),
onSuccess: (tokens) => {
storeTokens(tokens);
},
});
// Logout function
const logout = useCallback(() => {
clearAuthData();
queryClient.clear();
router.push("/login");
}, [queryClient, router]);
// Login function
const login = useCallback(
async (input: LoginInput) => {
try {
const result = await loginMutation.mutateAsync(input);
return result;
} catch (error) {
throw error;
}
},
[loginMutation]
);
// Register function
const register = useCallback(
async (input: RegisterInput) => {
try {
const result = await registerMutation.mutateAsync(input);
return result;
} catch (error) {
throw error;
}
},
[registerMutation]
);
// Verify OTP function
const verifyOtpCode = useCallback(
async (input: VerifyOtpInput) => {
try {
const result = await verifyOtpMutation.mutateAsync(input);
return result;
} catch (error) {
throw error;
}
},
[verifyOtpMutation]
);
return {
// State
user,
isAuthenticated,
isAdmin,
isLoading: loginMutation.isPending || registerMutation.isPending,
// Actions
login,
register,
logout,
verifyOtp: verifyOtpCode,
// Mutations (for direct access if needed)
loginMutation,
registerMutation,
verifyOtpMutation,
resendOtpMutation,
forgotPasswordMutation,
verifyPasswordResetOtpMutation,
resetPasswordMutation,
refreshTokenMutation,
};
}