Uecko_ERP/modules/customers/src/web/components/client-selector.tsx

440 lines
14 KiB
TypeScript
Raw Normal View History

2025-07-07 18:25:13 +00:00
"use client";
import { generateUUIDv4 } from "@repo/rdx-utils";
import {
Badge,
Button,
Card,
CardContent,
CommandDialog,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
Input,
Label,
Separator,
} from "@repo/shadcn-ui/components";
import {
Building,
Calendar,
Edit,
Mail,
MapPin,
Phone,
Plus,
Search,
Trash2,
User,
} from "lucide-react";
import { useState } from "react";
const mockCustomers = [
{
id: "a1d2e3f4-5678-90ab-cdef-1234567890ab",
name: "Juan Pérez",
email: "juan@email.com",
phone: "+34 600 123 456",
company: "Tech Corp",
address: "Calle Mayor 123, Madrid",
createdAt: "2024-01-15",
status: "Activo",
},
{
id: "b1d2e3f4-5678-90ab-cdef-1234567890ab",
name: "María García",
email: "maria@email.com",
phone: "+34 600 789 012",
company: "Design Studio",
address: "Av. Diagonal 456, Barcelona",
createdAt: "2024-02-20",
status: "Activo",
},
{
id: "c1d2e3f4-5678-90ab-cdef-1234567890ab",
name: "Carlos López",
email: "carlos@email.com",
phone: "+34 600 345 678",
company: "Marketing Plus",
address: "Gran Vía 789, Valencia",
createdAt: "2024-01-30",
status: "Inactivo",
},
{
id: "d1d2e3f4-5678-90ab-cdef-1234567890ab",
name: "Ana Martínez",
email: "ana@email.com",
phone: "+34 600 901 234",
company: "Consulting Group",
address: "Calle Sierpes 321, Sevilla",
createdAt: "2024-03-10",
status: "Activo",
},
];
export const ClientSelector = () => {
const [open, setOpen] = useState(false);
const [selectedCustomer, setSelectedCustomer] = useState(null);
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
const [isDetailsModalOpen, setIsDetailsModalOpen] = useState(false);
const [searchValue, setSearchValue] = useState("");
const [newCustomer, setNewCustomer] = useState({
name: "",
email: "",
phone: "",
company: "",
address: "",
});
const handleCreateCustomer = (e) => {
e.preventDefault();
const createdCustomer = {
id: generateUUIDv4(),
...newCustomer,
createdAt: new Date().toISOString().split("T")[0],
status: "Activo",
};
console.log("Cliente creado:", createdCustomer);
setSelectedCustomer(createdCustomer);
setIsCreateModalOpen(false);
setNewCustomer({ name: "", email: "", phone: "", company: "", address: "" });
};
const handleEditCustomer = () => {
console.log("Editar cliente:", selectedCustomer);
setIsDetailsModalOpen(false);
};
const handleDeleteCustomer = () => {
console.log("Eliminar cliente:", selectedCustomer);
setSelectedCustomer(null);
setIsDetailsModalOpen(false);
};
const handleSelectCustomer = (customer) => {
console.log("Seleccionar cliente:", customer);
setSelectedCustomer(customer);
setOpen(false);
};
return (
<div className='w-full max-w-md space-y-4'>
2025-07-17 08:50:28 +00:00
<div className='space-y-0'>
<Label className='m-0'>Cliente</Label>
2025-07-07 18:25:13 +00:00
<Button
variant='outline'
className='w-full justify-start bg-transparent'
onClick={(e) => {
e.preventDefault();
setOpen(true);
}}
>
<Search className='mr-2 h-4 w-4' />
{selectedCustomer ? selectedCustomer.name : "Buscar cliente..."}
</Button>
</div>
2025-07-17 08:50:28 +00:00
<CommandDialog
open={open}
onOpenChange={setOpen}
className='[&>div]:max-w-3xl [&>div]:max-h-[80vh] [&>div]:w-full'
>
2025-07-07 18:25:13 +00:00
<CommandInput
placeholder='Buscar cliente por nombre, email o empresa...'
value={searchValue}
onValueChange={setSearchValue}
/>
2025-07-17 08:50:28 +00:00
<CommandList className='max-w-screen'>
2025-07-07 18:25:13 +00:00
<CommandEmpty>
<div className='p-6 text-center'>
<User className='h-12 w-12 mx-auto text-muted-foreground mb-4' />
<p className='text-sm text-muted-foreground mb-4'>
No se encontró ningún cliente con "{searchValue}"
</p>
<Button
onClick={(e) => {
e.preventDefault();
setNewCustomer({ ...newCustomer, name: searchValue });
setIsCreateModalOpen(true);
setOpen(false);
}}
>
<Plus className='h-4 w-4 mr-2' />
Crear Cliente
</Button>
</div>
</CommandEmpty>
<CommandGroup heading='Clientes'>
{mockCustomers.map((customer) => (
<CommandItem
key={customer.id}
onSelect={() => handleSelectCustomer(customer)}
className='flex items-center space-x-3 p-3'
>
<User className='h-4 w-4 flex-shrink-0' />
<div className='flex-1 min-w-0'>
<div className='flex items-center space-x-2'>
<p className='font-medium truncate'>{customer.name}</p>
<Badge
variant={customer.status === "Activo" ? "default" : "secondary"}
className='text-xs'
>
{customer.status}
</Badge>
</div>
<div className='flex items-center space-x-4 text-xs text-muted-foreground'>
<span className='flex items-center'>
<Building className='h-3 w-3 mr-1' />
{customer.company}
</span>
<span className='flex items-center'>
<Mail className='h-3 w-3 mr-1' />
{customer.email}
</span>
</div>
</div>
</CommandItem>
))}
</CommandGroup>
<Separator />
<CommandGroup>
<CommandItem
onSelect={(e) => {
setIsCreateModalOpen(true);
setOpen(false);
}}
className='flex items-center space-x-3 p-3 text-primary'
>
<Plus className='h-4 w-4' />
<span>Crear nuevo cliente</span>
</CommandItem>
</CommandGroup>
</CommandList>
</CommandDialog>
{selectedCustomer && (
<Card className='border-primary'>
<CardContent className='p-4'>
<div className='flex items-center justify-between'>
<div className='flex items-center space-x-3'>
<User className='h-8 w-8 text-primary' />
<div>
<div className='flex items-center space-x-2'>
<h3 className='font-semibold'>{selectedCustomer.name}</h3>
<Badge
variant={selectedCustomer.status === "Activo" ? "default" : "secondary"}
className='text-xs'
>
{selectedCustomer.status}
</Badge>
</div>
<p className='text-sm text-muted-foreground'>{selectedCustomer.company}</p>
</div>
</div>
<div className='flex space-x-2'>
<Button
variant='outline'
size='sm'
onClick={(e) => {
e.preventDefault();
setIsDetailsModalOpen(true);
}}
>
Ver Detalles
</Button>
<Button
variant='outline'
size='sm'
onClick={(e) => {
e.preventDefault();
setOpen(true);
}}
>
Cambiar
</Button>
</div>
</div>
</CardContent>
</Card>
)}
<Dialog open={isCreateModalOpen} onOpenChange={setIsCreateModalOpen}>
<DialogContent className='max-w-md'>
<DialogHeader>
<DialogTitle className='flex items-center space-x-2'>
<Plus className='h-5 w-5' />
<span>Crear Nuevo Cliente</span>
</DialogTitle>
<DialogDescription>Completa la información del nuevo cliente</DialogDescription>
</DialogHeader>
<div className='space-y-4'>
<div className='grid grid-cols-2 gap-4'>
<div className='space-y-2'>
<Label htmlFor='name'>Nombre *</Label>
<Input
id='name'
value={newCustomer.name}
onChange={(e) => setNewCustomer({ ...newCustomer, name: e.target.value })}
placeholder='Nombre completo'
/>
</div>
<div className='space-y-2'>
<Label htmlFor='company'>Empresa</Label>
<Input
id='company'
value={newCustomer.company}
onChange={(e) => setNewCustomer({ ...newCustomer, company: e.target.value })}
placeholder='Nombre de la empresa'
/>
</div>
</div>
<div className='space-y-2'>
<Label htmlFor='email'>Email *</Label>
<Input
id='email'
type='email'
value={newCustomer.email}
onChange={(e) => setNewCustomer({ ...newCustomer, email: e.target.value })}
placeholder='correo@ejemplo.com'
/>
</div>
<div className='space-y-2'>
<Label htmlFor='phone'>Teléfono</Label>
<Input
id='phone'
value={newCustomer.phone}
onChange={(e) => setNewCustomer({ ...newCustomer, phone: e.target.value })}
placeholder='+34 600 000 000'
/>
</div>
<div className='space-y-2'>
<Label htmlFor='address'>Dirección</Label>
<Input
id='address'
value={newCustomer.address}
onChange={(e) => setNewCustomer({ ...newCustomer, address: e.target.value })}
placeholder='Dirección completa'
/>
</div>
</div>
<DialogFooter>
<Button
variant='outline'
onClick={(e) => {
e.preventDefault();
setIsCreateModalOpen(false);
}}
>
Cancelar
</Button>
<Button
onClick={handleCreateCustomer}
disabled={!newCustomer.name || !newCustomer.email}
>
<Plus className='h-4 w-4 mr-2' />
Crear Cliente
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
<Dialog open={isDetailsModalOpen} onOpenChange={setIsDetailsModalOpen}>
<DialogContent className='max-w-md'>
<DialogHeader>
<DialogTitle className='flex items-center space-x-2'>
<User className='h-5 w-5' />
<span>Detalles del Cliente</span>
</DialogTitle>
</DialogHeader>
{selectedCustomer && (
<div className='space-y-6'>
<div className='space-y-4'>
<div className='flex items-center justify-between'>
<div>
<h3 className='text-lg font-semibold'>{selectedCustomer.name}</h3>
<p className='text-sm text-muted-foreground'>{selectedCustomer.company}</p>
</div>
<Badge variant={selectedCustomer.status === "Activo" ? "default" : "secondary"}>
{selectedCustomer.status}
</Badge>
</div>
<Separator />
<div className='space-y-3'>
<div className='flex items-center space-x-3'>
<Mail className='h-4 w-4 text-muted-foreground' />
<div>
<Label className='text-xs font-medium text-muted-foreground'>EMAIL</Label>
<p className='font-medium'>{selectedCustomer.email}</p>
</div>
</div>
<div className='flex items-center space-x-3'>
<Phone className='h-4 w-4 text-muted-foreground' />
<div>
<Label className='text-xs font-medium text-muted-foreground'>TELÉFONO</Label>
<p className='font-medium'>{selectedCustomer.phone}</p>
</div>
</div>
<div className='flex items-start space-x-3'>
<MapPin className='h-4 w-4 text-muted-foreground mt-1' />
<div>
<Label className='text-xs font-medium text-muted-foreground'>DIRECCIÓN</Label>
<p className='font-medium'>{selectedCustomer.address}</p>
</div>
</div>
<div className='flex items-center space-x-3'>
<Calendar className='h-4 w-4 text-muted-foreground' />
<div>
<Label className='text-xs font-medium text-muted-foreground'>
FECHA DE REGISTRO
</Label>
<p className='font-medium'>
{new Date(selectedCustomer.createdAt).toLocaleDateString("es-ES")}
</p>
</div>
</div>
</div>
</div>
<Separator />
<div className='flex space-x-2'>
<Button className='flex-1'>
<Mail className='h-4 w-4 mr-2' />
Enviar Email
</Button>
<Button variant='outline' onClick={handleEditCustomer}>
<Edit className='h-4 w-4 mr-2' />
Editar
</Button>
<Button variant='outline' onClick={handleDeleteCustomer}>
<Trash2 className='h-4 w-4 mr-2' />
Eliminar
</Button>
</div>
</div>
)}
<DialogFooter>
<Button variant='outline' onClick={() => setIsDetailsModalOpen(false)}>
Cerrar
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</div>
);
};