'use client';
import { useState } from 'react';
import {
Button, Card, CardContent, CardHeader, CardTitle, Input, Label,
Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter,
Select, SelectContent, SelectItem, SelectTrigger, SelectValue,
cn,
} from '@horux/shared-ui';
import { useQueryClient } from '@tanstack/react-query';
import {
FolderOpen, Plus, Trash2, ChevronDown, ChevronUp, X,
Users, Building2, FolderPlus, UserCog,
} from 'lucide-react';
import {
useCarteras, useCreateCartera, useDeleteCartera,
useCarteraEntidades, useSubcarteras, useCreateSubcartera,
useSupervisores,
} from '@/lib/hooks/use-carteras';
import {
addEntidadToCartera, removeEntidadFromCartera,
} from '@/lib/api/carteras';
import { useContribuyentes } from '@/lib/hooks/use-contribuyentes';
import { useUsuarios } from '@/lib/hooks/use-usuarios';
import { useAuthStore } from '@/stores/auth-store';
import { DashboardShell } from '@/components/layouts/dashboard-shell';
import type { Cartera } from '@/lib/api/carteras';
/* ------------------------------------------------------------------ */
/* SubcarteraCard */
/* ------------------------------------------------------------------ */
function SubcarteraCard({ sub, usuarios, contribuyentes, onDelete }: {
sub: Cartera;
usuarios: any[];
contribuyentes: any[];
onDelete: () => void;
}) {
const [expanded, setExpanded] = useState(false);
const qc = useQueryClient();
const { data: entidadIds, isLoading } = useCarteraEntidades(expanded ? sub.id : null);
const [addingEntidad, setAddingEntidad] = useState(false);
const [selectedEntidadId, setSelectedEntidadId] = useState('');
const [busy, setBusy] = useState(false);
const entidadMap = Object.fromEntries(
(contribuyentes ?? []).map((c: any) => [c.id, { rfc: c.rfc, nombre: c.nombre }])
);
const available = (contribuyentes ?? []).filter(
(c: any) => !(entidadIds ?? []).includes(c.id)
);
const auxiliarUser = usuarios?.find((u: any) => u.id === sub.auxiliarUserId);
const invalidate = () => {
qc.invalidateQueries({ queryKey: ['cartera-entidades', sub.id] });
qc.invalidateQueries({ queryKey: ['subcarteras'] });
qc.invalidateQueries({ queryKey: ['carteras'] });
};
const handleAddEntidad = async () => {
if (!selectedEntidadId) return;
setBusy(true);
try {
await addEntidadToCartera(sub.id, selectedEntidadId);
setSelectedEntidadId('');
setAddingEntidad(false);
invalidate();
} finally { setBusy(false); }
};
const handleRemoveEntidad = async (entidadId: string) => {
setBusy(true);
try {
await removeEntidadFromCartera(sub.id, entidadId);
invalidate();
} finally { setBusy(false); }
};
return (
{expanded && (
{!addingEntidad && (
)}
{addingEntidad && (
)}
{isLoading ? (
Cargando...
) : !entidadIds || entidadIds.length === 0 ? (
Sin RFCs asignados a esta subcartera.
) : (
{entidadIds.map(id => {
const info = entidadMap[id];
return (
-
{info ? <>{info.rfc} {info.nombre}> : id}
);
})}
)}
)}
);
}
/* ------------------------------------------------------------------ */
/* CarteraDetail */
/* ------------------------------------------------------------------ */
function CarteraDetail({ cartera, canEdit = true, canManageSubcarteras = true }: { cartera: Cartera; canEdit?: boolean; canManageSubcarteras?: boolean }) {
const qc = useQueryClient();
const { data: contribuyentes } = useContribuyentes();
const { data: usuarios } = useUsuarios();
const { data: entidadIds, isLoading: loadingEntidades } = useCarteraEntidades(cartera.id);
const { data: subcarteras, isLoading: loadingSubs } = useSubcarteras(cartera.id);
const createSub = useCreateSubcartera();
const [addingEntidad, setAddingEntidad] = useState(false);
const [selectedEntidadId, setSelectedEntidadId] = useState('');
const [showCreateSub, setShowCreateSub] = useState(false);
const [subForm, setSubForm] = useState({ nombre: '', auxiliarUserId: '' });
const [busy, setBusy] = useState(false);
const entidadMap = Object.fromEntries(
(contribuyentes ?? []).map((c) => [c.id, { rfc: c.rfc, nombre: c.nombre }])
);
const available = (contribuyentes ?? []).filter(
(c) => !(entidadIds ?? []).includes(c.id)
);
// Auxiliares available for subcarteras (those assigned to this supervisor)
const auxiliares = (usuarios ?? []).filter((u: any) => u.role === 'auxiliar');
const supervisorUser = usuarios?.find((u: any) => u.id === cartera.supervisorUserId);
const invalidate = () => {
qc.invalidateQueries({ queryKey: ['cartera-entidades', cartera.id] });
qc.invalidateQueries({ queryKey: ['subcarteras', cartera.id] });
qc.invalidateQueries({ queryKey: ['carteras'] });
};
const handleAddEntidad = async () => {
if (!selectedEntidadId) return;
setBusy(true);
try {
await addEntidadToCartera(cartera.id, selectedEntidadId);
setSelectedEntidadId('');
setAddingEntidad(false);
invalidate();
} finally { setBusy(false); }
};
const handleRemoveEntidad = async (entidadId: string) => {
setBusy(true);
try {
await removeEntidadFromCartera(cartera.id, entidadId);
invalidate();
} finally { setBusy(false); }
};
const handleCreateSubcartera = async () => {
if (!subForm.nombre.trim() || !subForm.auxiliarUserId) return;
try {
await createSub.mutateAsync({
carteraId: cartera.id,
nombre: subForm.nombre.trim(),
auxiliarUserId: subForm.auxiliarUserId,
});
setSubForm({ nombre: '', auxiliarUserId: '' });
setShowCreateSub(false);
} catch (err: any) {
alert(err.response?.data?.message || 'Error al crear subcartera');
}
};
const handleDeleteSubcartera = async (subId: string) => {
if (!confirm('¿Eliminar esta subcartera?')) return;
try {
const { deleteCartera } = await import('@/lib/api/carteras');
await deleteCartera(subId);
invalidate();
} catch (err: any) {
alert(err.response?.data?.message || 'Error al eliminar');
}
};
return (
{/* Supervisor info */}
{supervisorUser && (
Supervisor: {supervisorUser.nombre} ({supervisorUser.email})
)}
{/* ---- Contribuyentes ---- */}
Contribuyentes ({entidadIds?.length || 0})
{canEdit && !addingEntidad && (
)}
{canEdit && addingEntidad && (
)}
{loadingEntidades ? (
Cargando...
) : !entidadIds || entidadIds.length === 0 ? (
Sin contribuyentes asignados.
) : (
{entidadIds.map(id => {
const info = entidadMap[id];
return (
-
{info ? <>{info.rfc} {info.nombre}> : {id}}
{canEdit && }
);
})}
)}
{/* ---- Subcarteras ---- */}
Subcarteras ({subcarteras?.length || 0})
{canManageSubcarteras && !showCreateSub && (
)}
{canManageSubcarteras && showCreateSub && (
)}
{loadingSubs ? (
Cargando...
) : !subcarteras || subcarteras.length === 0 ? (
Sin subcarteras. Crea una para asignar RFCs a un auxiliar.
) : (
{subcarteras.map(sub => (
handleDeleteSubcartera(sub.id)}
/>
))}
)}
);
}
/* ------------------------------------------------------------------ */
/* CarteraCard */
/* ------------------------------------------------------------------ */
function CarteraCard({ cartera, expanded, onToggle, onDelete, usuarios, canEdit, canManageSubcarteras }: {
cartera: Cartera;
expanded: boolean;
onToggle: () => void;
onDelete: () => void;
usuarios: any[];
canEdit: boolean;
canManageSubcarteras: boolean;
}) {
const supervisorUser = usuarios?.find((u: any) => u.id === cartera.supervisorUserId);
return (
{canEdit && (
)}
{supervisorUser && (
{supervisorUser.nombre}
)}
{cartera.entidadesCount} RFCs
{cartera.subcarterasCount} subcarteras
{expanded && (
)}
);
}
/* ------------------------------------------------------------------ */
/* Page */
/* ------------------------------------------------------------------ */
export default function CarterasPage() {
const { user } = useAuthStore();
const userRole = user?.role || 'visor';
const canCreate = userRole === 'owner'; // Create top-level carteras
const canEditCartera = userRole === 'owner'; // Edit/delete top-level carteras + add/remove RFCs
const canManageSubcarteras = userRole === 'owner' || userRole === 'supervisor'; // Create subcarteras
const isAuxiliar = userRole === 'auxiliar';
const { data: carteras, isLoading } = useCarteras();
const { data: supervisores } = useSupervisores();
const { data: usuarios } = useUsuarios();
const createMut = useCreateCartera();
const deleteMut = useDeleteCartera();
const [expandedId, setExpandedId] = useState(null);
const [showCreate, setShowCreate] = useState(false);
const [form, setForm] = useState({ nombre: '', descripcion: '', supervisorUserId: '' });
const hasSupervisores = supervisores && supervisores.length > 0;
const resetForm = () => {
setForm({ nombre: '', descripcion: '', supervisorUserId: '' });
setShowCreate(false);
};
const handleCreate = async () => {
if (!form.nombre.trim()) return;
try {
const supervisorUserId = form.supervisorUserId && form.supervisorUserId !== '__self__'
? form.supervisorUserId : undefined;
const cartera = await createMut.mutateAsync({
nombre: form.nombre.trim(),
descripcion: form.descripcion.trim() || undefined,
supervisorUserId,
});
resetForm();
setExpandedId(cartera.id);
} catch (err: any) {
alert(err.response?.data?.message || 'Error al crear cartera');
}
};
const handleDelete = async (cartera: Cartera) => {
if (!confirm(`¿Eliminar la cartera "${cartera.nombre}"? Se eliminarán también sus subcarteras.`)) return;
try {
await deleteMut.mutateAsync(cartera.id);
if (expandedId === cartera.id) setExpandedId(null);
} catch (err: any) {
alert(err.response?.data?.message || 'Error al eliminar cartera');
}
};
return (
{/* Header */}
{isAuxiliar ? 'Carteras asignadas a ti' : 'Organiza contribuyentes en carteras y asigna subcarteras a cada auxiliar'}
{canCreate && (
)}
{/* List */}
{isLoading ? (
Cargando...
) : !carteras || carteras.length === 0 ? (
Sin carteras
Crea la primera cartera para organizar tus contribuyentes.
) : (
{carteras.map(cartera => (
setExpandedId(expandedId === cartera.id ? null : cartera.id)}
onDelete={() => handleDelete(cartera)}
usuarios={usuarios ?? []}
canEdit={canEditCartera}
canManageSubcarteras={canManageSubcarteras}
/>
))}
)}
{/* Create dialog */}
);
}