185 lines
4.2 KiB
Svelte
185 lines
4.2 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 { Switch } from "$lib/components/ui/switch";
|
|
import { containersApi, type Container, type CreateContainerData, type UpdateContainerData } from "$lib/api/dashboard/reference_data/containers";
|
|
|
|
let {
|
|
open = $bindable(false),
|
|
item = $bindable<Container | null>(null),
|
|
onSuccess
|
|
}: {
|
|
open: boolean;
|
|
item?: Container | null;
|
|
onSuccess?: () => void;
|
|
} = $props();
|
|
|
|
let formData = $state({
|
|
key: "",
|
|
description: ""
|
|
});
|
|
|
|
let loading = $state(false);
|
|
let error = $state<string | null>(null);
|
|
|
|
// Actualizar formData cuando item cambia
|
|
$effect(() => {
|
|
if (item) {
|
|
formData = {
|
|
key: item.key,
|
|
description: item.description,
|
|
};
|
|
} else {
|
|
formData = {
|
|
key: "",
|
|
description: "",
|
|
};
|
|
}
|
|
});
|
|
|
|
const isEditing = $derived(!!item);
|
|
|
|
async function handleSubmit(e: Event) {
|
|
e.preventDefault();
|
|
loading = true;
|
|
error = null;
|
|
|
|
try {
|
|
let response;
|
|
if (isEditing && item) {
|
|
const payload: UpdateContainerData = {
|
|
key: formData.key,
|
|
description: formData.description
|
|
};
|
|
response = await containersApi.update(Number(item.key), payload);
|
|
} else {
|
|
const payload: CreateContainerData = {
|
|
key: formData.key,
|
|
description: formData.description
|
|
};
|
|
response = await containersApi.create(payload);
|
|
}
|
|
|
|
if (response.error) {
|
|
// Si es error de autenticación y ya se intentó refrescar, el API lo manejará
|
|
// pero mostramos un mensaje más claro
|
|
if (response.status === 401) {
|
|
error = 'Sesión expirada. Recargando página...';
|
|
setTimeout(() => {
|
|
window.location.reload();
|
|
}, 1500);
|
|
} else {
|
|
error = response.error;
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Éxito
|
|
open = false;
|
|
if (onSuccess) {
|
|
onSuccess();
|
|
}
|
|
} catch (e) {
|
|
error = e instanceof Error ? e.message : "Error al guardar";
|
|
console.error("Error saving:", e);
|
|
} finally {
|
|
loading = false;
|
|
}
|
|
}
|
|
|
|
function handleOpenChange(newOpen: boolean) {
|
|
if (!newOpen) {
|
|
// Limpiar form al cerrar
|
|
formData = {
|
|
key: "",
|
|
description: ""
|
|
};
|
|
error = null;
|
|
}
|
|
open = newOpen;
|
|
}
|
|
</script>
|
|
|
|
<Dialog.Root bind:open onOpenChange={handleOpenChange}>
|
|
<Dialog.Content class="sm:max-w-[500px]">
|
|
<Dialog.Header>
|
|
<Dialog.Title>
|
|
{isEditing ? "Editar" : "Nuevo"} Contenedor
|
|
</Dialog.Title>
|
|
<Dialog.Description>
|
|
{isEditing
|
|
? "Modifica los datos del contenedor."
|
|
: "Completa los datos para crear un nuevo contenedor."}
|
|
</Dialog.Description>
|
|
</Dialog.Header>
|
|
|
|
<form onsubmit={handleSubmit} class="space-y-4">
|
|
{#if error}
|
|
<div class="rounded-lg border border-destructive bg-destructive/10 p-3 text-sm text-destructive">
|
|
{error}
|
|
</div>
|
|
{/if}
|
|
|
|
<div class="space-y-2">
|
|
<Label for="key">Código *</Label>
|
|
<Input
|
|
id="key"
|
|
bind:value={formData.key}
|
|
placeholder="Ej: 20"
|
|
required
|
|
disabled={loading}
|
|
/>
|
|
</div>
|
|
|
|
<div class="space-y-2">
|
|
<Label for="description">Descripción *</Label>
|
|
<Input
|
|
id="description"
|
|
bind:value={formData.description}
|
|
placeholder="Ej: 20 pies"
|
|
required
|
|
disabled={loading}
|
|
/>
|
|
</div>
|
|
|
|
<Dialog.Footer>
|
|
<Button
|
|
type="button"
|
|
variant="outline"
|
|
onclick={() => (open = false)}
|
|
disabled={loading}
|
|
>
|
|
Cancelar
|
|
</Button>
|
|
<Button type="submit" disabled={loading}>
|
|
{#if loading}
|
|
<svg
|
|
class="mr-2 h-4 w-4 animate-spin"
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
fill="none"
|
|
viewBox="0 0 24 24"
|
|
>
|
|
<circle
|
|
class="opacity-25"
|
|
cx="12"
|
|
cy="12"
|
|
r="10"
|
|
stroke="currentColor"
|
|
stroke-width="4"
|
|
></circle>
|
|
<path
|
|
class="opacity-75"
|
|
fill="currentColor"
|
|
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
></path>
|
|
</svg>
|
|
{/if}
|
|
{isEditing ? "Guardar cambios" : "Crear"}
|
|
</Button>
|
|
</Dialog.Footer>
|
|
</form>
|
|
</Dialog.Content>
|
|
</Dialog.Root>
|