trello_fake/components/dashboard/project-list-item.tsx

147 lines
5.3 KiB
TypeScript
Raw Permalink Normal View History

2026-01-28 10:44:49 +00:00
"use client";
import Link from 'next/link';
import { Calendar, DollarSign, TrendingUp, MoreHorizontal, Pencil, Trash2, Eye } from 'lucide-react';
2026-01-28 10:44:49 +00:00
import { Avatar, AvatarFallback } from '@/components/ui/avatar';
import { Button } from '@/components/ui/button';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { ProjectStatusBadge } from '@/components/ui/project-status-badge';
import { Project } from '@/types/project';
2026-01-28 10:44:49 +00:00
interface ProjectListItemProps {
project: Project;
onEdit?: (project: Project) => void;
onDelete?: (project: Project) => void;
2026-01-28 10:44:49 +00:00
}
// Función para generar iniciales
function getInitials(name: string): string {
return name
.split(' ')
.map(word => word[0])
.join('')
.toUpperCase()
.slice(0, 2);
}
/**
* Componente de fila de proyecto para vista de lista
* Diseño horizontal y compacto
*/
export default function ProjectListItem({ project, onEdit, onDelete }: ProjectListItemProps) {
2026-01-28 10:44:49 +00:00
const initials = getInitials(project.name);
return (
<div className="bg-card border rounded-lg p-4 hover:shadow-md transition-all duration-300 group">
<div className="flex items-center gap-4">
{/* Avatar */}
<Link href={`/proyectos/${project.id}`}>
<Avatar className="w-12 h-12 flex-shrink-0 cursor-pointer">
2026-01-28 10:44:49 +00:00
<AvatarFallback className="bg-gradient-to-br from-blue-500 to-purple-600 text-white font-semibold">
{initials}
</AvatarFallback>
</Avatar>
</Link>
2026-01-28 10:44:49 +00:00
{/* Info Principal */}
<div className="flex-1 min-w-0">
<div className="flex items-start justify-between gap-4">
<Link href={`/proyectos/${project.id}`} className="flex-1">
<div className="flex items-center gap-2 mb-1">
<h3 className="text-base font-semibold truncate hover:text-primary transition-colors">
{project.name}
</h3>
<span className="text-xs text-muted-foreground flex-shrink-0">{project.ref}</span>
2026-01-28 10:44:49 +00:00
</div>
{project.client !== 'Sin cliente' && (
<p className="text-sm text-muted-foreground truncate">{project.client}</p>
)}
</Link>
{/* Estado */}
<ProjectStatusBadge status={project.status} />
2026-01-28 10:44:49 +00:00
</div>
</div>
2026-01-28 10:44:49 +00:00
{/* Progreso */}
<div className="hidden md:flex items-center gap-2 flex-shrink-0 w-32">
<TrendingUp className="w-4 h-4 text-muted-foreground" />
<div className="flex-1">
<div className="flex items-center justify-between mb-1">
<span className="text-xs text-muted-foreground">Progreso</span>
<span className="text-xs font-semibold">{project.progress}%</span>
</div>
<div className="w-full bg-muted rounded-full h-1.5">
<div
className="bg-gradient-to-r from-blue-500 to-purple-600 h-1.5 rounded-full transition-all duration-500"
style={{ width: `${project.progress}%` }}
/>
2026-01-28 10:44:49 +00:00
</div>
</div>
</div>
2026-01-28 10:44:49 +00:00
{/* Presupuesto */}
<div className="hidden lg:flex items-center gap-2 flex-shrink-0">
<DollarSign className="w-4 h-4 text-green-500" />
<div className="text-right">
<div className="text-sm font-semibold">
€{project.budget.toLocaleString('es-ES', { minimumFractionDigits: 0, maximumFractionDigits: 0 })}
2026-01-28 10:44:49 +00:00
</div>
<div className="text-xs text-muted-foreground">Presupuesto</div>
2026-01-28 10:44:49 +00:00
</div>
</div>
2026-01-28 10:44:49 +00:00
{/* Fechas */}
<div className="hidden xl:flex items-center gap-2 flex-shrink-0">
<Calendar className="w-4 h-4 text-muted-foreground" />
<div className="text-right">
<div className="text-sm">
{new Date(project.startDate).toLocaleDateString('es-ES', { day: '2-digit', month: 'short' })}
2026-01-28 10:44:49 +00:00
</div>
<div className="text-xs text-muted-foreground">Inicio</div>
2026-01-28 10:44:49 +00:00
</div>
</div>
{/* Menú de acciones */}
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
size="icon"
className="h-8 w-8 opacity-0 group-hover:opacity-100 transition-opacity flex-shrink-0"
>
<MoreHorizontal className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem asChild>
<Link href={`/proyectos/${project.id}`}>
<Eye className="mr-2 h-4 w-4" />
Ver detalles
</Link>
</DropdownMenuItem>
<DropdownMenuItem onClick={() => onEdit?.(project)}>
<Pencil className="mr-2 h-4 w-4" />
Editar
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem
className="text-destructive focus:text-destructive"
onClick={() => onDelete?.(project)}
>
<Trash2 className="mr-2 h-4 w-4" />
Eliminar
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
2026-01-28 10:44:49 +00:00
</div>
</div>
2026-01-28 10:44:49 +00:00
);
}