177 lines
5.2 KiB
TypeScript
177 lines
5.2 KiB
TypeScript
import { AuthenticationError } from "@/src/entities/errors/auth";
|
|
import { useState } from "react";
|
|
import { useAuthActions } from "./mutation";
|
|
import { useForm } from "react-hook-form";
|
|
import { zodResolver } from "@hookform/resolvers/zod";
|
|
import { defaultSignInPasswordlessValues, SignInFormData, SignInPasswordless, SignInPasswordlessSchema, SignInSchema } from "@/src/entities/models/auth/sign-in.model";
|
|
import { createFormData } from "@/app/_utils/common";
|
|
import { useFormHandler } from "@/app/_hooks/use-form-handler";
|
|
import { toast } from "sonner";
|
|
import { signIn } from "./action";
|
|
import { useNavigations } from "@/app/_hooks/use-navigations";
|
|
import { VerifyOtpFormData, verifyOtpSchema } from "@/src/entities/models/auth/verify-otp.model";
|
|
|
|
/**
|
|
* Hook untuk menangani proses sign in
|
|
*
|
|
* @returns {Object} Object berisi handler dan state untuk form sign in
|
|
* @example
|
|
* const { handleSubmit, isPending, error } = useSignInHandler();
|
|
* <form onSubmit={handleSubmit}>...</form>
|
|
*/
|
|
export function useSignInHandler() {
|
|
const { signIn } = useAuthActions();
|
|
const { router } = useNavigations();
|
|
|
|
const [error, setError] = useState<string>();
|
|
|
|
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
|
|
event.preventDefault();
|
|
if (signIn.isPending) return;
|
|
|
|
setError(undefined);
|
|
|
|
const formData = new FormData(event.currentTarget);
|
|
const email = formData.get("email")?.toString()
|
|
|
|
try {
|
|
await signIn.mutateAsync(formData, {
|
|
onSuccess: () => {
|
|
toast("An email has been sent to you. Please check your inbox.");
|
|
if (email) router.push(`/verify-otp?email=${encodeURIComponent(email)}`);
|
|
},
|
|
onError: (error) => {
|
|
setError(error.message);
|
|
}
|
|
});
|
|
} catch (error) {
|
|
if (error instanceof Error) {
|
|
setError(error.message);
|
|
}
|
|
}
|
|
};
|
|
|
|
return {
|
|
// formData,
|
|
// handleChange,
|
|
handleSignIn: handleSubmit,
|
|
error,
|
|
isPending: signIn.isPending,
|
|
errors: !!error || signIn.error,
|
|
clearError: () => setError(undefined)
|
|
};
|
|
}
|
|
|
|
|
|
|
|
export function useVerifyOtpHandler(email: string) {
|
|
const { router } = useNavigations()
|
|
const { verifyOtp } = useAuthActions()
|
|
const [error, setError] = useState<string>()
|
|
|
|
const {
|
|
register,
|
|
handleSubmit: hookFormSubmit,
|
|
control,
|
|
formState: { errors },
|
|
setValue
|
|
} = useForm<VerifyOtpFormData>({
|
|
resolver: zodResolver(verifyOtpSchema),
|
|
defaultValues: {
|
|
email,
|
|
token: ""
|
|
}
|
|
})
|
|
|
|
const handleOtpChange = (value: string, onChange: (value: string) => void) => {
|
|
onChange(value)
|
|
|
|
// Clear error when user starts typing
|
|
if (error) {
|
|
setError(undefined)
|
|
}
|
|
}
|
|
|
|
const handleSubmit = hookFormSubmit(async (data) => {
|
|
if (verifyOtp.isPending) return
|
|
|
|
setError(undefined)
|
|
|
|
// Create FormData object
|
|
const formData = new FormData()
|
|
formData.append("email", data.email)
|
|
formData.append("token", data.token)
|
|
|
|
try {
|
|
await verifyOtp.mutateAsync(formData, {
|
|
onSuccess: () => {
|
|
toast.success("OTP verified successfully")
|
|
// Navigate to dashboard on success
|
|
router.push("/dashboard")
|
|
},
|
|
onError: (error) => {
|
|
setError(error.message)
|
|
}
|
|
})
|
|
} catch (error) {
|
|
if (error instanceof Error) {
|
|
setError(error.message)
|
|
}
|
|
}
|
|
})
|
|
|
|
return {
|
|
register,
|
|
control,
|
|
handleVerifyOtp: handleSubmit,
|
|
handleOtpChange,
|
|
errors: {
|
|
...errors,
|
|
token: error ? { message: error } : errors.token
|
|
},
|
|
isPending: verifyOtp.isPending,
|
|
clearError: () => setError(undefined)
|
|
}
|
|
}
|
|
|
|
export function useSignOutHandler() {
|
|
const { signOut } = useAuthActions()
|
|
const { router } = useNavigations()
|
|
const [error, setError] = useState<string>()
|
|
|
|
const handleSignOut = async () => {
|
|
if (signOut.isPending) return
|
|
|
|
setError(undefined)
|
|
|
|
try {
|
|
await signOut.mutateAsync(undefined, {
|
|
onSuccess: () => {
|
|
toast.success("You have been signed out successfully")
|
|
router.push("/sign-in")
|
|
},
|
|
onError: (error) => {
|
|
if (error instanceof AuthenticationError) {
|
|
setError(error.message)
|
|
toast.error(error.message)
|
|
}
|
|
}
|
|
})
|
|
} catch (error) {
|
|
if (error instanceof Error) {
|
|
setError(error.message)
|
|
toast.error(error.message)
|
|
// toast.error("An error occurred during sign out. Please try again later.")
|
|
}
|
|
}
|
|
}
|
|
|
|
return {
|
|
handleSignOut,
|
|
error,
|
|
isPending: signOut.isPending,
|
|
errors: !!error || signOut.error,
|
|
clearError: () => setError(undefined)
|
|
}
|
|
}
|