Puliendo el proyecto de archivos redunantes

This commit is contained in:
2025-12-24 14:55:57 -06:00
parent 9f2971d8c4
commit b011ae32a4
11 changed files with 282 additions and 541 deletions

View File

@@ -1,7 +1,4 @@
/**
* API Client para Agentes Aduanales (Customs Brokers)
* Gestiona las operaciones CRUD para agentes aduanales
*/
import { api } from '$lib/api';
export interface CustomsBroker {

View File

@@ -3,17 +3,33 @@ import type { ApiResponse } from '$lib/api';
export interface CustomsBrokerConcept {
id: number;
broker_key: string;
concept: string;
amount?: number;
priority?: number;
code: string;
description?: string;
description_en?: string;
detailed_description?: string;
priority?: number;
first_total?: boolean;
type?: string;
is_printed?: boolean;
section?: number;
classification?: string;
tenant_id: string;
company_id?: string;
created_at: string;
updated_at?: string;
}
export interface CustomsBrokerConceptCreate {
broker_key: string;
concept?: string;
amount?: number;
code: string;
description?: string;
description_en?: string;
detailed_description?: string;
priority?: number;
first_total?: boolean;
type?: string;
is_printed?: boolean;
section?: number;
classification?: string;
}
export interface CustomsBrokerConceptUpdate extends Partial<CustomsBrokerConceptCreate> {}
@@ -26,12 +42,11 @@ export interface CustomsBrokerConceptListResponse {
pages: number;
}
export async function getCustomsBrokerConcepts(
page: number = 1,
pageSize: number = 50,
companyId: number, // <-- Nuevo
filters: Record<string, any> = {}
companyId: number,
filters: Record<string, any> = {},
): Promise<ApiResponse<CustomsBrokerConceptListResponse>> {
const params = new URLSearchParams({
page: page.toString(),
@@ -40,30 +55,21 @@ export async function getCustomsBrokerConcepts(
...filters
});
const response = await api.get(`/v1/a76/customs-broker-concepts/?${params.toString()}`);
return response.data;
return await api.get(`/v1/a76/customs-broker-concepts?${params.toString()}`);
}
export async function createCustomsBrokerConcept(
data: CustomsBrokerConceptCreate,
companyId: number
): Promise<CustomsBrokerConcept> {
const response = await api.post(`/v1/a76/customs-broker-concepts/?company_id=${companyId}`, data);
return response.data;
export async function getCustomsBrokerConcept(id: number, companyId: number): Promise<ApiResponse<CustomsBrokerConcept>> {
return await api.get(`/v1/a76/customs-broker-concepts/${id}?company_id=${companyId}`);
}
export async function updateCustomsBrokerConcept(
id: number,
data: CustomsBrokerConceptUpdate,
companyId: number
): Promise<CustomsBrokerConcept> {
const response = await api.put(`/v1/a76/customs-broker-concepts/${id}/?company_id=${companyId}`, data);
return response.data;
export async function createCustomsBrokerConcept(data: CustomsBrokerConceptCreate, companyId: number): Promise<ApiResponse<CustomsBrokerConcept>> {
return await api.post(`/v1/a76/customs-broker-concepts?company_id=${companyId}`, data);
}
export async function deleteCustomsBrokerConcept(id: number, companyId: number): Promise<void> {
await api.delete(`/v1/a76/customs-broker-concepts/${id}/?company_id=${companyId}`);
}
export async function updateCustomsBrokerConcept(id: number, data: CustomsBrokerConceptUpdate, companyId: number): Promise<ApiResponse<CustomsBrokerConcept>> {
return await api.put(`/v1/a76/customs-broker-concepts/${id}?company_id=${companyId}`, data);
}
export async function deleteCustomsBrokerConcept(id: number, companyId: number): Promise<ApiResponse<void>> {
return await api.delete(`/v1/a76/customs-broker-concepts/${id}?company_id=${companyId}`);
}

View File

@@ -1,381 +1,221 @@
<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 { customsBrokersApi, type CreateCustomsBrokerData } from "$lib/api/dashboard/a76/customs-brokers";
import { companyStore } from "$lib/stores/company.svelte";
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 { Separator } from "$lib/components/ui/separator";
import { Loader2 } from "lucide-svelte";
import type { CreateCustomsBrokerData, CustomsBroker } from "$lib/api/dashboard/a76/customs-brokers"; // Ajusta la ruta
import { toast } from "svelte-sonner";
let {
open = $bindable(false),
onSuccess
}: {
open: boolean;
onSuccess?: () => void;
} = $props();
// --- Props ---
export let open = false;
export let mode: "create" | "edit" = "create";
export let initialData: CustomsBroker | null = null;
export let companyId: string; // Necesario según tu API
let formData = $state({
broker_key: "",
name: "",
type: "",
address: "",
postal_code: "",
city: "",
state: "",
phone: "",
fax: "",
email: "",
country: "",
tax_id: "",
personal_id: "",
position: "",
license: "",
company: "",
contact: ""
});
// La función onSave ahora devuelve una promesa para manejar el loading aquí
export let onSave: (data: CreateCustomsBrokerData) => Promise<void>;
let loading = $state(false);
let error = $state<string | null>(null);
// --- Estado ---
let loading = false;
async function handleSubmit(e: Event) {
e.preventDefault();
if (!companyStore.activeCompany) {
error = "No hay compañía seleccionada";
return;
}
// Estado del formulario
let formData: CreateCustomsBrokerData = {
broker_key: "",
license: "",
name: "",
tax_id: "",
email: "",
phone: "",
fax: "",
contact: "",
address: "",
postal_code: "",
city: "",
state: "",
country: "",
tenant_id: "", // Se llenará en el submit o por defecto
company_id: ""
};
loading = true;
error = null;
// --- Reactividad ---
$: if (open) {
if (mode === "edit" && initialData) {
// Cargar datos existentes
formData = {
...initialData,
// Aseguramos que no sean null/undefined para los inputs
name: initialData.name || "",
tax_id: initialData.tax_id || "",
email: initialData.email || "",
phone: initialData.phone || "",
fax: initialData.fax || "",
contact: initialData.contact || "",
address: initialData.address || "",
postal_code: initialData.postal_code || "",
city: initialData.city || "",
state: initialData.state || "",
country: initialData.country || "",
license: initialData.license || ""
};
} else {
// Reset para crear
formData = {
broker_key: "",
license: "",
name: "",
tax_id: "",
email: "",
phone: "",
fax: "",
contact: "",
address: "",
postal_code: "",
city: "",
state: "",
country: "MEX", // Valor por defecto sugerido
tenant_id: "default", // Ajustar según lógica de tu app
company_id: companyId
};
}
}
try {
const payload: CreateCustomsBrokerData = {
broker_key: formData.broker_key,
name: formData.name || null,
type: formData.type || null,
address: formData.address || null,
postal_code: formData.postal_code || null,
city: formData.city || null,
state: formData.state || null,
phone: formData.phone || null,
fax: formData.fax || null,
email: formData.email || null,
country: formData.country || null,
tax_id: formData.tax_id || null,
personal_id: formData.personal_id || null,
position: formData.position || null,
license: formData.license || null,
company: formData.company || null,
contact: formData.contact || null,
tenant_id: "1", // TODO: Get from user context
company_id: companyStore.activeCompany.id.toString()
};
// --- Handlers ---
async function handleSubmit() {
try {
loading = true;
const response = await customsBrokersApi.create(payload);
// Validaciones básicas
if (!formData.broker_key) {
toast.error("La Clave del Agente es obligatoria");
loading = false;
return;
}
if (!formData.license) {
toast.error("La Patente es obligatoria");
loading = false;
return;
}
if (response.error) {
if (response.status === 401) {
error = 'Sesión expirada. Recargando página...';
setTimeout(() => {
window.location.reload();
}, 1500);
} else {
error = response.error;
}
return;
}
// Inyectar company_id si no viene
const payload = { ...formData, company_id: companyId };
// É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 = {
broker_key: "",
name: "",
type: "",
address: "",
postal_code: "",
city: "",
state: "",
phone: "",
fax: "",
email: "",
country: "",
tax_id: "",
personal_id: "",
position: "",
license: "",
company: "",
contact: ""
};
error = null;
}
open = newOpen;
}
await onSave(payload);
open = false;
toast.success(mode === 'create' ? "Agente creado correctamente" : "Agente actualizado correctamente");
} catch (error) {
console.error(error);
toast.error("Error al guardar el agente aduanal");
} finally {
loading = false;
}
}
</script>
<Dialog.Root bind:open onOpenChange={handleOpenChange}>
<Dialog.Content class="sm:max-w-[700px] max-h-[90vh] overflow-y-auto">
<Dialog.Header>
<Dialog.Title>Nuevo Agente Aduanal</Dialog.Title>
<Dialog.Description>
Completa los datos para crear un nuevo agente aduanal.
</Dialog.Description>
</Dialog.Header>
<Dialog.Root bind:open>
<Dialog.Content class="sm:max-w-[700px] max-h-[90vh] overflow-y-auto">
<Dialog.Header>
<Dialog.Title>
{mode === "create" ? "Nuevo Agente Aduanal" : "Editar Agente Aduanal"}
</Dialog.Title>
<Dialog.Description>
Ingresa los datos generales del agente. La configuración de VU y Personal se gestiona aparte.
</Dialog.Description>
</Dialog.Header>
<form onsubmit={handleSubmit} class="space-y-6">
{#if error}
<div class="rounded-lg border border-destructive bg-destructive/10 p-3 text-sm text-destructive">
{error}
</div>
{/if}
<div class="grid gap-6 py-4">
<div class="space-y-4">
<h4 class="text-sm font-medium leading-none text-muted-foreground">Identificación</h4>
<div class="grid grid-cols-2 gap-4">
<div class="space-y-2">
<Label for="broker_key">Clave Agente *</Label>
<Input id="broker_key" bind:value={formData.broker_key} placeholder="Ej. 550" disabled={mode === 'edit' || loading} />
</div>
<div class="space-y-2">
<Label for="license">Patente *</Label>
<Input id="license" bind:value={formData.license} placeholder="Ej. 3421" disabled={loading} />
</div>
</div>
<div class="grid grid-cols-2 gap-4">
<div class="space-y-2 col-span-2">
<Label for="name">Nombre / Razón Social</Label>
<Input id="name" bind:value={formData.name} placeholder="Nombre del Agente o Agencia" disabled={loading} />
</div>
<div class="space-y-2">
<Label for="tax_id">RFC</Label>
<Input id="tax_id" bind:value={formData.tax_id} placeholder="RFC de la agencia" disabled={loading} />
</div>
<div class="space-y-2">
<Label for="contact">Nombre Contacto</Label>
<Input id="contact" bind:value={formData.contact} placeholder="Persona de contacto" disabled={loading} />
</div>
</div>
</div>
<!-- Información básica -->
<div class="space-y-4">
<h3 class="text-sm font-semibold">Información Básica</h3>
<div class="grid grid-cols-2 gap-4">
<div class="space-y-2">
<Label for="broker_key">Clave *</Label>
<Input
id="broker_key"
bind:value={formData.broker_key}
placeholder="Ej: 12345"
maxlength={5}
required
disabled={loading}
/>
</div>
<Separator />
<div class="space-y-2">
<Label for="type">Tipo</Label>
<Input
id="type"
bind:value={formData.type}
placeholder="Tipo de agente"
maxlength={9}
disabled={loading}
/>
</div>
</div>
<div class="space-y-4">
<h4 class="text-sm font-medium leading-none text-muted-foreground">Contacto</h4>
<div class="grid grid-cols-3 gap-4">
<div class="space-y-2 col-span-1">
<Label for="phone">Teléfono</Label>
<Input id="phone" bind:value={formData.phone} disabled={loading} />
</div>
<div class="space-y-2 col-span-2">
<Label for="email">Correo Electrónico</Label>
<Input id="email" type="email" bind:value={formData.email} disabled={loading} />
</div>
</div>
</div>
<div class="space-y-2">
<Label for="name">Nombre</Label>
<Input
id="name"
bind:value={formData.name}
placeholder="Nombre del agente aduanal"
maxlength={80}
disabled={loading}
/>
</div>
<Separator />
<div class="grid grid-cols-2 gap-4">
<div class="space-y-2">
<Label for="license">Patente</Label>
<Input
id="license"
bind:value={formData.license}
placeholder="Número de patente"
maxlength={4}
disabled={loading}
/>
</div>
<div class="space-y-4">
<h4 class="text-sm font-medium leading-none text-muted-foreground">Dirección Fiscal</h4>
<div class="space-y-2">
<Label for="address">Calle y Número</Label>
<Input id="address" bind:value={formData.address} disabled={loading} />
</div>
<div class="space-y-2">
<Label for="company">Empresa</Label>
<Input
id="company"
bind:value={formData.company}
placeholder="Empresa del agente"
maxlength={200}
disabled={loading}
/>
</div>
</div>
</div>
<div class="grid grid-cols-4 gap-4">
<div class="space-y-2">
<Label for="postal_code">C.P.</Label>
<Input id="postal_code" bind:value={formData.postal_code} disabled={loading} />
</div>
<div class="space-y-2 col-span-2">
<Label for="city">Ciudad</Label>
<Input id="city" bind:value={formData.city} disabled={loading} />
</div>
<div class="space-y-2">
<Label for="state">Estado</Label>
<Input id="state" bind:value={formData.state} disabled={loading} />
</div>
</div>
<div class="grid grid-cols-4 gap-4">
<div class="space-y-2">
<Label for="country">País</Label>
<Input id="country" bind:value={formData.country} disabled={loading} />
</div>
</div>
</div>
<!-- Información de contacto -->
<div class="space-y-4">
<h3 class="text-sm font-semibold">Información de Contacto</h3>
<div class="grid grid-cols-2 gap-4">
<div class="space-y-2">
<Label for="phone">Teléfono</Label>
<Input
id="phone"
bind:value={formData.phone}
placeholder="Número telefónico"
maxlength={30}
disabled={loading}
/>
</div>
</div>
<div class="space-y-2">
<Label for="fax">Fax</Label>
<Input
id="fax"
bind:value={formData.fax}
placeholder="Número de fax"
maxlength={30}
disabled={loading}
/>
</div>
</div>
<div class="space-y-2">
<Label for="email">Email</Label>
<Input
id="email"
type="email"
bind:value={formData.email}
placeholder="correo@ejemplo.com"
maxlength={100}
disabled={loading}
/>
</div>
<div class="space-y-2">
<Label for="contact">Contacto</Label>
<Input
id="contact"
bind:value={formData.contact}
placeholder="Nombre del contacto"
maxlength={80}
disabled={loading}
/>
</div>
</div>
<!-- Dirección -->
<div class="space-y-4">
<h3 class="text-sm font-semibold">Dirección</h3>
<div class="space-y-2">
<Label for="address">Dirección</Label>
<Input
id="address"
bind:value={formData.address}
placeholder="Calle y número"
maxlength={1500}
disabled={loading}
/>
</div>
<div class="grid grid-cols-3 gap-4">
<div class="space-y-2">
<Label for="postal_code">Código Postal</Label>
<Input
id="postal_code"
bind:value={formData.postal_code}
placeholder="C.P."
maxlength={15}
disabled={loading}
/>
</div>
<div class="space-y-2">
<Label for="city">Ciudad</Label>
<Input
id="city"
bind:value={formData.city}
placeholder="Ciudad"
maxlength={30}
disabled={loading}
/>
</div>
<div class="space-y-2">
<Label for="state">Estado</Label>
<Input
id="state"
bind:value={formData.state}
placeholder="Estado"
maxlength={30}
disabled={loading}
/>
</div>
</div>
<div class="space-y-2">
<Label for="country">País</Label>
<Input
id="country"
bind:value={formData.country}
placeholder="País"
maxlength={3}
disabled={loading}
/>
</div>
</div>
<!-- Información fiscal -->
<div class="space-y-4">
<h3 class="text-sm font-semibold">Información Fiscal</h3>
<div class="grid grid-cols-2 gap-4">
<div class="space-y-2">
<Label for="tax_id">RFC</Label>
<Input
id="tax_id"
bind:value={formData.tax_id}
placeholder="RFC"
maxlength={30}
disabled={loading}
/>
</div>
<div class="space-y-2">
<Label for="personal_id">CURP</Label>
<Input
id="personal_id"
bind:value={formData.personal_id}
placeholder="CURP"
maxlength={20}
disabled={loading}
/>
</div>
</div>
<div class="space-y-2">
<Label for="position">Posición</Label>
<Input
id="position"
bind:value={formData.position}
placeholder="Cargo o posición"
maxlength={30}
disabled={loading}
/>
</div>
</div>
<Dialog.Footer>
<Button type="button" variant="outline" onclick={() => (open = false)} disabled={loading}>
Cancelar
</Button>
<Button type="submit" disabled={loading}>
{#if loading}
<div class="flex items-center gap-2">
<div class="h-4 w-4 animate-spin rounded-full border-2 border-primary-foreground border-t-transparent"></div>
Guardando...
</div>
{:else}
Crear Agente Aduanal
{/if}
</Button>
</Dialog.Footer>
</form>
</Dialog.Content>
</Dialog.Root>
<Dialog.Footer>
<Button variant="outline" on:click={() => (open = false)} disabled={loading}>
Cancelar
</Button>
<Button on:click={handleSubmit} disabled={loading}>
{#if loading}
<Loader2 class="mr-2 h-4 w-4 animate-spin" />
Guardando
{:else}
Guardar Agente
{/if}
</Button>
</Dialog.Footer>
</Dialog.Content>
</Dialog.Root>

View File

@@ -1,4 +1,4 @@
import type { CustomsBrokerConcept } from '$lib/api/dashboard/a76/general_catalogs/customs_broker_concepts';
import type { CustomsBrokerConcept } from '$lib/api/dashboard/a76/general_catalogs/customs-broker-concepts';
import type { ColumnDef } from '@tanstack/table-core';
import { renderComponent } from '$lib/components/ui/data-table';
import DataTableActions from './data-table-actions.svelte';

View File

@@ -47,8 +47,8 @@
formData = {
broker_key: '',
concept: '',
amount: '',
priority: ''
amount: null,
priority: null
};
}
});
@@ -69,8 +69,8 @@
const dataToSend = {
broker_key: formData.broker_key.trim(),
concept: formData.concept.trim(),
amount: formData.amount ? Number(formData.amount) : null,
priority: formData.priority ? Number(formData.priority) : null
amount: formData.amount ? Number(formData.amount) : undefined,
priority: formData.priority ? Number(formData.priority) : undefined
};
// 6. Corregida la sintaxis de llamada a la API

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import { Button } from "$lib/components/ui/button";
import * as DropdownMenu from "$lib/components/ui/dropdown-menu";
import { deleteCustomsBrokerConcept, type CustomsBrokerConcept } from "$lib/api/dashboard/a76/general_catalogs/customs_broker_concepts";
import { deleteCustomsBrokerConcept, type CustomsBrokerConcept } from "$lib/api/dashboard/a76/general_catalogs/customs-broker-concepts";
import { companyStore } from "$lib/stores/company.svelte";
import { EllipsisVertical, Pencil, LoaderCircle, Trash2 } from 'lucide-svelte';
import CreateEditDialog from "./create-edite-dialoge.svelte";

View File

@@ -1,137 +0,0 @@
<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";
import { Loader2 } from "lucide-svelte";
import type { Equivalency, EquivalencyCreate } from "$lib/api/dashboard/a76/general_catalogs/equivalencies";
// --- Props ---
export let open = false;
export let mode: "create" | "edit" = "create";
export let initialData: Equivalency | null = null;
// Función que el padre debe pasar para realizar la llamada a la API
export let onSave: (data: EquivalencyCreate) => Promise<void>;
// --- Estado Local ---
let loading = false;
// Estado del formulario
let formData: EquivalencyCreate = {
fraccion_mex: "",
fraccion_us: "",
description: ""
};
// --- Reactividad ---
// Cuando se abre el modal o cambia initialData, reseteamos/llenamos el form
$: if (open) {
if (mode === "edit" && initialData) {
formData = {
fraccion_mex: initialData.fraccion_mex,
fraccion_us: initialData.fraccion_us,
description: initialData.description || ""
};
} else {
// Reset para crear
formData = {
fraccion_mex: "",
fraccion_us: "",
description: ""
};
}
}
// --- Handlers ---
async function handleSubmit() {
try {
loading = true;
// Validaciones simples
if (!formData.fraccion_mex || !formData.fraccion_us) {
toast.error("Las fracciones son obligatorias");
loading = false;
return;
}
await onSave(formData);
open = false; // Cerramos el modal si todo sale bien
toast.success(mode === 'create' ? "Equivalencia creada" : "Equivalencia actualizada");
} catch (error) {
console.error(error);
toast.error("Error al guardar la equivalencia");
} finally {
loading = false;
}
}
</script>
<Dialog.Root bind:open>
<Dialog.Content class="sm:max-w-[500px]">
<Dialog.Header>
<Dialog.Title>
{mode === "create" ? "Nueva Equivalencia" : "Editar Equivalencia"}
</Dialog.Title>
<Dialog.Description>
{mode === "create"
? "Ingresa los datos para registrar una nueva equivalencia."
: "Modifica los datos de la equivalencia existente."}
</Dialog.Description>
</Dialog.Header>
<div class="grid gap-4 py-4">
<div class="grid grid-cols-4 items-center gap-4">
<Label for="fraccion_mex" class="text-right">Fracción MX</Label>
<div class="col-span-3">
<Input
id="fraccion_mex"
bind:value={formData.fraccion_mex}
placeholder="Ej. 8544.11.01"
disabled={loading}
/>
</div>
</div>
<div class="grid grid-cols-4 items-center gap-4">
<Label for="fraccion_us" class="text-right">Fracción US</Label>
<div class="col-span-3">
<Input
id="fraccion_us"
bind:value={formData.fraccion_us}
placeholder="Ej. 8544.10.00"
disabled={loading}
/>
</div>
</div>
<div class="grid grid-cols-4 items-start gap-4">
<Label for="description" class="text-right pt-2">Descripción</Label>
<div class="col-span-3">
<Textarea
id="description"
bind:value={formData.description}
placeholder="Descripción opcional de la equivalencia..."
class="resize-none"
disabled={loading}
/>
</div>
</div>
</div>
<Dialog.Footer>
<Button variant="outline" on:click={() => (open = false)} disabled={loading}>
Cancelar
</Button>
<Button on:click={handleSubmit} disabled={loading}>
{#if loading}
<Loader2 class="mr-2 h-4 w-4 animate-spin" />
Guardando...
{:else}
Guardar
{/if}
</Button>
</Dialog.Footer>
</Dialog.Content>
</Dialog.Root>

View File

@@ -0,0 +1,28 @@
<script lang="ts">
import { Checkbox as CheckboxPrimitive } from "bits-ui";
import { Check } from "lucide-svelte";
import { cn } from "$lib/utils";
let {
ref = $bindable(null),
checked = $bindable(false),
class: className,
...restProps
}: CheckboxPrimitive.RootProps = $props();
</script>
<CheckboxPrimitive.Root
bind:ref
bind:checked
class={cn(
"peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
className
)}
{...restProps}
>
<CheckboxPrimitive.Indicator
class={cn("flex items-center justify-center text-current")}
>
<Check class="h-4 w-4" />
</CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root>

View File

@@ -0,0 +1,7 @@
import Root from "./checkbox.svelte";
export {
Root,
//
Root as Checkbox,
};

View File

@@ -14,7 +14,7 @@ export const load: PageServerLoad = async ({ cookies, fetch, url, parent }) => {
companies: parentData.companies || []
};
}
/////HOLAAA
try {
// Obtener company_id de múltiples fuentes (en orden de prioridad):
// 1. URL query param (permite cambiar vía navegación)

View File

@@ -12,7 +12,7 @@
import { browser } from '$app/environment';
import { companyStore } from '$lib/stores/company.svelte';
import { Plus, Search, Trash2 } from 'lucide-svelte';
//HOLAA
// Los datos iniciales vienen del servidor
let { data }: { data: PageData } = $props();