436 lines
14 KiB
TypeScript
436 lines
14 KiB
TypeScript
|
|
"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'>
|
||
|
|
<div className='space-y-2'>
|
||
|
|
<Label>Cliente</Label>
|
||
|
|
<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>
|
||
|
|
|
||
|
|
<CommandDialog open={open} onOpenChange={setOpen}>
|
||
|
|
<CommandInput
|
||
|
|
placeholder='Buscar cliente por nombre, email o empresa...'
|
||
|
|
value={searchValue}
|
||
|
|
onValueChange={setSearchValue}
|
||
|
|
/>
|
||
|
|
<CommandList>
|
||
|
|
<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>
|
||
|
|
);
|
||
|
|
};
|