chore: upload parte 1 - logica
DevSecOps Enterprise Pipeline / security-gate-and-deploy (push) Failing after 41s
DevSecOps Enterprise Pipeline / security-gate-and-deploy (push) Failing after 41s
This commit is contained in:
@@ -0,0 +1,190 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import Image from "next/image";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { Eye, EyeOff, Loader2 } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
|
||||
export default function LoginPage() {
|
||||
const router = useRouter();
|
||||
const [email, setEmail] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
const [rememberMe, setRememberMe] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
async function handleSubmit(e: React.FormEvent) {
|
||||
e.preventDefault();
|
||||
if (!email || !password) {
|
||||
toast.error("Please enter email and password");
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
try {
|
||||
const res = await fetch("/api/auth/login", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
credentials: "include",
|
||||
body: JSON.stringify({ email, password }),
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
if (!res.ok) {
|
||||
toast.error(data.error || "Login failed");
|
||||
return;
|
||||
}
|
||||
|
||||
toast.success("Login successful");
|
||||
window.location.href = "/";
|
||||
} catch {
|
||||
toast.error("An error occurred");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className="min-h-screen flex flex-col items-center justify-center px-4"
|
||||
style={{
|
||||
background: "radial-gradient(circle at center, #0c1c28 0%, #05131d 100%)"
|
||||
}}
|
||||
>
|
||||
{/* LINSE Title */}
|
||||
<h1
|
||||
className="text-4xl md:text-[38px] font-light mb-10"
|
||||
style={{ color: "#7cecff", letterSpacing: "12px", opacity: 0.9 }}
|
||||
>
|
||||
LINSE
|
||||
</h1>
|
||||
|
||||
{/* Circuit Logo */}
|
||||
<div className="mb-10">
|
||||
<Image
|
||||
src="/images/linse-symbol.png"
|
||||
alt="Linse Symbol"
|
||||
width={160}
|
||||
height={160}
|
||||
className="w-40 h-40"
|
||||
style={{
|
||||
filter: "drop-shadow(0 0 25px #18d1e4) brightness(0) saturate(100%) invert(73%) sepia(67%) saturate(1000%) hue-rotate(130deg) brightness(95%)"
|
||||
}}
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Login Form Card */}
|
||||
<div
|
||||
className="w-full max-w-[360px] rounded-[14px] p-9 text-left"
|
||||
style={{
|
||||
background: "rgba(255, 255, 255, 0.04)",
|
||||
border: "1px solid rgba(255, 255, 255, 0.06)",
|
||||
backdropFilter: "blur(10px)",
|
||||
boxShadow: "0 0 30px rgba(0, 0, 0, 0.3)"
|
||||
}}
|
||||
>
|
||||
<form onSubmit={handleSubmit} className="space-y-[18px]">
|
||||
{/* Email Input */}
|
||||
<Input
|
||||
type="email"
|
||||
placeholder="Email or username"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
className="h-[50px] rounded-lg text-[15px]"
|
||||
style={{
|
||||
background: "rgba(255, 255, 255, 0.05)",
|
||||
border: "1px solid rgba(255, 255, 255, 0.12)",
|
||||
color: "#d8e8f0"
|
||||
}}
|
||||
autoComplete="email"
|
||||
disabled={loading}
|
||||
/>
|
||||
|
||||
{/* Password Input */}
|
||||
<div className="relative">
|
||||
<Input
|
||||
type={showPassword ? "text" : "password"}
|
||||
placeholder="Password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
className="h-[50px] rounded-lg text-[15px] pr-10"
|
||||
style={{
|
||||
background: "rgba(255, 255, 255, 0.05)",
|
||||
border: "1px solid rgba(255, 255, 255, 0.12)",
|
||||
color: "#d8e8f0"
|
||||
}}
|
||||
autoComplete="current-password"
|
||||
disabled={loading}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowPassword(!showPassword)}
|
||||
className="absolute right-3 top-1/2 -translate-y-1/2 transition-colors"
|
||||
style={{ color: "#9db4c1" }}
|
||||
tabIndex={-1}
|
||||
>
|
||||
{showPassword ? (
|
||||
<EyeOff className="h-5 w-5" />
|
||||
) : (
|
||||
<Eye className="h-5 w-5" />
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Remember me & Forgot password */}
|
||||
<div className="flex items-center justify-between mb-[25px] text-[14px]">
|
||||
<div className="flex items-center gap-[6px]">
|
||||
<Checkbox
|
||||
id="remember"
|
||||
checked={rememberMe}
|
||||
onCheckedChange={(checked) => setRememberMe(checked as boolean)}
|
||||
className="border-[#9db4c1] data-[state=checked]:bg-cyan-600 data-[state=checked]:border-cyan-600"
|
||||
/>
|
||||
<label
|
||||
htmlFor="remember"
|
||||
className="cursor-pointer select-none"
|
||||
style={{ color: "#d8e8f0" }}
|
||||
>
|
||||
Remember me
|
||||
</label>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className="hover:underline transition-colors"
|
||||
style={{ color: "#8fd8e8" }}
|
||||
onClick={() => toast.info("Contact your administrator to reset your password")}
|
||||
>
|
||||
Forgot password?
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Login Button */}
|
||||
<Button
|
||||
type="submit"
|
||||
className="w-full h-[50px] text-base font-semibold rounded-lg transition-all hover:scale-[1.02]"
|
||||
style={{
|
||||
background: "linear-gradient(90deg, #1cb5c9, #0fa4b7)",
|
||||
color: "#ffffff",
|
||||
}}
|
||||
disabled={loading}
|
||||
>
|
||||
{loading ? (
|
||||
<>
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
Logging in...
|
||||
</>
|
||||
) : (
|
||||
"Log in"
|
||||
)}
|
||||
</Button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user