feat: Enhance Customer Order Wizard with improved customer list UI

Customer List Improvements:
- Added customer avatars with dynamic colors
- Enhanced visual card design with gradient backgrounds
- Customer type badges with color coding:
  * Wholesale (purple)
  * Restaurant (orange)
  * Event (pink)
  * Retail (blue)
- Display contact information (phone, email) with icons
- Show additional details (city, payment terms)
- Added empty state when no customers found
- Improved hover effects and transitions
- Better spacing and visual hierarchy
- Increased max height for better scrolling
- Group hover states for better interactivity

UX Enhancements:
- More scannable customer information
- Clear visual distinction between customer types
- Better mobile responsiveness
- Improved selected state with gradient
- Smoother transitions and animations

Files modified:
- frontend/src/components/domain/unified-wizard/wizards/CustomerOrderWizard.tsx
This commit is contained in:
Claude
2025-11-09 21:42:10 +00:00
parent 243aec3f90
commit 5f9fa142bc

View File

@@ -172,30 +172,104 @@ const CustomerSelectionStep: React.FC<WizardDataProps> = ({ data, onDataChange,
</div>
{/* Customer List */}
<div className="space-y-2 max-h-64 overflow-y-auto">
{filteredCustomers.map((customer) => (
<button
key={customer.id}
onClick={() => handleSelectCustomer(customer)}
className={`w-full p-4 rounded-lg border-2 transition-all text-left ${
selectedCustomer?.id === customer.id
? 'border-[var(--color-primary)] bg-[var(--color-primary)]/5'
: 'border-[var(--border-secondary)] hover:border-[var(--color-primary)]/50'
}`}
>
<div className="flex items-center justify-between">
<div>
<p className="font-semibold text-[var(--text-primary)]">{customer.name}</p>
<p className="text-sm text-[var(--text-secondary)]">
{customer.customer_type} {customer.phone || 'Sin teléfono'}
</p>
<div className="space-y-3 max-h-96 overflow-y-auto pr-2">
{filteredCustomers.length === 0 ? (
<div className="text-center py-8 border-2 border-dashed border-[var(--border-secondary)] rounded-lg">
<Users className="w-12 h-12 mx-auto mb-3 text-[var(--text-tertiary)]" />
<p className="text-[var(--text-secondary)] mb-1">No se encontraron clientes</p>
<p className="text-sm text-[var(--text-tertiary)]">Intenta con otro término de búsqueda</p>
</div>
) : (
filteredCustomers.map((customer) => (
<button
key={customer.id}
onClick={() => handleSelectCustomer(customer)}
className={`w-full p-4 rounded-xl border-2 transition-all text-left group hover:shadow-md ${
selectedCustomer?.id === customer.id
? 'border-[var(--color-primary)] bg-gradient-to-r from-[var(--color-primary)]/10 to-[var(--color-primary)]/5 shadow-sm'
: 'border-[var(--border-secondary)] hover:border-[var(--color-primary)]/50 hover:bg-[var(--bg-secondary)]/30'
}`}
>
<div className="flex items-start gap-3">
{/* Customer Avatar */}
<div className={`w-12 h-12 rounded-full flex items-center justify-center flex-shrink-0 transition-colors ${
selectedCustomer?.id === customer.id
? 'bg-[var(--color-primary)] text-white'
: 'bg-[var(--bg-tertiary)] text-[var(--text-tertiary)] group-hover:bg-[var(--color-primary)]/20 group-hover:text-[var(--color-primary)]'
}`}>
<Users className="w-6 h-6" />
</div>
{/* Customer Info */}
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2 mb-1">
<h4 className={`font-semibold truncate transition-colors ${
selectedCustomer?.id === customer.id
? 'text-[var(--color-primary)]'
: 'text-[var(--text-primary)]'
}`}>
{customer.name}
</h4>
{selectedCustomer?.id === customer.id && (
<CheckCircle2 className="w-5 h-5 text-[var(--color-primary)] flex-shrink-0" />
)}
</div>
<div className="flex flex-wrap items-center gap-2 text-sm text-[var(--text-secondary)]">
{/* Customer Type Badge */}
<span className={`px-2 py-0.5 rounded-full text-xs font-medium ${
customer.customer_type === 'wholesale'
? 'bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-300'
: customer.customer_type === 'restaurant'
? 'bg-orange-100 text-orange-700 dark:bg-orange-900/30 dark:text-orange-300'
: customer.customer_type === 'event'
? 'bg-pink-100 text-pink-700 dark:bg-pink-900/30 dark:text-pink-300'
: 'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-300'
}`}>
{customer.customer_type === 'wholesale' ? 'Mayorista' :
customer.customer_type === 'restaurant' ? 'Restaurante' :
customer.customer_type === 'event' ? 'Eventos' : 'Minorista'}
</span>
{/* Phone */}
{customer.phone && (
<span className="flex items-center gap-1">
📱 {customer.phone}
</span>
)}
{/* Email */}
{customer.email && (
<span className="flex items-center gap-1 truncate">
{customer.email}
</span>
)}
</div>
{/* Additional Info */}
{(customer.city || customer.payment_terms) && (
<div className="flex items-center gap-3 mt-2 text-xs text-[var(--text-tertiary)]">
{customer.city && (
<span className="flex items-center gap-1">
<MapPin className="w-3 h-3" />
{customer.city}
</span>
)}
{customer.payment_terms && (
<span className="flex items-center gap-1">
<CreditCard className="w-3 h-3" />
{customer.payment_terms === 'immediate' ? 'Pago inmediato' :
customer.payment_terms === 'net_15' ? 'Net 15' :
customer.payment_terms === 'net_30' ? 'Net 30' : customer.payment_terms}
</span>
)}
</div>
)}
</div>
</div>
{selectedCustomer?.id === customer.id && (
<CheckCircle2 className="w-5 h-5 text-[var(--color-primary)]" />
)}
</div>
</button>
))}
</button>
))
)}
</div>
{/* Create New Customer Button */}