Merge pull request 'eliminacion masiva y selector mas inteligente para mostrar informacion y deseleccionarse' (#434) from fix/clases-selector-delete into development

Reviewed-on: ADUANASOFT/anexo76#434
This commit is contained in:
2026-05-22 21:40:12 +00:00
2 changed files with 72 additions and 37 deletions

View File

@@ -156,15 +156,18 @@
onclick={(e) => {
if ((e.target as HTMLElement).closest('input[type="checkbox"]')) return;
const rowId = getRowIdValue(row.original);
if (rowId !== null) {
const isSelected = selectedIds.includes(rowId);
if (isSelected) {
onSelectedIdsChange?.(selectedIds.filter((id) => id !== rowId));
} else {
// El id clickeado va primero para que el cuadro informativo lo muestre
onSelectedIdsChange?.([rowId, ...selectedIds.filter((id) => id !== rowId)]);
}
if (rowId === null) return;
// Click sobre la fila activa (la del frente) la deselecciona.
// Click sobre cualquier otra fila la trae al frente (mostrar su info).
if (selectedIds[0] === rowId) {
onSelectedIdsChange?.(selectedIds.filter((id) => id !== rowId));
return;
}
if (selectedIds.includes(rowId)) {
onSelectedIdsChange?.([rowId, ...selectedIds.filter((id) => id !== rowId)]);
return;
}
onSelectedIdsChange?.([rowId, ...selectedIds]);
}}
ondblclick={() => onRowDoubleClick?.(row.original)}
class="cursor-pointer hover:bg-muted/50 transition-colors {row.getIsSelected() ? 'bg-primary/10' : ''}"

View File

@@ -290,15 +290,15 @@
function handleDelete() {
if (!canDelete) return;
if (!selectedClass) {
toast.error('Selecciona una clase para borrar');
if (selectedClassIds.length === 0) {
toast.error('Selecciona al menos una clase para borrar');
return;
}
showDeleteDialog = true;
}
async function confirmDelete() {
if (!selectedClass) return;
if (selectedClassIds.length === 0) return;
const companyId = companyStore.activeCompany?.id;
if (!companyId) {
@@ -306,24 +306,37 @@
return;
}
const classToDelete = selectedClass;
const idsToDelete = [...selectedClassIds];
let okCount = 0;
const errors: number[] = [];
try {
// El backend ahora elimina automáticamente la extensión FA si existe
await classesApi.delete(classToDelete.id, companyId);
toast.success(`Clase ${classToDelete.class_code} eliminada correctamente`);
// Recargar lista
await loadClasses();
selectedClassIds = [];
clearSelectedClass();
showDeleteDialog = false;
} catch (error) {
console.error('Error deleting class:', error);
toast.error('Error al eliminar la clase');
for (const id of idsToDelete) {
try {
// El backend elimina automáticamente la extensión FA si existe
await classesApi.delete(id, companyId);
okCount++;
} catch (error) {
console.error(`Error deleting class ${id}:`, error);
errors.push(id);
}
}
if (errors.length === 0) {
toast.success(
okCount === 1
? 'Clase eliminada correctamente'
: `${okCount} clases eliminadas correctamente`
);
} else if (okCount === 0) {
toast.error(`Error al eliminar ${errors.length} clase(s)`);
} else {
toast.error(`${okCount} eliminada(s), ${errors.length} con error`);
}
await loadClasses();
selectedClassIds = [];
clearSelectedClass();
showDeleteDialog = false;
}
// Keyboard Shortcuts
@@ -615,9 +628,14 @@
>
{/if}
{#if canDelete}
<Button variant="outline" size="sm" onclick={handleDelete} disabled={!selectedClass}
>Borrar</Button
<Button
variant="outline"
size="sm"
onclick={handleDelete}
disabled={selectedClassIds.length === 0}
>
Borrar{selectedClassIds.length > 1 ? ` (${selectedClassIds.length})` : ''}
</Button>
{/if}
</div>
</div>
@@ -903,14 +921,28 @@
<Dialog.Title>¿Confirmar eliminación?</Dialog.Title>
</Dialog.Header>
<div class="py-4">
<p class="text-sm text-muted-foreground">
¿Estás seguro que deseas eliminar la clase <strong class="text-foreground"
>{selectedClass?.class_code}</strong
>?
</p>
<p class="mt-2 text-sm text-muted-foreground">
{selectedClass?.description_es}
</p>
{#if selectedClassIds.length === 1}
<p class="text-sm text-muted-foreground">
¿Estás seguro que deseas eliminar la clase
<strong class="text-foreground">{selectedClass?.class_code}</strong>?
</p>
<p class="mt-2 text-sm text-muted-foreground">
{selectedClass?.description_es}
</p>
{:else}
<p class="text-sm text-muted-foreground">
¿Estás seguro que deseas eliminar
<strong class="text-foreground">{selectedClassIds.length}</strong> clases?
</p>
<ul class="mt-2 max-h-40 list-disc overflow-auto pl-5 text-sm text-muted-foreground">
{#each classes.filter((c) => selectedClassIds.includes(c.id)) as c (c.id)}
<li>
<strong class="text-foreground">{c.class_code}</strong>
{c.description_es ? ` — ${c.description_es}` : ''}
</li>
{/each}
</ul>
{/if}
<p class="mt-4 text-sm text-destructive">Esta acción no se puede deshacer.</p>
</div>
<Dialog.Footer>