Files
HoruxDespachosNuevo/apps/web/components/tenant-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

165 lines
6.4 KiB
TypeScript

'use client';
import { useState, useEffect } from 'react';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { getTenants, type Tenant } from '@/lib/api/tenants';
import { useTenantViewStore } from '@/stores/tenant-view-store';
import { useContribuyenteStore } from '@/stores/contribuyente-store';
import { useAuthStore } from '@/stores/auth-store';
import { Building, ChevronDown, Check, X } from 'lucide-react';
import { cn } from '@horux/shared-ui';
import { isGlobalAdminRfc } from '@horux/shared';
export function TenantSelector() {
const [open, setOpen] = useState(false);
const { user } = useAuthStore();
const queryClient = useQueryClient();
const { viewingTenantId, viewingTenantName, setViewingTenant, clearViewingTenant } = useTenantViewStore();
const { clearSelectedContribuyente } = useContribuyenteStore();
const isGlobalAdmin = isGlobalAdminRfc(user?.tenantRfc, user?.role, user?.platformRoles);
const { data: tenants, isLoading } = useQuery({
queryKey: ['tenants'],
queryFn: getTenants,
enabled: isGlobalAdmin,
});
// Close dropdown when clicking outside
useEffect(() => {
const handleClickOutside = (e: MouseEvent) => {
const target = e.target as HTMLElement;
if (!target.closest('.tenant-selector')) {
setOpen(false);
}
};
document.addEventListener('click', handleClickOutside);
return () => document.removeEventListener('click', handleClickOutside);
}, []);
// Solo admin global — ningún otro admin puede cambiar de tenant
if (!isGlobalAdmin) {
return null;
}
const currentTenant = viewingTenantId
? tenants?.find(t => t.id === viewingTenantId)
: null;
const displayName = viewingTenantName || currentTenant?.nombre || user?.tenantName;
const isViewingOther = viewingTenantId && viewingTenantId !== user?.tenantId;
return (
<div className="tenant-selector relative">
<button
onClick={() => setOpen(!open)}
className={cn(
'flex items-center gap-2 rounded-lg px-3 py-2 text-sm font-medium transition-colors',
isViewingOther
? 'bg-primary/10 text-primary border border-primary/30'
: 'hover:bg-accent'
)}
>
<Building className="h-4 w-4" />
<span className="max-w-[150px] truncate">{displayName}</span>
{isViewingOther && (
<span
role="button"
tabIndex={0}
onClick={(e) => {
e.stopPropagation();
clearViewingTenant();
clearSelectedContribuyente();
queryClient.invalidateQueries();
}}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.stopPropagation();
clearViewingTenant();
clearSelectedContribuyente();
queryClient.invalidateQueries();
}
}}
className="ml-1 p-0.5 rounded hover:bg-primary/20 cursor-pointer"
title="Volver a mi empresa"
>
<X className="h-3 w-3" />
</span>
)}
<ChevronDown className={cn('h-4 w-4 transition-transform', open && 'rotate-180')} />
</button>
{open && (
<div className="absolute top-full left-0 mt-2 w-72 rounded-lg border bg-card shadow-lg z-50">
<div className="p-2 border-b">
<p className="text-xs text-muted-foreground px-2">Seleccionar cliente</p>
</div>
<div className="max-h-64 overflow-y-auto p-1">
{isLoading ? (
<div className="px-3 py-2 text-sm text-muted-foreground">Cargando...</div>
) : tenants && tenants.length > 0 ? (
<>
{/* Option to go back to own tenant */}
<button
onClick={() => {
clearViewingTenant();
clearSelectedContribuyente();
setOpen(false);
queryClient.invalidateQueries();
}}
className={cn(
'flex w-full items-center gap-3 rounded-md px-3 py-2 text-sm hover:bg-accent transition-colors',
!viewingTenantId && 'bg-primary/10'
)}
>
<div className="h-8 w-8 rounded bg-primary/10 flex items-center justify-center">
<Building className="h-4 w-4 text-primary" />
</div>
<div className="flex-1 text-left">
<p className="font-medium">{user?.tenantName}</p>
<p className="text-xs text-muted-foreground">Mi empresa</p>
</div>
{!viewingTenantId && <Check className="h-4 w-4 text-primary" />}
</button>
<div className="my-1 border-t" />
{/* Other tenants */}
{tenants
.filter(t => t.id !== user?.tenantId)
.map((tenant) => (
<button
key={tenant.id}
onClick={() => {
setViewingTenant(tenant.id, tenant.nombre, tenant.rfc);
clearSelectedContribuyente();
setOpen(false);
queryClient.invalidateQueries();
}}
className={cn(
'flex w-full items-center gap-3 rounded-md px-3 py-2 text-sm hover:bg-accent transition-colors',
viewingTenantId === tenant.id && 'bg-primary/10'
)}
>
<div className="h-8 w-8 rounded bg-muted flex items-center justify-center text-xs font-medium">
{tenant.nombre.substring(0, 2).toUpperCase()}
</div>
<div className="flex-1 text-left">
<p className="font-medium truncate">{tenant.nombre}</p>
<p className="text-xs text-muted-foreground">{tenant.rfc}</p>
</div>
{viewingTenantId === tenant.id && <Check className="h-4 w-4 text-primary" />}
</button>
))}
</>
) : (
<div className="px-3 py-2 text-sm text-muted-foreground">
No hay otros clientes
</div>
)}
</div>
</div>
)}
</div>
);
}