Files
plantillas-proyectos/frontend/src/lib/components/dashboard/packages/create-edit-dialog.svelte

261 lines
6.4 KiB
Svelte

<script lang="ts">
import { Button } from "$lib/components/ui/button";
import * as Dialog from "$lib/components/ui/dialog";
import { Input } from "$lib/components/ui/input";
import { Label } from "$lib/components/ui/label";
import { createPackage, updatePackage, type Package} from "$lib/api/dashboard/a76/general_catalogs/packages";
import { companyStore } from "$lib/stores/company.svelte";
let {
open = $bindable(false),
item = null,
onSuccess
}: {
open: boolean;
item?: Package | null;
onSuccess?: () => void;
} = $props();
// Determinar si es modo edición o creación
const isEdit = $derived(!!item);
const title = $derived(isEdit ? "Editar Bulto" : "Nuevo Bulto");
// Estado del formulario
let formData = $state({
key: item?.key || '',
description_es: item?.description_es || '',
description_en: item?.description_en || '',
weight_unit: item?.weight_unit || null,
plurals: item?.plurals || '',
plural_in: item?.plural_in || '',
code_ace: item?.code_ace || '',
code_aamex: item?.code_aamex || ''
});
let loading = $state(false);
let error = $state<string | null>(null);
// Resetear formulario cuando cambia el item
$effect(() => {
if (item) {
formData = {
key: item.key,
description_es: item.description_es || '',
description_en: item.description_en || '',
weight_unit: item.weight_unit,
plurals: item.plurals || '',
plural_in: item.plural_in || '',
code_ace: item.code_ace || '',
code_aamex: item.code_aamex || ''
};
} else {
formData = {
key: '',
description_es: '',
description_en: '',
weight_unit: null,
plurals: '',
plural_in: '',
code_ace: '',
code_aamex: ''
};
}
});
async function handleSubmit() {
error = null;
loading = true;
try {
const companyId = companyStore.activeCompany?.id;
if (!companyId) {
throw new Error('No hay una compañía seleccionada');
}
// Validación básica
if (!formData.key.trim()) {
throw new Error('La clave es requerida');
}
if (formData.key.length > 5) {
throw new Error('La clave no puede tener más de 5 caracteres');
}
// Preparar datos
const dataToSend = {
key: formData.key.trim(),
description_es: formData.description_es.trim() || null,
description_en: formData.description_en.trim() || null,
weight_unit: formData.weight_unit,
plurals: formData.plurals.trim() || null,
plural_in: formData.plural_in.trim() || null,
code_ace: formData.code_ace.trim() || null,
code_aamex: formData.code_aamex.trim() || null
};
let response;
if (isEdit && item) {
response = await updatePackage(item.id, dataToSend, companyId);
} else {
response = await createPackage(dataToSend, companyId);
}
if (response.error) {
throw new Error(response.error);
}
// Cerrar diálogo y notificar éxito
open = false;
if (onSuccess) {
onSuccess();
}
} catch (e) {
error = e instanceof Error ? e.message : 'Error al guardar el bulto';
} finally {
loading = false;
}
}
function handleCancel() {
open = false;
error = null;
}
</script>
<Dialog.Root bind:open>
<Dialog.Content class="max-w-2xl max-h-[90vh] overflow-y-auto">
<Dialog.Header>
<Dialog.Title>{title}</Dialog.Title>
<Dialog.Description>
{isEdit ? 'Modifica los datos del bulto' : 'Completa los datos para crear un nuevo bulto'}
</Dialog.Description>
</Dialog.Header>
<form onsubmit={(e) => { e.preventDefault(); handleSubmit(); }} class="space-y-4">
{#if error}
<div class="rounded-md bg-destructive/15 p-3 text-sm text-destructive">
{error}
</div>
{/if}
<div class="grid gap-4">
<!-- Clave -->
<div class="grid gap-2">
<Label for="key">
Clave <span class="text-destructive">*</span>
</Label>
<Input
id="key"
bind:value={formData.key}
placeholder="Ej: CAJA"
maxlength={5}
required
disabled={isEdit}
/>
<p class="text-xs text-muted-foreground">
Máximo 5 caracteres. {isEdit ? 'No se puede modificar en edición.' : ''}
</p>
</div>
<!-- Descripciones -->
<div class="grid grid-cols-2 gap-4">
<div class="grid gap-2">
<Label for="description_es">Descripción (Español)</Label>
<Input
id="description_es"
bind:value={formData.description_es}
placeholder="Ej: Caja de cartón"
maxlength={40}
/>
</div>
<div class="grid gap-2">
<Label for="description_en">Descripción (Inglés)</Label>
<Input
id="description_en"
bind:value={formData.description_en}
placeholder="Ej: Cardboard box"
maxlength={40}
/>
</div>
</div>
<!-- Peso Unitario -->
<div class="grid gap-2">
<Label for="weight_unit">Peso Unitario</Label>
<Input
id="weight_unit"
type="number"
step="0.00000001"
bind:value={formData.weight_unit}
placeholder="0.00"
/>
<p class="text-xs text-muted-foreground">
Peso unitario del bulto (hasta 8 decimales)
</p>
</div>
<!-- Plurales -->
<div class="grid grid-cols-2 gap-4">
<div class="grid gap-2">
<Label for="plurals">Plural</Label>
<Input
id="plurals"
bind:value={formData.plurals}
placeholder="Ej: CAJS"
maxlength={4}
/>
</div>
<div class="grid gap-2">
<Label for="plural_in">Plural (Inglés)</Label>
<Input
id="plural_in"
bind:value={formData.plural_in}
placeholder="Ej: BOXS"
maxlength={4}
/>
</div>
</div>
<!-- Códigos -->
<div class="grid grid-cols-2 gap-4">
<div class="grid gap-2">
<Label for="code_ace">Código ACE</Label>
<Input
id="code_ace"
bind:value={formData.code_ace}
placeholder="Código ACE"
maxlength={4}
/>
</div>
<div class="grid gap-2">
<Label for="code_aamex">Código AAMEX</Label>
<Input
id="code_aamex"
bind:value={formData.code_aamex}
placeholder="Código AAMEX"
maxlength={9}
/>
</div>
</div>
</div>
<Dialog.Footer>
<Button
type="button"
variant="outline"
onclick={handleCancel}
disabled={loading}
>
Cancelar
</Button>
<Button type="submit" disabled={loading}>
{loading ? 'Guardando...' : isEdit ? 'Actualizar' : 'Crear'}
</Button>
</Dialog.Footer>
</form>
</Dialog.Content>
</Dialog.Root>