178 lines
6.2 KiB
Svelte
178 lines
6.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 { Textarea } from "$lib/components/ui/textarea";
|
|
// 👇 Importar tipos correctos
|
|
import {
|
|
createIdentifier,
|
|
updateIdentifier,
|
|
type Identifier
|
|
} from "$lib/api/dashboard/a76/general_catalogs/identifiers";
|
|
import { companyStore } from "$lib/stores/company.svelte";
|
|
|
|
let {
|
|
open = $bindable(false),
|
|
item = null,
|
|
onSuccess
|
|
}: {
|
|
open: boolean;
|
|
item?: Identifier | null;
|
|
onSuccess?: () => void;
|
|
} = $props();
|
|
|
|
// Calculamos si es edición basado en si hay item
|
|
const isEdit = $derived(!!item);
|
|
const title = $derived(isEdit ? "Editar Identificador" : "Nuevo Identificador");
|
|
|
|
let formData = $state({
|
|
code: '',
|
|
description: '',
|
|
level: '',
|
|
complement: ''
|
|
});
|
|
|
|
let loading = $state(false);
|
|
let error = $state<string | null>(null);
|
|
|
|
// Efecto para cargar o limpiar datos
|
|
$effect(() => {
|
|
if (open) {
|
|
if (item) {
|
|
formData = {
|
|
code: item.code,
|
|
description: item.description || '',
|
|
level: item.level || '',
|
|
complement: item.complement || ''
|
|
};
|
|
} else {
|
|
formData = {
|
|
code: '',
|
|
description: '',
|
|
level: '',
|
|
complement: ''
|
|
};
|
|
}
|
|
error = null;
|
|
}
|
|
});
|
|
|
|
async function handleSubmit() {
|
|
loading = true;
|
|
error = null;
|
|
|
|
try {
|
|
const companyId = companyStore.activeCompany?.id;
|
|
if (!companyId) throw new Error('No hay una compañía seleccionada');
|
|
|
|
// Validaciones básicas
|
|
if (!formData.code.trim()) throw new Error('La clave es requerida');
|
|
|
|
// Preparar payload (SIN company_id adentro)
|
|
const dataToSend = {
|
|
code: formData.code.trim(),
|
|
description: formData.description.trim() || null,
|
|
level: formData.level.trim() || null,
|
|
complement: formData.complement.trim() || null
|
|
};
|
|
|
|
let response;
|
|
// 👇 AQUI ESTA EL CAMBIO IMPORTANTE: companyId va por fuera
|
|
if (isEdit && item) {
|
|
response = await updateIdentifier(item.id, dataToSend, companyId);
|
|
} else {
|
|
response = await createIdentifier(dataToSend, companyId);
|
|
}
|
|
|
|
if (response.error) {
|
|
throw new Error(response.error);
|
|
}
|
|
|
|
open = false;
|
|
if (onSuccess) onSuccess();
|
|
} catch (e) {
|
|
error = e instanceof Error ? e.message : 'Error al guardar';
|
|
} finally {
|
|
loading = false;
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<Dialog.Root bind:open>
|
|
<Dialog.Content class="sm:max-w-[500px]">
|
|
<Dialog.Header>
|
|
<Dialog.Title>{title}</Dialog.Title>
|
|
</Dialog.Header>
|
|
|
|
<form onsubmit={(e) => { e.preventDefault(); handleSubmit(); }} class="space-y-4 py-4">
|
|
{#if error}
|
|
<div class="rounded-md bg-destructive/15 p-3 text-sm text-destructive">
|
|
{error}
|
|
</div>
|
|
{/if}
|
|
|
|
<div class="grid gap-4">
|
|
<div class="grid grid-cols-4 items-center gap-4">
|
|
<Label for="code" class="text-right">Clave <span class="text-destructive">*</span></Label>
|
|
<div class="col-span-3">
|
|
<Input
|
|
id="code"
|
|
bind:value={formData.code}
|
|
disabled={loading || isEdit}
|
|
placeholder="Ej: CI"
|
|
maxlength={2}
|
|
required
|
|
/>
|
|
<p class="text-[10px] text-muted-foreground mt-1">Máximo 2 caracteres.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-4 items-center gap-4">
|
|
<Label for="description" class="text-right">Descripción</Label>
|
|
<Textarea
|
|
id="description"
|
|
bind:value={formData.description}
|
|
class="col-span-3"
|
|
disabled={loading}
|
|
maxlength={1000}
|
|
/>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-4 items-center gap-4">
|
|
<Label for="level" class="text-right">Nivel</Label>
|
|
<div class="col-span-3">
|
|
<Input
|
|
id="level"
|
|
bind:value={formData.level}
|
|
disabled={loading}
|
|
placeholder="Ej: G"
|
|
maxlength={1}
|
|
/>
|
|
<p class="text-[10px] text-muted-foreground mt-1">Máximo 1 caracter (G, S, etc).</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-4 items-center gap-4">
|
|
<Label for="complement" class="text-right">Complemento</Label>
|
|
<Textarea
|
|
id="complement"
|
|
bind:value={formData.complement}
|
|
class="col-span-3"
|
|
disabled={loading}
|
|
maxlength={5000}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<Dialog.Footer>
|
|
<Button type="button" variant="outline" onclick={() => open = false} disabled={loading}>
|
|
Cancelar
|
|
</Button>
|
|
<Button type="submit" disabled={loading}>
|
|
{loading ? 'Guardando...' : isEdit ? 'Actualizar' : 'Crear'}
|
|
</Button>
|
|
</Dialog.Footer>
|
|
</form>
|
|
</Dialog.Content>
|
|
</Dialog.Root> |