login-form
This code defines a login form component using React, Next.js, and several libraries such as react-hook-form, Zod, and Framer Motion. The form accepts user credentials (SID and PIN), sends an authentication request, and manages the login state.
Key Features and Breakdown:
1. Component Setup:
State Management (useState):
const [isLoading, setIsLoading] = useState(false);
The isLoading state is used to manage the loading indicator during the login process, preventing multiple submissions and providing a visual cue to the user.
isLoadingis used to manage the loading state of the form during the login process (shows a loading indicator or disables the button).
Form Handling (react-hook-form and zod):
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
sid: "",
pin: "",
},
});
The form is managed using react-hook-form for state management and Zod for schema validation. This combination ensures smooth validation and form handling.
- The form state and validation are managed using react-hook-form and Zod. The
zodResolverintegrates Zod schema validation into the form.
Zod Schema Validation:
const formSchema = z.object({
sid: z.string().regex(/^\d{6}$/, {message: "User ID must be a 6-digit numeric code."}).min(1, {message: "Please enter a valid user ID."}),
pin: z.string().max(4).min(4, {"message": "pin must be min 4 digits long"}),
});
Ensure that the sid field is strictly validated to be exactly 6 digits, and the pin field must be a 4-digit number. This prevents potential errors from invalid data.
- The schema validates:
sid: A 6-digit user ID.pin: A 4-digit numeric pin.
Input OTP (One-Time Password):
<InputOTP maxLength={4} {...field} pattern={REGEXP_ONLY_DIGITS}>
<InputOTPGroup>
<InputOTPSlot index={0}/>
<InputOTPSlot index={1}/>
<InputOTPSlot index={2}/>
<InputOTPSlot index={3}/>
</InputOTPGroup>
</InputOTP>
The OTP input is implemented using InputOTP, where each digit is separated into individual slots. This creates a smooth UX for PIN entry.
- This custom component handles OTP (one-time password) input using
InputOTP, where each digit is entered separately in individual slots.
2. Login Flow:
Form Submission (onSubmit function):
async function onSubmit(values: z.infer<typeof formSchema>) {
setIsLoading(true);
let json: Record<string, unknown> = {};
let username = "";
try {
await new Promise((resolve) => setTimeout(resolve, 1000)); // Simulate delay
// Authentication API call
const response = await fetch(apilink + '/trylogUser', {
method: 'GET',
headers: {
'accept': 'application/json',
'sid': values.sid,
'pin': values.pin
}
});
// Handle success or failure
if (response.status !== 200) throw new Error("Invalid credentials");
const response2 = await fetch(apilink + '/getUser', {
method: 'GET',
headers: {
'accept': 'application/json',
'sid': values.sid,
'pin': values.pin
}
});
json = await response2.json();
username = (json.data as { fullname: string }).fullname;
if (response2.status !== 200) throw new Error("Error getting name");
// Toast on successful login
toast({
title: "Login Successful",
description: "You have been logged in successfully, " + username
});
// Store credentials and username as cookies
document.cookie = `user=${JSON.stringify(values)}; max-age=${3 * 60 * 60}; path=/`;
document.cookie = `name=${JSON.stringify(username)}; max-age=${3 * 60 * 60}; path=/`;
// Trigger page refresh
router.refresh();
} catch {
toast({
title: "Login Failed",
description: "There was an error logging in. Please try again.",
variant: "destructive",
});
} finally {
setIsLoading(false);
}
}
The onSubmit function handles the form submission, validates the credentials, manages the login process, and handles success/failure with appropriate feedback. Make sure to handle errors properly to guide users effectively.
-
Authentication Process:
- The form submits
sid(user ID) andpin(PIN) to the API for validation. - If valid, the user’s name is fetched and stored in cookies along with login credentials.
- The form submits
-
Error Handling:
- If the credentials are invalid or if there's an error, a toast notification is shown to inform the user.
-
Cookie Management:
- The login credentials and username are stored in cookies (
document.cookie), making them accessible on the client-side for subsequent requests.
- The login credentials and username are stored in cookies (
-
Page Refresh:
- After a successful login, the
router.refresh()is called to trigger a re-render or refresh the current page.
- After a successful login, the
3. Component Rendering (Form UI):
Form Layout:
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
<FormField control={form.control} name="sid" render={({field}) => (
<FormItem>
<FormLabel>Names</FormLabel>
<FormControl>
<Input placeholder="0XXXXX" {...field} />
</FormControl>
<FormDescription>
Enter your name.
</FormDescription>
<FormMessage/>
</FormItem>
)} />
<FormField control={form.control} name="pin" render={({field}) => (
<FormItem>
<FormLabel>
<div className="flex justify-between">
<span>Pin</span>
<span className="text-sm text-gray-500 dark:text-gray-400">4 digits</span>
</div>
</FormLabel>
<FormControl>
<div className="flex justify-center">
<InputOTP maxLength={4} {...field} pattern={REGEXP_ONLY_DIGITS}>
<InputOTPGroup>
<InputOTPSlot index={0}/>
<InputOTPSlot index={1}/>
<InputOTPSlot index={2}/>
<InputOTPSlot index={3}/>
</InputOTPGroup>
</InputOTP>
</div>
</FormControl>
<FormDescription>
Please enter the code that you found in the envelope.
</FormDescription>
<FormMessage/>
</FormItem>
)} />
<Button type="submit" className="w-full" disabled={isLoading}>
{isLoading ? "Logging in..." : "Log in"}
</Button>
</form>
</Form>
Ensure that the button is disabled while the form is loading, preventing multiple submissions. The loading state helps avoid errors caused by user impatience.
-
Form Fields:
sid(user ID) andpin(4-digit PIN) fields are rendered.InputOTPis used for entering the PIN, broken into individual slots for each digit.
-
Button:
- The button is disabled when the form is in a loading state (e.g., while waiting for API responses).
Summary:
This code implements a login form that:
- Collects a 6-digit user ID (
sid) and a 4-digit PIN (pin). - Sends the credentials to an API for validation and fetches the user's full name.
- Stores login information in cookies.
- Uses
react-hook-formfor managing form state andZodfor schema validation. - Displays toast notifications for success or failure.
The form also provides a custom OTP input (InputOTP) for entering the PIN, enhancing the UX by separating each digit in its own input slot.