Component Details

Auth Component 01

Auth Component 01

LoginPage.tsx

Next.jsTailwind CSS
1// app/auth/login/page.tsx
2"use client";
3
4import type React from "react";
5import { useState } from "react";
6import { useRouter } from "next/navigation";
7import Link from "next/link";
8import { Button } from "@/components/ui/button";
9import { Input } from "@/components/ui/input";
10import {
11  Card,
12  CardContent,
13  CardHeader,
14  CardTitle,
15  CardDescription,
16} from "@/components/ui/card";
17import { Alert, AlertDescription } from "@/components/ui/alert";
18import { Checkbox } from "@/components/ui/checkbox";
19import { Label } from "@/components/ui/label";
20import {
21  AlertCircle,
22  Loader2,
23  LogIn,
24  Eye,
25  EyeOff,
26  Mail,
27  Lock,
28} from "lucide-react";
29
30export default function LoginPage() {
31  const [email, setEmail] = useState("");
32  const [password, setPassword] = useState("");
33  const [rememberMe, setRememberMe] = useState(false);
34  const [error, setError] = useState("");
35  const [isLoading, setIsLoading] = useState(false);
36  const [showPassword, setShowPassword] = useState(false);
37  const router = useRouter();
38
39  // Demo credentials for easy testing
40  const demoCredentials = {
41    email: "demo@example.com",
42    password: "demo123",
43  };
44
45  const handleLogin = async (e: React.FormEvent) => {
46    e.preventDefault();
47    setError("");
48    setIsLoading(true);
49
50    // Simulate API call delay
51    await new Promise((resolve) => setTimeout(resolve, 800));
52
53    // Basic validation
54    if (!email.trim()) {
55      setError("Please enter your email address");
56      setIsLoading(false);
57      return;
58    }
59
60    if (!password.trim()) {
61      setError("Please enter your password");
62      setIsLoading(false);
63      return;
64    }
65
66    // Email format validation
67    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
68    if (!emailRegex.test(email)) {
69      setError("Please enter a valid email address");
70      setIsLoading(false);
71      return;
72    }
73
74    // Demo validation - accept demo credentials or any valid email
75    const isDemoLogin =
76      email === demoCredentials.email && password === demoCredentials.password;
77
78    if (isDemoLogin || (emailRegex.test(email) && password)) {
79      // Store demo session in localStorage
80      localStorage.setItem(
81        "userSession",
82        JSON.stringify({
83          email: email,
84          name: email.split("@")[0], // Extract name from email
85          isAuthenticated: true,
86          timestamp: new Date().toISOString(),
87        })
88      );
89
90      // Store remember me preference
91      if (rememberMe) {
92        localStorage.setItem("rememberMe", "true");
93        localStorage.setItem("userEmail", email);
94      } else {
95        localStorage.removeItem("userEmail");
96      }
97
98      // Redirect to home page
99      router.push("/");
100    } else {
101      setError("Invalid credentials. Try demo@example.com / demo123");
102      setPassword("");
103    }
104
105    setIsLoading(false);
106  };
107
108  const handleDemoLogin = () => {
109    setEmail(demoCredentials.email);
110    setPassword(demoCredentials.password);
111    setRememberMe(true);
112  };
113
114  return (
115    <div className="flex flex-col">
116      <main className="flex-1 flex items-center justify-center px-4 py-12">
117        <div className="w-full max-w-md">
118          <div className="text-center mb-8">
119            <h1 className="text-3xl font-bold mb-2">Welcome back</h1>
120            <p className="text-muted-foreground">
121              Sign in to your account to continue
122            </p>
123          </div>
124
125          <Card className="border shadow-sm">
126            <CardHeader className="space-y-1">
127              <CardTitle className="text-2xl">Sign in</CardTitle>
128              <CardDescription>
129                Enter your credentials to access your account
130              </CardDescription>
131            </CardHeader>
132
133            <CardContent>
134              <form onSubmit={handleLogin} className="space-y-4">
135                <div className="space-y-2">
136                  <Label htmlFor="email">Email address</Label>
137                  <div className="relative">
138                    <Mail className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
139                    <Input
140                      id="email"
141                      type="email"
142                      placeholder="name@example.com"
143                      className="pl-10"
144                      value={email}
145                      onChange={(e) => setEmail(e.target.value)}
146                      disabled={isLoading}
147                      autoComplete="email"
148                    />
149                  </div>
150                </div>
151
152                <div className="space-y-2">
153                  <div className="flex items-center justify-between">
154                    <Label htmlFor="password">Password</Label>
155                    <Link
156                      href="/forgot-password"
157                      className="text-sm text-primary hover:underline"
158                      // onClick={(e) => {
159                      //   e.preventDefault();
160                      //   setError(
161                      //     "Forgot password feature is not implemented in this demo"
162                      //   );
163                      // }}
164                    >
165                      Forgot password?
166                    </Link>
167                  </div>
168                  <div className="relative">
169                    <Lock className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
170                    <Input
171                      id="password"
172                      type={showPassword ? "text" : "password"}
173                      placeholder="Enter your password"
174                      className="pl-10 pr-10"
175                      value={password}
176                      onChange={(e) => setPassword(e.target.value)}
177                      disabled={isLoading}
178                      autoComplete="current-password"
179                    />
180                    <Button
181                      type="button"
182                      variant="ghost"
183                      size="sm"
184                      className="absolute right-0 top-0 h-full px-3"
185                      onClick={() => setShowPassword(!showPassword)}
186                    >
187                      {showPassword ? (
188                        <EyeOff className="h-4 w-4" />
189                      ) : (
190                        <Eye className="h-4 w-4" />
191                      )}
192                    </Button>
193                  </div>
194                </div>
195
196                <div className="flex items-center space-x-2">
197                  <Checkbox
198                    id="remember"
199                    checked={rememberMe}
200                    onCheckedChange={(checked) =>
201                      setRememberMe(checked as boolean)
202                    }
203                    disabled={isLoading}
204                  />
205                  <Label htmlFor="remember" className="text-sm font-normal">
206                    Remember me for 30 days
207                  </Label>
208                </div>
209
210                {error && (
211                  <Alert variant="destructive">
212                    <AlertCircle className="h-4 w-4" />
213                    <AlertDescription>{error}</AlertDescription>
214                  </Alert>
215                )}
216
217                <Button
218                  type="submit"
219                  className="w-full"
220                  disabled={isLoading}
221                  onClick={handleDemoLogin}
222                >
223                  {isLoading ? (
224                    <>
225                      <Loader2 className="mr-2 h-4 w-4 animate-spin" />
226                      Signing in...
227                    </>
228                  ) : (
229                    <>
230                      <LogIn className="mr-2 h-4 w-4" />
231                      Sign in
232                    </>
233                  )}
234                </Button>
235
236                <div className="relative">
237                  <div className="absolute inset-0 flex items-center">
238                    <div className="w-full border-t"></div>
239                  </div>
240                  <div className="relative flex justify-center text-xs">
241                    <span className="bg-background px-2 text-muted-foreground">
242                      Don't have an account?
243                    </span>
244                  </div>
245                </div>
246
247                <Link href="/signup">
248                  <Button
249                    type="button"
250                    variant="outline"
251                    className="w-full"
252                    disabled={isLoading}
253                  >
254                    Sign up to create an account
255                  </Button>
256                </Link>
257              </form>
258            </CardContent>
259          </Card>
260        </div>
261      </main>
262    </div>
263  );
264}