platform-marketing-content-.../src/pages/crm/BrandsPage.tsx
2026-01-04 07:19:31 -06:00

220 lines
7.7 KiB
TypeScript

import { useState } from 'react';
import { Link } from 'react-router-dom';
import { useBrands, useDeleteBrand } from '@/hooks/useBrands';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from '@/components/ui/card';
import { Plus, Search, Palette, Pencil, Trash2 } from 'lucide-react';
export default function BrandsPage() {
const [search, setSearch] = useState('');
const [page, setPage] = useState(1);
const { data, isLoading } = useBrands({ search, page, limit: 12 });
const deleteBrand = useDeleteBrand();
const handleDelete = (id: string) => {
if (confirm('¿Está seguro de eliminar esta marca?')) {
deleteBrand.mutate(id);
}
};
return (
<div className="space-y-6">
{/* Header */}
<div className="flex items-center justify-between">
<div>
<h1 className="text-3xl font-bold">Marcas</h1>
<p className="text-muted-foreground">
Gestiona las marcas de tus clientes
</p>
</div>
<Link to="/crm/brands/new">
<Button>
<Plus className="mr-2 h-4 w-4" />
Nueva Marca
</Button>
</Link>
</div>
{/* Search */}
<div className="flex items-center gap-4">
<div className="relative flex-1 max-w-sm">
<Search className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
<Input
placeholder="Buscar marcas..."
value={search}
onChange={(e) => setSearch(e.target.value)}
className="pl-9"
/>
</div>
</div>
{/* Grid */}
{isLoading ? (
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{[...Array(6)].map((_, i) => (
<Card key={i} className="animate-pulse">
<CardHeader>
<div className="h-6 bg-muted rounded w-2/3" />
</CardHeader>
<CardContent>
<div className="h-4 bg-muted rounded w-full" />
</CardContent>
</Card>
))}
</div>
) : data?.data?.length === 0 ? (
<Card>
<CardContent className="flex flex-col items-center justify-center py-12">
<Palette className="h-12 w-12 text-muted-foreground mb-4" />
<h3 className="text-lg font-semibold">No hay marcas</h3>
<p className="text-muted-foreground mb-4">
Comienza agregando tu primera marca
</p>
<Link to="/crm/brands/new">
<Button>
<Plus className="mr-2 h-4 w-4" />
Nueva Marca
</Button>
</Link>
</CardContent>
</Card>
) : (
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{data?.data?.map((brand) => (
<Card key={brand.id} className="group hover:shadow-md transition-shadow">
<CardHeader className="pb-3">
<div className="flex items-start justify-between">
<div className="flex items-center gap-3">
{brand.logo_url ? (
<img
src={brand.logo_url}
alt={brand.name}
className="h-10 w-10 rounded-lg object-cover"
/>
) : (
<div
className="h-10 w-10 rounded-lg flex items-center justify-center"
style={{
backgroundColor: brand.primary_color || '#3B82F6',
}}
>
<span className="text-white font-bold text-lg">
{brand.name.charAt(0).toUpperCase()}
</span>
</div>
)}
<div>
<CardTitle className="text-lg">
<Link
to={`/crm/brands/${brand.id}`}
className="hover:underline"
>
{brand.name}
</Link>
</CardTitle>
{brand.client && (
<CardDescription>
<Link
to={`/crm/clients/${brand.client.id}`}
className="hover:underline"
>
{brand.client.name}
</Link>
</CardDescription>
)}
</div>
</div>
<div className="opacity-0 group-hover:opacity-100 transition-opacity flex gap-1">
<Link to={`/crm/brands/${brand.id}/edit`}>
<Button variant="ghost" size="icon" className="h-8 w-8">
<Pencil className="h-4 w-4" />
</Button>
</Link>
<Button
variant="ghost"
size="icon"
className="h-8 w-8 text-destructive"
onClick={() => handleDelete(brand.id)}
>
<Trash2 className="h-4 w-4" />
</Button>
</div>
</div>
</CardHeader>
<CardContent className="space-y-3">
{brand.description && (
<p className="text-sm text-muted-foreground line-clamp-2">
{brand.description}
</p>
)}
{(brand.primary_color || brand.secondary_color) && (
<div className="flex items-center gap-2">
{brand.primary_color && (
<div
className="w-6 h-6 rounded-full border"
style={{ backgroundColor: brand.primary_color }}
title="Color primario"
/>
)}
{brand.secondary_color && (
<div
className="w-6 h-6 rounded-full border"
style={{ backgroundColor: brand.secondary_color }}
title="Color secundario"
/>
)}
</div>
)}
<div className="pt-2">
<span
className={`px-2 py-1 rounded-full text-xs font-medium ${
brand.is_active
? 'bg-green-100 text-green-700'
: 'bg-gray-100 text-gray-700'
}`}
>
{brand.is_active ? 'Activa' : 'Inactiva'}
</span>
</div>
</CardContent>
</Card>
))}
</div>
)}
{/* Pagination */}
{data?.meta && data.meta.totalPages > 1 && (
<div className="flex items-center justify-center gap-2">
<Button
variant="outline"
size="sm"
disabled={!data.meta.hasPreviousPage}
onClick={() => setPage(page - 1)}
>
Anterior
</Button>
<span className="text-sm text-muted-foreground">
Página {data.meta.page} de {data.meta.totalPages}
</span>
<Button
variant="outline"
size="sm"
disabled={!data.meta.hasNextPage}
onClick={() => setPage(page + 1)}
>
Siguiente
</Button>
</div>
)}
</div>
);
}