feat(auth): implement better authentication system with user sessions and password management

- Added user, session, account, and verification models to Prisma schema.
- Integrated better-auth for user authentication with email and password.
- Created auth middleware for session validation.
- Implemented auth context and client in frontend for managing user sessions.
- Added login and settings pages for user authentication and password management.
- Updated routes to include authentication checks and user-specific content.
- Enhanced UI components to reflect authentication state.
This commit is contained in:
Jose Selesan
2026-05-29 16:03:38 -03:00
parent de57ea4bd7
commit 9482fea7f2
29 changed files with 621 additions and 21 deletions

View File

@@ -1,7 +1,8 @@
import { Menu, Sun, Moon, Monitor } from "lucide-react";
import { Menu, Sun, Moon, Monitor, LogOut } from "lucide-react";
import { Button } from "@/components/ui/button";
import { useSseStatus } from "@/lib/sse-context";
import { useTheme } from "@/lib/theme";
import { useAuth } from "@/lib/auth-context";
import { cn } from "@/lib/utils";
interface HeaderProps {
@@ -11,11 +12,17 @@ interface HeaderProps {
export function Header({ onMenuClick }: HeaderProps) {
const sseStatus = useSseStatus();
const { theme, cycleTheme } = useTheme();
const auth = useAuth();
const ThemeIcon = theme === "light" ? Sun : theme === "dark" ? Moon : Monitor;
const themeLabel =
theme === "light" ? "Claro" : theme === "dark" ? "Oscuro" : "Sistema";
async function handleSignOut() {
await auth.signOut();
window.location.href = "/login";
}
return (
<header className="flex h-14 items-center gap-4 border-b px-4">
<Button
@@ -28,6 +35,21 @@ export function Header({ onMenuClick }: HeaderProps) {
</Button>
<div className="flex-1" />
<div className="flex items-center gap-1.5">
{auth.isAuthenticated && (
<>
<span className="hidden text-sm text-muted-foreground sm:inline">
{auth.session?.user.email}
</span>
<Button
variant="ghost"
size="icon"
onClick={handleSignOut}
title="Cerrar sesión"
>
<LogOut className="size-4" />
</Button>
</>
)}
<Button
variant="ghost"
size="icon"

View File

@@ -1,5 +1,5 @@
import { Link } from "@tanstack/react-router";
import { FileText, LayoutDashboard, TrendingUp, Wallet } from "lucide-react";
import { FileText, LayoutDashboard, Settings, TrendingUp, Wallet } from "lucide-react";
import { cn } from "@/lib/utils";
const navItems = [
@@ -9,6 +9,10 @@ const navItems = [
{ to: "/quotes/belo", label: "BELO", icon: TrendingUp },
];
const bottomItems = [
{ to: "/settings", label: "Configuración", icon: Settings },
];
interface SidebarProps {
open: boolean;
onClose: () => void;
@@ -48,6 +52,20 @@ export function Sidebar({ open, onClose }: SidebarProps) {
</Link>
))}
</nav>
<div className="border-t p-3">
{bottomItems.map((item) => (
<Link
key={item.to}
to={item.to}
activeProps={{ className: "bg-sidebar-accent text-sidebar-accent-foreground font-medium" }}
className="flex items-center gap-3 rounded-lg px-3 py-2 text-sm text-sidebar-foreground/70 transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"
onClick={onClose}
>
<item.icon className="size-4" />
{item.label}
</Link>
))}
</div>
</aside>
</>
);