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:
@@ -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' : ''}"
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user