Files
HoruxDespachosNuevo/apps/web/components/contribuyente-selector.tsx
Horux Dev 66d68c652c Revert "feat(ui): make dashboard responsive for iPhone and mobile devices"
This reverts commit d3b326e.

The deployment caused reports of blank screens and 400 errors. Reverting to restore stable state while investigating root cause.
2026-06-13 20:16:04 +00:00

119 lines
5.2 KiB
TypeScript

'use client';
import { useState, useEffect } from 'react';
import { usePathname } from 'next/navigation';
import { useContribuyentes } from '@/lib/hooks/use-contribuyentes';
import { useContribuyenteStore } from '@/stores/contribuyente-store';
import { cn } from '@horux/shared-ui';
import { Building2, ChevronDown, Check, Users } from 'lucide-react';
// Rutas donde el selector NO aplica (vistas cross-contribuyente del despacho).
const HIDDEN_PATHS = ['/despachos'];
export function ContribuyenteSelector() {
const pathname = usePathname();
const [open, setOpen] = useState(false);
const { data: contribuyentes, isLoading } = useContribuyentes();
const { selectedContribuyenteId, setSelectedContribuyente, clearSelectedContribuyente } =
useContribuyenteStore();
useEffect(() => {
const handleClickOutside = (e: MouseEvent) => {
const target = e.target as HTMLElement;
if (!target.closest('.contribuyente-selector')) setOpen(false);
};
document.addEventListener('click', handleClickOutside);
return () => document.removeEventListener('click', handleClickOutside);
}, []);
// Auto-select if user has exactly 1 contribuyente (common for clients)
useEffect(() => {
if (contribuyentes && contribuyentes.length === 1 && !selectedContribuyenteId) {
setSelectedContribuyente(contribuyentes[0].id, contribuyentes[0].rfc, contribuyentes[0].nombre);
}
}, [contribuyentes, selectedContribuyenteId, setSelectedContribuyente]);
// Clear invalid selection (e.g. stale localStorage from another tenant/session)
useEffect(() => {
if (contribuyentes && contribuyentes.length > 0 && selectedContribuyenteId) {
const exists = contribuyentes.some(c => c.id === selectedContribuyenteId);
if (!exists) {
clearSelectedContribuyente();
}
}
}, [contribuyentes, selectedContribuyenteId, clearSelectedContribuyente]);
if (isLoading || !contribuyentes || contribuyentes.length === 0) return null;
if (pathname && HIDDEN_PATHS.some(p => pathname === p || pathname.startsWith(`${p}/`))) return null;
const selected = contribuyentes.find((c) => c.id === selectedContribuyenteId);
return (
<div className="contribuyente-selector relative">
<button
onClick={() => setOpen(!open)}
className="flex items-center gap-2 rounded-lg px-3 py-2 text-sm font-medium hover:bg-accent transition-colors"
>
<Building2 className="h-4 w-4" />
<span className="max-w-[180px] truncate">
{selected ? selected.nombre : 'Todos los RFCs'}
</span>
<ChevronDown className={cn('h-4 w-4 transition-transform', open && 'rotate-180')} />
</button>
{open && (
<div className="absolute top-full right-0 mt-2 w-80 rounded-lg border bg-card shadow-lg z-50">
<div className="p-2 border-b">
<p className="text-xs text-muted-foreground px-2">Contribuyentes</p>
</div>
<div className="max-h-80 overflow-y-auto p-1">
{/* Todos los RFCs — only show if more than 1 contribuyente */}
{contribuyentes.length > 1 && (
<>
<button
onClick={() => { clearSelectedContribuyente(); setOpen(false); }}
className={cn(
'flex w-full items-center gap-3 rounded-md px-3 py-2 text-sm hover:bg-accent transition-colors text-left',
!selectedContribuyenteId && 'bg-primary/10'
)}
>
<div className="h-8 w-8 rounded bg-muted flex items-center justify-center">
<Users className="h-4 w-4 text-muted-foreground" />
</div>
<div className="flex-1 min-w-0">
<p className="font-medium">Todos los RFCs</p>
<p className="text-xs text-muted-foreground">{contribuyentes.length} contribuyentes</p>
</div>
{!selectedContribuyenteId && <Check className="h-4 w-4 text-primary flex-shrink-0" />}
</button>
<div className="border-t my-1" />
</>
)}
{/* Lista de contribuyentes */}
{contribuyentes.map((c) => (
<button
key={c.id}
onClick={() => { setSelectedContribuyente(c.id, c.rfc, c.nombre); setOpen(false); }}
className={cn(
'flex w-full items-center gap-3 rounded-md px-3 py-2 text-sm hover:bg-accent transition-colors text-left',
selectedContribuyenteId === c.id && 'bg-primary/10'
)}
>
<div className="h-8 w-8 rounded bg-muted flex items-center justify-center text-xs font-medium">
{c.nombre.substring(0, 2).toUpperCase()}
</div>
<div className="flex-1 min-w-0">
<p className="font-medium truncate">{c.nombre}</p>
<p className="text-xs text-muted-foreground truncate">{c.rfc}</p>
</div>
{selectedContribuyenteId === c.id && <Check className="h-4 w-4 text-primary flex-shrink-0" />}
</button>
))}
</div>
</div>
)}
</div>
);
}