Files
plantillas-proyectos/frontend/src/lib/components/dashboard/exchange-rate/data-table-actions.svelte
KevinMrkz3221 64b6f3e5c9 feat: implementar CRUD completo para exchange_rate, packages y seal
Backend:
- Corregir tipos datetime en exchange_rate (dto.py, models.py)
- Agregar datetime import en packages dto.py
- Corregir orden de parámetros en seal services.py
- Actualizar router.py con nuevas rutas

Frontend:
- Crear API clients para exchange-rate, packages y seal
- Implementar componentes de tabla con renderComponent
- Crear diálogos de crear/editar para cada módulo
- Implementar data-table-actions con manejo interno de diálogos
- Agregar páginas completas con filtros e infinite scroll
- Actualizar sidebar con nuevos módulos

Características:
- Acciones inline (editar/eliminar) totalmente funcionales
- Filtros de búsqueda específicos por módulo
- Paginación con infinite scroll
- Sincronización con companyStore
- Manejo de errores robusto
2025-12-02 20:46:41 -06:00

100 lines
2.5 KiB
Svelte

<script lang="ts">
import { Button } from '$lib/components/ui/button';
import * as DropdownMenu from '$lib/components/ui/dropdown-menu';
import { EllipsisVertical, Pencil, Trash2, LoaderCircle } from 'lucide-svelte';
import type { ExchangeRate } from '$lib/api/dashboard/a76/exchange-rate';
import { deleteExchangeRate } from '$lib/api/dashboard/a76/exchange-rate';
import { companyStore } from '$lib/stores/company.svelte';
import CreateEditDialog from './create-edit-dialog.svelte';
let {
item,
onSuccess
}: {
item: ExchangeRate;
onSuccess?: () => void;
} = $props();
let loading = $state(false);
let error = $state<string | null>(null);
let dialogOpen = $state(false);
let selectedItem = $state<ExchangeRate | null>(null);
async function handleDelete() {
if (!confirm('¿Está seguro de que desea eliminar este tipo de cambio?')) {
return;
}
const companyId = companyStore.activeCompany?.id;
if (!companyId) {
alert('No hay compañía seleccionada');
return;
}
loading = true;
error = null;
try {
await deleteExchangeRate(item.id, companyId);
// Éxito
if (onSuccess) {
onSuccess();
}
} catch (err: any) {
error = err.message || 'Error al eliminar el tipo de cambio';
alert(`Error: ${error}`);
console.error('Error deleting:', err);
} finally {
loading = false;
}
}
function handleEdit() {
selectedItem = item;
dialogOpen = true;
}
function handleDialogSuccess() {
dialogOpen = false;
selectedItem = null;
if (onSuccess) {
onSuccess();
}
}
</script>
<DropdownMenu.Root>
<DropdownMenu.Trigger>
{#snippet child({ props })}
<Button {...props} variant="ghost" size="icon" class="relative size-8 p-0">
<span class="sr-only">Abrir menú</span>
<EllipsisVertical size={16} />
</Button>
{/snippet}
</DropdownMenu.Trigger>
<DropdownMenu.Content align="end" class="w-[160px]">
<DropdownMenu.Label>Acciones</DropdownMenu.Label>
<DropdownMenu.Separator />
<DropdownMenu.Item onclick={handleEdit}>
<Pencil size={16} class="mr-2" />
Editar
</DropdownMenu.Item>
<DropdownMenu.Separator />
<DropdownMenu.Item onclick={handleDelete} class="text-destructive" disabled={loading}>
{#if loading}
<LoaderCircle class="mr-2 h-4 w-4 animate-spin" />
{:else}
<Trash2 size={16} class="mr-2" />
{/if}
Eliminar
</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu.Root>
<CreateEditDialog
bind:open={dialogOpen}
item={selectedItem}
onSuccess={handleDialogSuccess}
/>