Merge branch 'fix/transportes-traduccion-erronea' into feature/visible-clicks-csv

This commit is contained in:
2026-04-29 08:39:09 -06:00
7 changed files with 414 additions and 118 deletions

View File

@@ -4,7 +4,7 @@
import * as Card from '$lib/components/ui/card';
import { Button } from '$lib/components/ui/button';
import { Input } from '$lib/components/ui/input';
import { Plus, RefreshCw, Pencil, Trash2 } from 'lucide-svelte';
import { Plus, Pencil, Trash2 } from 'lucide-svelte';
// Importar componentes de la librería
import InfiniteDataTable from '$lib/components/dashboard/common/infinite-data-table.svelte';
@@ -16,6 +16,7 @@
import { browser } from '$app/environment';
import { useShortcuts } from '$lib/hooks/use-shortcuts';
import { obtenerAtajosCatalogoSimple } from '$lib/config/shortcuts/dashboard/general_catalogs/common/factory';
import { tv } from '$lib/i18n/vehicles';
// --- ESTADO ---
let data = $state<Vehicle[]>([]);
@@ -115,7 +116,7 @@
if (!selectedVehicle) return;
if (
!confirm(
`¿Estás seguro de eliminar el vehículo "${selectedVehicle.vehicle_key}"?\n\nNota: No se puede eliminar si tiene registros relacionados.`
tv('delete_confirm', { key: selectedVehicle.vehicle_key })
)
) {
return;
@@ -129,9 +130,9 @@
companyStore.activeCompany.id
);
if (response.error) {
alert(`❌ Error al eliminar:\n\n${response.error}`);
alert(`${tv('delete_error_title')}\n\n${response.error}`);
} else {
alert(`✅ Vehículo eliminado correctamente`);
alert(tv('delete_success'));
selectedIds = [];
loadData();
}
@@ -166,7 +167,7 @@
}
});
useShortcuts('Vehículos (transporte)', [
useShortcuts(tv('shortcuts_scope'), [
...obtenerAtajosCatalogoSimple({
manejarNuevo: () => {
createDialogOpen = true;
@@ -175,7 +176,7 @@
}),
{
key: 'Ctrl+S',
description: 'Guardar',
description: tv('shortcuts_save'),
action: () => {
if (!createDialogOpen) return;
document.dispatchEvent(new CustomEvent('save-form'));
@@ -189,20 +190,20 @@
<div class="flex flex-col gap-6 p-6 h-[calc(100svh-4rem)] group-has-data-[collapsible=icon]/sidebar-wrapper:h-[calc(100svh-3rem)] overflow-hidden">
<div class="flex items-center justify-between">
<div>
<h1 class="text-2xl font-bold tracking-tight">Vehículos (Transporte)</h1>
<h1 class="text-2xl font-bold tracking-tight">{tv('page_title')}</h1>
<p class="text-muted-foreground">
Gestión del catálogo de camiones y vehículos de transporte
{tv('page_subtitle')}
</p>
</div>
<div class="flex items-center gap-3"><Button class="h-9" onclick={() => { editingItem = null; createDialogOpen = true; }}><Plus class="mr-2 h-4 w-4" />Nuevo Vehículo</Button></div>
<div class="flex items-center gap-3"><Button class="h-9" onclick={() => { editingItem = null; createDialogOpen = true; }}><Plus class="mr-2 h-4 w-4" />{tv('new_vehicle')}</Button></div>
</div>
<Card.Root class="border bg-background flex flex-col">
<Card.Header><div class="flex flex-wrap items-center justify-between gap-3"><Card.Title>Listado de Vehículos</Card.Title><div class="flex flex-wrap items-center gap-2"><Input placeholder="Clave" class="h-9 w-40 bg-card lg:w-52" bind:value={searchKey} oninput={handleSearch} /><Input placeholder="Placas" class="h-9 w-40 bg-card lg:w-52" bind:value={searchPlate} oninput={handleSearch} /></div></div></Card.Header>
<Card.Content class="p-0">{#if loading && data.length === 0}<div class="flex h-64 items-center justify-center text-muted-foreground">Cargando vehículos...</div>{:else}<div class="rounded-md border bg-background overflow-hidden"><InfiniteDataTable {data} {columns} {loading} {hasMore} {loadMore} {selectedIds} onSelectedIdsChange={(ids) => (selectedIds = ids)} onRowClick={handleRowClick} onRowDoubleClick={handleRowDoubleClick} getRowId={(row) => row.vehicle_key} /></div>{/if}</Card.Content>
<Card.Header><div class="flex flex-wrap items-center justify-between gap-3"><Card.Title>{tv('vehicle_list')}</Card.Title><div class="flex flex-wrap items-center gap-2"><Input placeholder={tv('search_key')} class="h-9 w-40 bg-card lg:w-52" bind:value={searchKey} oninput={handleSearch} /><Input placeholder={tv('search_plate')} class="h-9 w-40 bg-card lg:w-52" bind:value={searchPlate} oninput={handleSearch} /></div></div></Card.Header>
<Card.Content class="p-0">{#if loading && data.length === 0}<div class="flex h-64 items-center justify-center text-muted-foreground">{tv('loading_vehicles')}</div>{:else}<div class="rounded-md border bg-background overflow-hidden"><InfiniteDataTable {data} {columns} {loading} {hasMore} {loadMore} {selectedIds} onSelectedIdsChange={(ids) => (selectedIds = ids)} onRowClick={handleRowClick} onRowDoubleClick={handleRowDoubleClick} getRowId={(row) => row.vehicle_key} /></div>{/if}</Card.Content>
</Card.Root>
<div class="flex-none text-sm text-muted-foreground">Mostrando {data.length} de {totalItems} registros</div>
<div class="flex-none text-sm text-muted-foreground">{tv('showing_records', { shown: data.length, total: totalItems })}</div>
<div class="h-20"></div>
@@ -220,7 +221,7 @@
disabled={selectedIds.length !== 1}
>
<Pencil size={16} class="mr-2" />
Editar
{tv('edit')}
</Button>
<Button
variant="outline"
@@ -230,7 +231,7 @@
class="text-destructive hover:bg-destructive/10 hover:text-destructive"
>
<Trash2 size={16} class="mr-2" />
Eliminar
{tv('delete')}
</Button>
</div>
</div>