mirror of
https://github.com/andwati/telecom-platform.git
synced 2026-10-18 11:02:54 +00:00
feat: Add login/register page with form validation and token persistence
- Add LoginPage component with toggle between login and registration modes - Add form state management for username, password, email, first_name, last_name fields - Add handleSubmit with api.auth.login/register integration and token storage (access_token, refresh_token) - Add error handling with red alert banner display - Add conditional rendering for registration fields (email, first_name, last_name) - Add loading state with
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { api, setAuthToken, type LoginRequest, type RegisterRequest } from "@/lib/api";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
|
||||
export default function LoginPage() {
|
||||
const router = useRouter();
|
||||
const [isLogin, setIsLogin] = useState(true);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
|
||||
const [formData, setFormData] = useState<LoginRequest | RegisterRequest>({
|
||||
username: "",
|
||||
password: "",
|
||||
});
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setLoading(true);
|
||||
setError("");
|
||||
|
||||
try {
|
||||
if (isLogin) {
|
||||
const response = await api.auth.login(formData as LoginRequest);
|
||||
setAuthToken(response.access_token);
|
||||
localStorage.setItem("refresh_token", response.refresh_token);
|
||||
router.push("/");
|
||||
} else {
|
||||
const response = await api.auth.register(formData as RegisterRequest);
|
||||
setAuthToken(response.access_token);
|
||||
localStorage.setItem("refresh_token", response.refresh_token);
|
||||
router.push("/");
|
||||
}
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : "Authentication failed");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen flex items-center justify-center bg-gray-50">
|
||||
<div className="max-w-md w-full bg-white rounded-lg shadow-md p-8">
|
||||
<h1 className="text-2xl font-bold text-center mb-6">
|
||||
{isLogin ? "Login" : "Register"}
|
||||
</h1>
|
||||
|
||||
{error && (
|
||||
<div className="mb-4 p-3 bg-red-100 border border-red-400 text-red-700 rounded">
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<form onSubmit={handleSubmit} className="space-y-4">
|
||||
<div>
|
||||
<label htmlFor="username" className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Username
|
||||
</label>
|
||||
<Input
|
||||
id="username"
|
||||
type="text"
|
||||
value={formData.username}
|
||||
onChange={(e) => setFormData({ ...formData, username: e.target.value })}
|
||||
required
|
||||
className="w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{!isLogin && (
|
||||
<>
|
||||
<div>
|
||||
<label htmlFor="email" className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Email
|
||||
</label>
|
||||
<Input
|
||||
id="email"
|
||||
type="email"
|
||||
value={(formData as RegisterRequest).email || ""}
|
||||
onChange={(e) => setFormData({ ...formData as RegisterRequest, email: e.target.value })}
|
||||
required={!isLogin}
|
||||
className="w-full"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="firstName" className="block text-sm font-medium text-gray-700 mb-1">
|
||||
First Name
|
||||
</label>
|
||||
<Input
|
||||
id="firstName"
|
||||
type="text"
|
||||
value={(formData as RegisterRequest).first_name || ""}
|
||||
onChange={(e) => setFormData({ ...formData as RegisterRequest, first_name: e.target.value })}
|
||||
required={!isLogin}
|
||||
className="w-full"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="lastName" className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Last Name
|
||||
</label>
|
||||
<Input
|
||||
id="lastName"
|
||||
type="text"
|
||||
value={(formData as RegisterRequest).last_name || ""}
|
||||
onChange={(e) => setFormData({ ...formData as RegisterRequest, last_name: e.target.value })}
|
||||
required={!isLogin}
|
||||
className="w-full"
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<label htmlFor="password" className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Password
|
||||
</label>
|
||||
<Input
|
||||
id="password"
|
||||
type="password"
|
||||
value={formData.password}
|
||||
onChange={(e) => setFormData({ ...formData, password: e.target.value })}
|
||||
required
|
||||
className="w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Button type="submit" disabled={loading} className="w-full">
|
||||
{loading ? "Loading..." : isLogin ? "Login" : "Register"}
|
||||
</Button>
|
||||
</form>
|
||||
|
||||
<div className="mt-4 text-center">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
setIsLogin(!isLogin);
|
||||
setError("");
|
||||
setFormData({ username: "", password: "" });
|
||||
}}
|
||||
className="text-blue-600 hover:underline"
|
||||
>
|
||||
{isLogin ? "Need an account? Register" : "Already have an account? Login"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user