Add login and register dialogs, user dropdown menu with profile link and logout option, and integrate with session management hook. Prevent hydration mismatches by conditionally rendering auth elements after mount. Update package-lock.json with new @esbuild dependencies for build tooling.
120 lines
3.3 KiB
TypeScript
120 lines
3.3 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogDescription,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
} from "@/components/ui/dialog";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Input } from "@/components/ui/input";
|
|
import { Label } from "@/components/ui/label";
|
|
import { useSession } from "@/lib/hooks/use-session";
|
|
|
|
interface LoginDialogProps {
|
|
open: boolean;
|
|
onOpenChange: (open: boolean) => void;
|
|
}
|
|
|
|
export function LoginDialog({ open, onOpenChange }: LoginDialogProps) {
|
|
const [emailOrUsername, setEmailOrUsername] = useState("");
|
|
const [password, setPassword] = useState("");
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
const { refreshSession } = useSession();
|
|
|
|
const handleSubmit = async (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
setIsLoading(true);
|
|
setError(null);
|
|
|
|
try {
|
|
const response = await fetch("/api/auth/login", {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
credentials: "include",
|
|
body: JSON.stringify({
|
|
emailOrUsername,
|
|
password,
|
|
}),
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (data.success) {
|
|
// Atualizar sessão
|
|
await refreshSession();
|
|
// Fechar diálogo
|
|
onOpenChange(false);
|
|
// Limpar formulário
|
|
setEmailOrUsername("");
|
|
setPassword("");
|
|
// Recarregar página para atualizar estado
|
|
window.location.reload();
|
|
} else {
|
|
setError(data.error || "Erro ao fazer login");
|
|
}
|
|
} catch (err) {
|
|
setError("Erro ao conectar com o servidor");
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
<DialogContent className="sm:max-w-md">
|
|
<DialogHeader>
|
|
<DialogTitle>Entrar</DialogTitle>
|
|
<DialogDescription>
|
|
Faça login para acessar sua conta
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
|
|
<form onSubmit={handleSubmit} className="space-y-4">
|
|
<div className="space-y-2">
|
|
<Label htmlFor="emailOrUsername">Email ou Username</Label>
|
|
<Input
|
|
id="emailOrUsername"
|
|
type="text"
|
|
placeholder="[email protected] ou username"
|
|
value={emailOrUsername}
|
|
onChange={(e) => setEmailOrUsername(e.target.value)}
|
|
required
|
|
disabled={isLoading}
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="password">Senha</Label>
|
|
<Input
|
|
id="password"
|
|
type="password"
|
|
placeholder="••••••••"
|
|
value={password}
|
|
onChange={(e) => setPassword(e.target.value)}
|
|
required
|
|
disabled={isLoading}
|
|
/>
|
|
</div>
|
|
|
|
{error && (
|
|
<div className="text-sm text-destructive bg-destructive/10 p-3 rounded-md">
|
|
{error}
|
|
</div>
|
|
)}
|
|
|
|
<Button type="submit" className="w-full" disabled={isLoading}>
|
|
{isLoading ? "Entrando..." : "Entrar"}
|
|
</Button>
|
|
</form>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
}
|
|
|