fix/transportes-no-traducido

This commit is contained in:
2026-04-24 16:17:43 -06:00
parent 1fe0d66f4f
commit 2a2ef8ff86

View File

@@ -4,6 +4,7 @@
import { Input } from '$lib/components/ui/input';
import { Label } from '$lib/components/ui/label';
import * as Select from '$lib/components/ui/select';
import * as Tabs from '$lib/components/ui/tabs';
import { vehiclesApi, type Vehicle } from '$lib/api/dashboard/a76/vehicles';
import { transportersApi, type Transporter } from '$lib/api/dashboard/a76/transporters';
import { transportTypesApi } from '$lib/api/dashboard/reference_data/transport_types';
@@ -72,6 +73,29 @@
{ value: 'B', label: 'B' }
];
const TRANSPORT_TYPE_TRANSLATIONS: Record<string, string> = {
AR: 'Camión Blindado',
AU: 'Automóviles',
BT: 'Camión de Caja',
BU: 'Autobús',
BV: 'Camión de Bebidas',
BY: 'Bicicleta',
CO: 'Vehículo de Construcción',
EV: 'Vehículo de Emergencia',
FE: 'Ferry',
FM: 'Tractor Agrícola',
GB: 'Camión de Basura',
MC: 'Motocicleta',
OC: 'Otro',
PM: 'Camioneta con cabina',
PN: 'Camión Panel',
PU: 'Camioneta (Pick-up)',
PV: 'Pasajero',
RV: 'Vehículo Recreativo (RV)',
TR: 'Tractocamión',
TV: 'Van'
};
const countryM3 = $derived(
countries.find((c) => c.ame_key === formData.country)?.m3_key ?? null
);
@@ -209,7 +233,7 @@
</script>
<Dialog.Root bind:open>
<Dialog.Content class="max-h-[90vh] max-w-4xl overflow-y-auto">
<Dialog.Content class="max-h-[95vh] max-w-3xl overflow-y-auto">
<Dialog.Header>
<Dialog.Title>{title}</Dialog.Title>
<Dialog.Description>
@@ -232,221 +256,263 @@
</div>
{/if}
<div class="grid grid-cols-1 gap-6 md:grid-cols-2">
<!-- Información del Vehículo -->
<section class="space-y-4">
<h3 class="border-b pb-2 text-sm font-semibold">Identificación del Vehículo</h3>
<Tabs.Root value="general" class="w-full">
<Tabs.List class="grid w-full grid-cols-2">
<Tabs.Trigger value="general">Información General</Tabs.Trigger>
<Tabs.Trigger value="details">Seguro y Detalles</Tabs.Trigger>
</Tabs.List>
<div class="grid gap-2">
<Label for="vehicle_key"
>Clave del Vehículo <span class="text-destructive">*</span></Label
>
<Input
id="vehicle_key"
bind:value={formData.vehicle_key}
disabled={isEdit}
required
maxlength={14}
/>
</div>
<Tabs.Content value="general" class="mt-6 space-y-8">
<!-- Información del Vehículo -->
<section class="space-y-4">
<h3 class="border-b pb-2 text-sm font-bold uppercase tracking-wider text-muted-foreground">
Identificación del Vehículo
</h3>
<div class="grid grid-cols-2 gap-4">
<div class="grid gap-2">
<Label for="brand">Marca</Label>
<Input id="brand" bind:value={formData.brand} maxlength={20} />
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<div class="grid gap-2 md:col-span-2">
<Label for="vehicle_key"
>Clave del Vehículo <span class="text-destructive">*</span></Label
>
<Input
id="vehicle_key"
bind:value={formData.vehicle_key}
disabled={isEdit}
required
maxlength={14}
placeholder="Ej: VH001"
/>
</div>
<div class="grid gap-2">
<Label for="brand">Marca</Label>
<Input id="brand" bind:value={formData.brand} maxlength={20} placeholder="Ej: Kenworth" />
</div>
<div class="grid gap-2">
<Label for="year">Año</Label>
<Input id="year" bind:value={formData.year} maxlength={4} placeholder="YYYY" />
</div>
<div class="grid gap-2">
<Label for="plate_number">Placas</Label>
<Input id="plate_number" bind:value={formData.plate_number} maxlength={17} placeholder="Placas actuales" />
</div>
<div class="grid gap-2">
<Label for="series">Serie / VIN</Label>
<Input id="series" bind:value={formData.series} maxlength={30} placeholder="Número de serie" />
</div>
</div>
<div class="grid gap-2">
<Label for="year">Año</Label>
<Input id="year" bind:value={formData.year} maxlength={4} placeholder="YYYY" />
</section>
<!-- Datos de Transporte -->
<section class="space-y-4">
<h3 class="border-b pb-2 text-sm font-bold uppercase tracking-wider text-muted-foreground">
Datos de Transporte
</h3>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<div class="grid gap-2 md:col-span-2">
<Label for="transporter_key">Transportista</Label>
<Select.Root type="single" bind:value={formData.transporter_key} disabled={refsLoading}>
<Select.Trigger class="w-full">
{refsLoading
? '...'
: formData.transporter_key
? `${formData.transporter_key} ${transporters.find((t) => t.transporter_key === formData.transporter_key)?.name ?? ''}`
: '— Seleccionar transportista —'}
</Select.Trigger>
<Select.Content class="max-h-60">
<Select.Item value="" label="Vacío">— Vacío —</Select.Item>
{#each transporters as t}
<Select.Item value={t.transporter_key} label={t.transporter_key}>
{t.transporter_key} — {t.name || t.short_name || ''}
</Select.Item>
{/each}
</Select.Content>
</Select.Root>
</div>
<div class="grid gap-2">
<Label for="transport_identifier">ID Transporte</Label>
<Input
id="transport_identifier"
bind:value={formData.transport_identifier}
maxlength={30}
placeholder="Identificador único"
/>
</div>
<div class="grid gap-2">
<Label for="transport_type">Tipo de Transporte</Label>
<Select.Root type="single" bind:value={formData.transport_type} disabled={refsLoading}>
<Select.Trigger class="w-full" id="transport_type">
{refsLoading
? '...'
: formData.transport_type
? `${formData.transport_type} ${TRANSPORT_TYPE_TRANSLATIONS[formData.transport_type] || transportTypes.find((x) => x.transport_code === formData.transport_type)?.description || ''}`
: '— Opcional —'}
</Select.Trigger>
<Select.Content>
<Select.Item value="" label="Vacío">— Vacío —</Select.Item>
{#each transportTypes as x}
<Select.Item value={x.transport_code} label={x.transport_code}>
{x.transport_code} — {TRANSPORT_TYPE_TRANSLATIONS[x.transport_code] || x.description}
</Select.Item>
{/each}
</Select.Content>
</Select.Root>
</div>
<div class="grid gap-2">
<Label for="entity_code">Código de Entidad</Label>
<Select.Root type="single" bind:value={formData.entity_code}>
<Select.Trigger class="w-full" id="entity_code">
{ENTITY_OPTS.find((o) => o.value === (formData.entity_code || ''))?.label ??
'— Sin código —'}
</Select.Trigger>
<Select.Content>
{#each ENTITY_OPTS as o}
<Select.Item value={o.value} label={o.label}>{o.label}</Select.Item>
{/each}
</Select.Content>
</Select.Root>
<p class="text-[10px] text-muted-foreground uppercase">Obligatorio al crear (reglas CSV)</p>
</div>
<div class="grid gap-2">
<Label for="sct_permission">Permiso SCT</Label>
<Input id="sct_permission" bind:value={formData.sct_permission} maxlength={40} placeholder="Número de permiso" />
</div>
</div>
</div>
</section>
</Tabs.Content>
<div class="grid gap-2">
<Label for="plate_number">Placas</Label>
<Input id="plate_number" bind:value={formData.plate_number} maxlength={17} />
</div>
<Tabs.Content value="details" class="mt-6 space-y-8">
<!-- Seguro y Otros -->
<section class="space-y-4">
<h3 class="border-b pb-2 text-sm font-bold uppercase tracking-wider text-muted-foreground">
Seguro y Otros
</h3>
<div class="grid gap-2">
<Label for="series">Serie / VIN</Label>
<Input id="series" bind:value={formData.series} maxlength={30} />
</div>
</section>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<div class="grid gap-2 md:col-span-2">
<Label for="insurance_company_name">Aseguradora</Label>
<Input
id="insurance_company_name"
bind:value={formData.insurance_company_name}
maxlength={30}
placeholder="Nombre de la compañía"
/>
</div>
<!-- Datos de Transporte -->
<section class="space-y-4">
<h3 class="border-b pb-2 text-sm font-semibold">Datos de Transporte</h3>
<div class="grid gap-2">
<Label for="insurance_number">Póliza</Label>
<Input
id="insurance_number"
bind:value={formData.insurance_number}
maxlength={20}
placeholder="Número de póliza"
/>
</div>
<div class="grid gap-2">
<Label for="insurance_amount">Monto</Label>
<Input
id="insurance_amount"
type="number"
bind:value={formData.insurance_amount}
placeholder="0.00"
/>
</div>
<div class="grid gap-2">
<Label for="transporter_key">Clave Transportista</Label>
<Select.Root type="single" bind:value={formData.transporter_key} disabled={refsLoading}>
<Select.Trigger class="w-full">
{refsLoading
? '...'
: formData.transporter_key
? `${formData.transporter_key} ${transporters.find((t) => t.transporter_key === formData.transporter_key)?.name ?? ''}`
: '— Opcional —'}
</Select.Trigger>
<Select.Content class="max-h-60">
<Select.Item value="" label="Vacío">— Vacío —</Select.Item>
{#each transporters as t}
<Select.Item value={t.transporter_key} label={t.transporter_key}>
{t.transporter_key} — {t.name || t.short_name || ''}
</Select.Item>
{/each}
</Select.Content>
</Select.Root>
</div>
<div class="grid gap-2">
<Label for="transport_identifier">Identificador Transporte</Label>
<Input
id="transport_identifier"
bind:value={formData.transport_identifier}
maxlength={30}
/>
</div>
<div class="grid gap-2">
<Label for="transport_type">Tipo de Transporte</Label>
<Select.Root type="single" bind:value={formData.transport_type} disabled={refsLoading}>
<Select.Trigger class="w-full" id="transport_type">
{refsLoading
? '...'
: formData.transport_type
? `${formData.transport_type} ${transportTypes.find((x) => x.transport_code === formData.transport_type)?.description ?? ''}`
: '— Opcional —'}
</Select.Trigger>
<Select.Content>
<Select.Item value="" label="Vacío">— Vacío —</Select.Item>
{#each transportTypes as x}
<Select.Item value={x.transport_code} label={x.transport_code}>
{x.transport_code} — {x.description}
</Select.Item>
{/each}
</Select.Content>
</Select.Root>
</div>
<div class="grid gap-2">
<Label for="entity_code">Código de entidad</Label>
<Select.Root type="single" bind:value={formData.entity_code}>
<Select.Trigger class="w-full" id="entity_code">
{ENTITY_OPTS.find((o) => o.value === (formData.entity_code || ''))?.label ??
'— Sin código —'}
</Select.Trigger>
<Select.Content>
{#each ENTITY_OPTS as o}
<Select.Item value={o.value} label={o.label}>{o.label}</Select.Item>
{/each}
</Select.Content>
</Select.Root>
<p class="text-xs text-muted-foreground">Obligatorio al crear (reglas CSV).</p>
</div>
<div class="grid gap-2">
<Label for="sct_permission">Permiso SCT</Label>
<Input id="sct_permission" bind:value={formData.sct_permission} maxlength={40} />
</div>
</section>
<!-- Seguro y Otros -->
<section class="space-y-4">
<h3 class="border-b pb-2 text-sm font-semibold">Seguro y Otros</h3>
<div class="grid gap-2">
<Label for="insurance_company_name">Aseguradora</Label>
<Input
id="insurance_company_name"
bind:value={formData.insurance_company_name}
maxlength={30}
/>
</div>
<div class="grid grid-cols-2 gap-4">
<div class="grid gap-2">
<Label for="insurance_number">Póliza</Label>
<Input id="insurance_number" bind:value={formData.insurance_number} maxlength={20} />
<div class="grid gap-2">
<Label for="dot_number">Número DOT</Label>
<Input id="dot_number" bind:value={formData.dot_number} maxlength={8} placeholder="DOT ID" />
</div>
</div>
<div class="grid gap-2">
<Label for="insurance_amount">Monto Seguro</Label>
<Input id="insurance_amount" type="number" bind:value={formData.insurance_amount} />
</section>
<!-- Ubicación y Detalles -->
<section class="space-y-4">
<h3 class="border-b pb-2 text-sm font-bold uppercase tracking-wider text-muted-foreground">
Ubicación y Detalles
</h3>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<div class="grid gap-2">
<Label for="country">País (AME)</Label>
<Select.Root type="single" bind:value={formData.country} disabled={refsLoading}>
<Select.Trigger class="w-full" id="country">
{refsLoading
? '...'
: formData.country
? `${formData.country} ${countries.find((c) => c.ame_key === formData.country)?.description_es ?? ''}`
: '— Opcional —'}
</Select.Trigger>
<Select.Content class="max-h-60">
<Select.Item value="" label="Vacío">— Vacío —</Select.Item>
{#each countries as c}
<Select.Item value={c.ame_key} label={c.ame_key}>
{c.ame_key}{c.description_es}
</Select.Item>
{/each}
</Select.Content>
</Select.Root>
</div>
<div class="grid gap-2">
<Label for="state">Estado</Label>
<Select.Root type="single" bind:value={formData.state} disabled={refsLoading}>
<Select.Trigger class="w-full" id="state">
{refsLoading
? '...'
: formData.state ||
(formData.country ? '— Selecciona —' : '— Primero el país —')}
</Select.Trigger>
<Select.Content class="max-h-60">
<Select.Item value="" label="Vacío">— Vacío —</Select.Item>
{#each statesFiltered as s}
<Select.Item value={s.description} label={s.description}>
{s.description}
</Select.Item>
{/each}
</Select.Content>
</Select.Root>
</div>
<div class="grid gap-2">
<Label for="city">Ciudad</Label>
<Input id="city" bind:value={formData.city} maxlength={30} placeholder="Ciudad/Localidad" />
</div>
<div class="grid gap-2">
<Label for="color">Color</Label>
<Input id="color" bind:value={formData.color} maxlength={20} placeholder="Color del vehículo" />
</div>
<div class="grid gap-2">
<Label for="container_key">Tipo Contenedor</Label>
<Input
id="container_key"
bind:value={formData.container_key}
maxlength={3}
placeholder="Ej: 40G"
/>
</div>
</div>
</div>
</section>
<div class="grid gap-2">
<Label for="dot_number">Número DOT</Label>
<Input id="dot_number" bind:value={formData.dot_number} maxlength={8} />
</div>
</section>
<!-- Ubicación y Detalles -->
<section class="space-y-4">
<h3 class="border-b pb-2 text-sm font-semibold">Ubicación y Detalles</h3>
<div class="grid grid-cols-2 gap-4">
<section class="space-y-4 pt-4">
<div class="grid gap-2">
<Label for="country">País (clave americana)</Label>
<Select.Root type="single" bind:value={formData.country} disabled={refsLoading}>
<Select.Trigger class="w-full" id="country">
{refsLoading
? '...'
: formData.country
? `${formData.country} ${countries.find((c) => c.ame_key === formData.country)?.description_es ?? ''}`
: '— Opcional —'}
</Select.Trigger>
<Select.Content class="max-h-60">
<Select.Item value="" label="Vacío">— Vacío —</Select.Item>
{#each countries as c}
<Select.Item value={c.ame_key} label={c.ame_key}>
{c.ame_key}{c.description_es}
</Select.Item>
{/each}
</Select.Content>
</Select.Root>
</div>
<div class="grid gap-2">
<Label for="state">Estado / provincia</Label>
<Select.Root type="single" bind:value={formData.state} disabled={refsLoading}>
<Select.Trigger class="w-full" id="state">
{refsLoading
? '...'
: formData.state ||
(formData.country ? '— Selecciona —' : '— Primero el país —')}
</Select.Trigger>
<Select.Content class="max-h-60">
<Select.Item value="" label="Vacío">— Vacío —</Select.Item>
{#each statesFiltered as s}
<Select.Item value={s.description} label={s.description}>
{s.description}
</Select.Item>
{/each}
</Select.Content>
</Select.Root>
</div>
</div>
<div class="grid gap-2">
<Label for="description">Descripción</Label>
<Input id="description" bind:value={formData.description} maxlength={100} />
</div>
<div class="grid grid-cols-2 gap-4">
<div class="grid gap-2">
<Label for="color">Color</Label>
<Input id="color" bind:value={formData.color} maxlength={20} />
</div>
<div class="grid gap-2">
<Label for="container_key">Contenedor</Label>
<Label for="description">Descripción Adicional</Label>
<Input
id="container_key"
bind:value={formData.container_key}
maxlength={3}
placeholder="3 car."
id="description"
bind:value={formData.description}
maxlength={100}
placeholder="Notas adicionales sobre el vehículo..."
/>
</div>
</div>
</section>
</div>
</section>
</Tabs.Content>
</Tabs.Root>
<Dialog.Footer>
<Button type="button" variant="outline" onclick={handleCancel} disabled={loading}>