feat: seguimiento auxiliares UI con tabs Asignadas/Sin asignar
- Componente seguimiento-auxiliares.tsx con tabs Asignadas/Sin asignar - Tabs internos Obligaciones/Tareas en cada vista - API client y hooks para asignaciones - Fix: invalidar query sin-asignar al asignar/desasignar
This commit is contained in:
@@ -5,12 +5,13 @@ import {
|
||||
Button, Card, CardContent, CardHeader, CardTitle, Input, Label,
|
||||
Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter,
|
||||
Select, SelectContent, SelectItem, SelectTrigger, SelectValue,
|
||||
Tabs, TabsList, TabsTrigger, TabsContent,
|
||||
cn,
|
||||
} from '@horux/shared-ui';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import {
|
||||
FolderOpen, Plus, Trash2, ChevronDown, ChevronUp, X,
|
||||
Users, Building2, FolderPlus, UserCog,
|
||||
Users, Building2, FolderPlus, UserCog, ClipboardList,
|
||||
} from 'lucide-react';
|
||||
import {
|
||||
useCarteras, useCreateCartera, useDeleteCartera,
|
||||
@@ -25,14 +26,16 @@ 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';
|
||||
import SeguimientoAuxiliares from './seguimiento-auxiliares';
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* SubcarteraCard */
|
||||
/* ------------------------------------------------------------------ */
|
||||
function SubcarteraCard({ sub, usuarios, contribuyentes, onDelete }: {
|
||||
function SubcarteraCard({ sub, usuarios, contribuyentes, parentEntidadIds, onDelete }: {
|
||||
sub: Cartera;
|
||||
usuarios: any[];
|
||||
contribuyentes: any[];
|
||||
parentEntidadIds: string[];
|
||||
onDelete: () => void;
|
||||
}) {
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
@@ -47,7 +50,7 @@ function SubcarteraCard({ sub, usuarios, contribuyentes, onDelete }: {
|
||||
);
|
||||
|
||||
const available = (contribuyentes ?? []).filter(
|
||||
(c: any) => !(entidadIds ?? []).includes(c.id)
|
||||
(c: any) => (parentEntidadIds ?? []).includes(c.id) && !(entidadIds ?? []).includes(c.id)
|
||||
);
|
||||
|
||||
const auxiliarUser = usuarios?.find((u: any) => u.id === sub.auxiliarUserId);
|
||||
@@ -319,6 +322,7 @@ function CarteraDetail({ cartera, canEdit = true, canManageSubcarteras = true }:
|
||||
sub={sub}
|
||||
usuarios={usuarios ?? []}
|
||||
contribuyentes={contribuyentes ?? []}
|
||||
parentEntidadIds={entidadIds ?? []}
|
||||
onDelete={() => handleDeleteSubcartera(sub.id)}
|
||||
/>
|
||||
))}
|
||||
@@ -396,6 +400,10 @@ export default function CarterasPage() {
|
||||
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 isSupervisor = userRole === 'supervisor';
|
||||
const isOwner = userRole === 'owner';
|
||||
const puedeVerSeguimiento = isOwner || isSupervisor;
|
||||
const [activeTab, setActiveTab] = useState('carteras');
|
||||
const { data: carteras, isLoading } = useCarteras();
|
||||
const { data: supervisores } = useSupervisores();
|
||||
const { data: usuarios } = useUsuarios();
|
||||
@@ -440,9 +448,43 @@ export default function CarterasPage() {
|
||||
}
|
||||
};
|
||||
|
||||
const CarterasList = () => (
|
||||
<>
|
||||
{isLoading ? (
|
||||
<p className="text-muted-foreground">Cargando...</p>
|
||||
) : !carteras || carteras.length === 0 ? (
|
||||
<Card>
|
||||
<CardContent className="flex flex-col items-center justify-center py-12 text-center">
|
||||
<FolderOpen className="h-12 w-12 text-muted-foreground mb-4" />
|
||||
<h3 className="text-lg font-semibold">Sin carteras</h3>
|
||||
<p className="text-sm text-muted-foreground mt-1 mb-4">
|
||||
Crea la primera cartera para organizar tus contribuyentes.
|
||||
</p>
|
||||
<Button onClick={() => setShowCreate(true)}>Crear primera cartera</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
) : (
|
||||
<div className="space-y-3">
|
||||
{carteras.map(cartera => (
|
||||
<CarteraCard
|
||||
key={cartera.id}
|
||||
cartera={cartera}
|
||||
expanded={expandedId === cartera.id}
|
||||
onToggle={() => setExpandedId(expandedId === cartera.id ? null : cartera.id)}
|
||||
onDelete={() => handleDelete(cartera)}
|
||||
usuarios={usuarios ?? []}
|
||||
canEdit={canEditCartera}
|
||||
canManageSubcarteras={canManageSubcarteras}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<DashboardShell title="Carteras">
|
||||
<div className="max-w-3xl mx-auto space-y-6">
|
||||
<div className="max-w-4xl mx-auto space-y-6">
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
@@ -450,42 +492,34 @@ export default function CarterasPage() {
|
||||
{isAuxiliar ? 'Carteras asignadas a ti' : 'Organiza contribuyentes en carteras y asigna subcarteras a cada auxiliar'}
|
||||
</p>
|
||||
</div>
|
||||
{canCreate && (
|
||||
{canCreate && activeTab === 'carteras' && (
|
||||
<Button onClick={() => setShowCreate(true)} className="flex items-center gap-2">
|
||||
<Plus className="h-4 w-4" /> Nueva cartera
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* List */}
|
||||
{isLoading ? (
|
||||
<p className="text-muted-foreground">Cargando...</p>
|
||||
) : !carteras || carteras.length === 0 ? (
|
||||
<Card>
|
||||
<CardContent className="flex flex-col items-center justify-center py-12 text-center">
|
||||
<FolderOpen className="h-12 w-12 text-muted-foreground mb-4" />
|
||||
<h3 className="text-lg font-semibold">Sin carteras</h3>
|
||||
<p className="text-sm text-muted-foreground mt-1 mb-4">
|
||||
Crea la primera cartera para organizar tus contribuyentes.
|
||||
</p>
|
||||
<Button onClick={() => setShowCreate(true)}>Crear primera cartera</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
{puedeVerSeguimiento ? (
|
||||
<Tabs value={activeTab} onValueChange={setActiveTab} defaultValue="carteras" className="space-y-4">
|
||||
<TabsList>
|
||||
<TabsTrigger value="carteras">
|
||||
<FolderOpen className="h-4 w-4 mr-1.5" /> Carteras
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="seguimiento">
|
||||
<ClipboardList className="h-4 w-4 mr-1.5" /> Seguimiento de Auxiliares
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="carteras">
|
||||
<CarterasList />
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="seguimiento">
|
||||
<SeguimientoAuxiliares />
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
) : (
|
||||
<div className="space-y-3">
|
||||
{carteras.map(cartera => (
|
||||
<CarteraCard
|
||||
key={cartera.id}
|
||||
cartera={cartera}
|
||||
expanded={expandedId === cartera.id}
|
||||
onToggle={() => setExpandedId(expandedId === cartera.id ? null : cartera.id)}
|
||||
onDelete={() => handleDelete(cartera)}
|
||||
usuarios={usuarios ?? []}
|
||||
canEdit={canEditCartera}
|
||||
canManageSubcarteras={canManageSubcarteras}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<CarterasList />
|
||||
)}
|
||||
|
||||
{/* Create dialog */}
|
||||
|
||||
Reference in New Issue
Block a user