feat: replace SVG icons with Lucide icons in reference data pages
- Updated the "Nueva Sección" button in customs_sections, customs_warehouses, incoterms, invoice_types, material_types, payment_methods, pedimento_codes, pedimento_regimens, sectors, states, transport_modes, and transport_types pages to use the Plus icon from Lucide. - Updated the "Actualizar" button in the same pages to use the RefreshCw icon from Lucide. - Added a new edit dialog component for customs brokers with a comprehensive form for editing broker details, including validation and loading states.
This commit is contained in:
@@ -31,8 +31,8 @@ export interface ClientProvider {
|
||||
domicile_fiscal?: string | null;
|
||||
foreign_tax_id?: string | null;
|
||||
client_or_provider?: string | null;
|
||||
enabled_disabled?: number;
|
||||
tenant_id: number;
|
||||
is_active?: boolean;
|
||||
tenant_id: number;
|
||||
address?: ClientProviderAddress | null;
|
||||
programs?: ClientProviderPrograms | null;
|
||||
}
|
||||
@@ -46,7 +46,7 @@ export interface ClientProviderBasic {
|
||||
domicile_fiscal?: string | null;
|
||||
foreign_tax_id?: string | null;
|
||||
client_or_provider?: string | null;
|
||||
enabled_disabled?: number;
|
||||
is_active?: boolean;
|
||||
tenant_id: number;
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ export interface CreateClientProviderData {
|
||||
domicile_fiscal?: string | null;
|
||||
foreign_tax_id?: string | null;
|
||||
client_or_provider?: string | null;
|
||||
enabled_disabled?: number;
|
||||
is_active?: boolean;
|
||||
address?: Omit<ClientProviderAddress, 'id' | 'client_id'> | null;
|
||||
programs?: Omit<ClientProviderPrograms, 'id' | 'client_id'> | null;
|
||||
}
|
||||
@@ -78,7 +78,7 @@ export interface UpdateClientProviderData {
|
||||
domicile_fiscal?: string | null;
|
||||
foreign_tax_id?: string | null;
|
||||
client_or_provider?: string | null;
|
||||
enabled_disabled?: number;
|
||||
is_active?: boolean;
|
||||
address?: Partial<ClientProviderAddress> | null;
|
||||
programs?: Partial<ClientProviderPrograms> | null;
|
||||
}
|
||||
@@ -100,7 +100,7 @@ export const clientsProvidersApi = {
|
||||
page: page.toString(),
|
||||
page_size: pageSize.toString()
|
||||
});
|
||||
|
||||
|
||||
if (filters) {
|
||||
Object.entries(filters).forEach(([key, value]) => {
|
||||
if (value !== undefined && value !== null && value !== '') {
|
||||
@@ -108,7 +108,7 @@ export const clientsProvidersApi = {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
return api.get<ClientProviderListResponse>(
|
||||
`/v1/a76/clients-providers?${params.toString()}`
|
||||
);
|
||||
@@ -166,7 +166,7 @@ export const clientsProvidersApi = {
|
||||
|
||||
/**
|
||||
* Crea un nuevo cliente/proveedor
|
||||
* @param companyId - ID de la compañía
|
||||
* @param companyId - ID de la compañía
|
||||
* @param data - Datos del cliente/proveedor a crear
|
||||
*/
|
||||
create: (companyId: number, data: CreateClientProviderData) =>
|
||||
|
||||
@@ -19,7 +19,7 @@ export interface CustomsBroker {
|
||||
tax_id?: string | null;
|
||||
personal_id?: string | null;
|
||||
position?: string | null;
|
||||
license?: string | null;
|
||||
license: string;
|
||||
company?: string | null;
|
||||
contact?: string | null;
|
||||
tenant_id: string;
|
||||
@@ -117,6 +117,14 @@ export const customsBrokersApi = {
|
||||
return api.delete<CustomsBroker>(`/v1/a76/customs-brokers/${brokerKey}?company_id=${companyId}`);
|
||||
},
|
||||
|
||||
/**
|
||||
* Actualiza la información de un agente aduanal
|
||||
*/
|
||||
update: (brokerKey: string, data: CreateCustomsBrokerData) => {
|
||||
const companyId = data.company_id;
|
||||
return api.put<CustomsBroker>(`/v1/a76/customs-brokers/${brokerKey}?company_id=${companyId}`, data);
|
||||
},
|
||||
|
||||
/**
|
||||
* Actualiza la información de VU de un agente aduanal
|
||||
*/
|
||||
|
||||
@@ -17,8 +17,6 @@ export interface PedimentoDates {
|
||||
original_date?: string | null;
|
||||
start_date?: string | null;
|
||||
end_date?: string | null;
|
||||
capture_date?: string | null;
|
||||
capture_time?: string | null;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
@@ -33,8 +31,6 @@ export interface CreatePedimentoDatesData {
|
||||
original_date?: string | null;
|
||||
start_date?: string | null;
|
||||
end_date?: string | null;
|
||||
capture_date?: string | null;
|
||||
capture_time?: string | null;
|
||||
}
|
||||
|
||||
export interface UpdatePedimentoDatesData {
|
||||
@@ -48,8 +44,6 @@ export interface UpdatePedimentoDatesData {
|
||||
original_date?: string | null;
|
||||
start_date?: string | null;
|
||||
end_date?: string | null;
|
||||
capture_date?: string | null;
|
||||
capture_time?: string | null;
|
||||
}
|
||||
|
||||
export const pedimentoDatesApi = {
|
||||
|
||||
@@ -15,9 +15,7 @@ export interface PedimentoDates {
|
||||
eucan_date?: string | null;
|
||||
original_date?: string | null;
|
||||
start_date?: string | null;
|
||||
end_date?: string | null;
|
||||
capture_date?: string | null;
|
||||
capture_time?: string | null;
|
||||
end_date?: string | null;
|
||||
}
|
||||
|
||||
export interface PedimentoPayments {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
import { materialTypesApi, type MaterialType } from "$lib/api/dashboard/refrence_data/material_types";
|
||||
import { companyStore } from "$lib/stores/company.svelte";
|
||||
import { onMount } from 'svelte';
|
||||
import { LoaderCircle, Home } from 'lucide-svelte';
|
||||
|
||||
let {
|
||||
open = $bindable(false),
|
||||
@@ -248,21 +249,7 @@
|
||||
{#if companyStore.activeCompany}
|
||||
<div class="rounded-md bg-blue-50 border border-blue-200 p-3">
|
||||
<div class="flex items-center gap-2">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="text-blue-600"
|
||||
>
|
||||
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
|
||||
<polyline points="9 22 9 12 15 12 15 22" />
|
||||
</svg>
|
||||
<Home class="h-4 w-4 text-blue-600" />
|
||||
<div>
|
||||
<p class="text-sm font-medium text-blue-900">
|
||||
{companyStore.activeCompany.name}
|
||||
@@ -426,26 +413,7 @@
|
||||
</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>
|
||||
<LoaderCircle class="mr-2 h-4 w-4 animate-spin" />
|
||||
Guardando...
|
||||
{:else}
|
||||
{isEdit ? 'Actualizar' : 'Crear'}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import * as DropdownMenu from "$lib/components/ui/dropdown-menu";
|
||||
import { classesApi, type A76Class } from "$lib/api/dashboard/a76/classes";
|
||||
import { companyStore } from "$lib/stores/company.svelte";
|
||||
import { EllipsisVertical, Pencil, LoaderCircle, Trash2 } from 'lucide-svelte';
|
||||
import CreateEditDialog from "./create-edit-dialog.svelte";
|
||||
|
||||
let {
|
||||
@@ -80,21 +81,7 @@
|
||||
{#snippet child({ props })}
|
||||
<Button {...props} variant="ghost" size="icon" class="relative size-8 p-0">
|
||||
<span class="sr-only">Abrir menú</span>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<circle cx="12" cy="12" r="1" />
|
||||
<circle cx="12" cy="5" r="1" />
|
||||
<circle cx="12" cy="19" r="1" />
|
||||
</svg>
|
||||
<EllipsisVertical size={16} />
|
||||
</Button>
|
||||
{/snippet}
|
||||
</DropdownMenu.Trigger>
|
||||
@@ -102,63 +89,15 @@
|
||||
<DropdownMenu.Label>Acciones</DropdownMenu.Label>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.Item onclick={handleEdit}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z" />
|
||||
<path d="m15 5 4 4" />
|
||||
</svg>
|
||||
<Pencil size={16} class="mr-2" />
|
||||
Editar
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.Item onclick={handleDelete} class="text-destructive" 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>
|
||||
<LoaderCircle class="mr-2 h-4 w-4 animate-spin" />
|
||||
{:else}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M3 6h18" />
|
||||
<path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" />
|
||||
<path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" />
|
||||
</svg>
|
||||
<Trash2 size={16} class="mr-2" />
|
||||
{/if}
|
||||
Eliminar
|
||||
</DropdownMenu.Item>
|
||||
|
||||
@@ -56,10 +56,10 @@ export function createColumns(onSuccess?: () => void): ColumnDef<ClientProvider>
|
||||
const typeSnippet = createRawSnippet<[{ type: string | null | undefined }]>((getType) => {
|
||||
const { type } = getType();
|
||||
const displayType = type === 'client' ? 'Cliente' : type === 'provider' ? 'Proveedor' : type === 'both' ? 'Ambos' : 'N/A';
|
||||
const colorClass = type === 'client' ? 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300'
|
||||
const colorClass = type === 'client' ? 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300'
|
||||
: type === 'provider' ? 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300'
|
||||
: type === 'both' ? 'bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-300'
|
||||
: 'bg-gray-100 text-gray-800 dark:bg-gray-900 dark:text-gray-300';
|
||||
: type === 'both' ? 'bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-300'
|
||||
: 'bg-gray-100 text-gray-800 dark:bg-gray-900 dark:text-gray-300';
|
||||
return {
|
||||
render: () => `<span class="inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium ${colorClass}">${displayType}</span>`
|
||||
};
|
||||
@@ -81,21 +81,21 @@ export function createColumns(onSuccess?: () => void): ColumnDef<ClientProvider>
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: "enabled_disabled",
|
||||
accessorKey: "is_active",
|
||||
header: "Estado",
|
||||
cell: ({ row }) => {
|
||||
const statusSnippet = createRawSnippet<[{ status: number | undefined }]>((getStatus) => {
|
||||
const { status } = getStatus();
|
||||
const isEnabled = status === 1;
|
||||
const statusText = isEnabled ? 'Activo' : 'Inactivo';
|
||||
const colorClass = isEnabled
|
||||
? 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300'
|
||||
const colorClass = isEnabled
|
||||
? 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300'
|
||||
: 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300';
|
||||
return {
|
||||
render: () => `<span class="inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium ${colorClass}">${statusText}</span>`
|
||||
};
|
||||
});
|
||||
return renderSnippet(statusSnippet, { status: row.original.enabled_disabled });
|
||||
return renderSnippet(statusSnippet, { status: row.original.is_active });
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import { Label } from "$lib/components/ui/label";
|
||||
import { clientsProvidersApi, type ClientProvider, type CreateClientProviderData, type UpdateClientProviderData } from "$lib/api/dashboard/a76/clients-providers";
|
||||
import { companyStore } from "$lib/stores/company.svelte";
|
||||
import { LoaderCircle } from 'lucide-svelte';
|
||||
|
||||
let {
|
||||
open = $bindable(false),
|
||||
@@ -24,7 +25,7 @@
|
||||
domicile_fiscal: "",
|
||||
foreign_tax_id: "",
|
||||
client_or_provider: "client",
|
||||
enabled_disabled: 1,
|
||||
is_active: true,
|
||||
// Address fields
|
||||
street: "",
|
||||
neighborhood: "",
|
||||
@@ -51,7 +52,7 @@
|
||||
domicile_fiscal: item.domicile_fiscal || "",
|
||||
foreign_tax_id: item.foreign_tax_id || "",
|
||||
client_or_provider: item.client_or_provider || "client",
|
||||
enabled_disabled: item.enabled_disabled ?? 1,
|
||||
is_active: item.is_active ?? true,
|
||||
street: item.address?.street || "",
|
||||
neighborhood: item.address?.neighborhood || "",
|
||||
city: item.address?.city || "",
|
||||
@@ -70,7 +71,7 @@
|
||||
domicile_fiscal: "",
|
||||
foreign_tax_id: "",
|
||||
client_or_provider: "client",
|
||||
enabled_disabled: 1,
|
||||
is_active: true,
|
||||
street: "",
|
||||
neighborhood: "",
|
||||
city: "",
|
||||
@@ -107,7 +108,7 @@
|
||||
domicile_fiscal: formData.domicile_fiscal || null,
|
||||
foreign_tax_id: formData.foreign_tax_id || null,
|
||||
client_or_provider: formData.client_or_provider as "client" | "provider" | "both" | null,
|
||||
enabled_disabled: formData.enabled_disabled,
|
||||
is_active: formData.is_active,
|
||||
address: {
|
||||
street: formData.street || null,
|
||||
neighborhood: formData.neighborhood || null,
|
||||
@@ -132,7 +133,7 @@
|
||||
domicile_fiscal: formData.domicile_fiscal || null,
|
||||
foreign_tax_id: formData.foreign_tax_id || null,
|
||||
client_or_provider: formData.client_or_provider as "client" | "provider" | "both" | null,
|
||||
enabled_disabled: formData.enabled_disabled,
|
||||
is_active: formData.is_active,
|
||||
address: {
|
||||
street: formData.street || null,
|
||||
neighborhood: formData.neighborhood || null,
|
||||
@@ -185,7 +186,7 @@
|
||||
domicile_fiscal: "",
|
||||
foreign_tax_id: "",
|
||||
client_or_provider: "client",
|
||||
enabled_disabled: 1,
|
||||
is_active: true,
|
||||
street: "",
|
||||
neighborhood: "",
|
||||
city: "",
|
||||
@@ -432,26 +433,7 @@
|
||||
</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>
|
||||
<LoaderCircle class="mr-2 h-4 w-4 animate-spin" />
|
||||
{/if}
|
||||
{isEditing ? "Guardar cambios" : "Crear"}
|
||||
</Button>
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
<DropdownMenu.Item onclick={handleViewDetails}>Ver detalles</DropdownMenu.Item>
|
||||
<DropdownMenu.Item onclick={handleEdit}>Editar</DropdownMenu.Item>
|
||||
<DropdownMenu.Item onclick={handleToggleStatus} disabled={isToggling}>
|
||||
{isToggling ? 'Cambiando...' : item.enabled_disabled === 1 ? 'Desactivar' : 'Activar'}
|
||||
{isToggling ? 'Cambiando...' : item.is_active === true ? 'Desactivar' : 'Activar'}
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.Item class="text-destructive" onclick={handleDelete}>Eliminar</DropdownMenu.Item>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import * as AlertDialog from "$lib/components/ui/alert-dialog";
|
||||
import { clientsProvidersApi, type ClientProvider } from "$lib/api/dashboard/a76/clients-providers";
|
||||
import { companyStore } from "$lib/stores/company.svelte";
|
||||
import { LoaderCircle } from 'lucide-svelte';
|
||||
|
||||
let {
|
||||
open = $bindable(false),
|
||||
@@ -97,26 +98,7 @@
|
||||
class="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
||||
>
|
||||
{#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>
|
||||
<LoaderCircle class="mr-2 h-4 w-4 animate-spin" />
|
||||
{/if}
|
||||
Eliminar
|
||||
</AlertDialog.Action>
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
|
||||
<div class="flex flex-col gap-1">
|
||||
<span class="text-xs font-medium text-muted-foreground">Estado</span>
|
||||
{#if item.enabled_disabled === 1}
|
||||
{#if item.is_active === true}
|
||||
<span class="inline-flex w-fit items-center rounded-full bg-green-100 px-2.5 py-0.5 text-xs font-medium text-green-800 dark:bg-green-900 dark:text-green-300">
|
||||
Activo
|
||||
</span>
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import type { CustomsBroker } from "./columns.js";
|
||||
import DetailsDialog from "./details-dialog.svelte";
|
||||
import DeleteDialog from "./delete-dialog.svelte";
|
||||
import EditDialog from "./edit-dialog.svelte";
|
||||
|
||||
let {
|
||||
broker,
|
||||
@@ -16,6 +17,7 @@
|
||||
|
||||
let showDetailsDialog = $state(false);
|
||||
let showDeleteDialog = $state(false);
|
||||
let showEditDialog = $state(false);
|
||||
|
||||
function handleCopyKey() {
|
||||
navigator.clipboard.writeText(broker.broker_key);
|
||||
@@ -31,6 +33,10 @@
|
||||
showDetailsDialog = true;
|
||||
}
|
||||
|
||||
function handleEdit() {
|
||||
showEditDialog = true;
|
||||
}
|
||||
|
||||
function handleDelete() {
|
||||
showDeleteDialog = true;
|
||||
}
|
||||
@@ -64,6 +70,9 @@
|
||||
<DropdownMenu.Item onclick={handleViewDetails}>
|
||||
Ver detalles
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item onclick={handleEdit}>
|
||||
Editar
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item onclick={handleDelete} class="text-destructive">
|
||||
Eliminar
|
||||
</DropdownMenu.Item>
|
||||
@@ -72,4 +81,5 @@
|
||||
</DropdownMenu.Root>
|
||||
|
||||
<DetailsDialog bind:open={showDetailsDialog} {broker} />
|
||||
<EditDialog bind:open={showEditDialog} {broker} {onSuccess} />
|
||||
<DeleteDialog bind:open={showDeleteDialog} {broker} {onSuccess} />
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import * as AlertDialog from "$lib/components/ui/alert-dialog";
|
||||
import { customsBrokersApi, type CustomsBroker } from "$lib/api/dashboard/a76/customs-brokers";
|
||||
import { LoaderCircle } from 'lucide-svelte';
|
||||
|
||||
let {
|
||||
open = $bindable(false),
|
||||
@@ -92,26 +93,7 @@
|
||||
class="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
||||
>
|
||||
{#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>
|
||||
<LoaderCircle class="mr-2 h-4 w-4 animate-spin" />
|
||||
Eliminando...
|
||||
{:else}
|
||||
Eliminar
|
||||
|
||||
@@ -0,0 +1,384 @@
|
||||
<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, type CustomsBroker } from "$lib/api/dashboard/a76/customs-brokers";
|
||||
import { companyStore } from "$lib/stores/company.svelte";
|
||||
|
||||
let {
|
||||
open = $bindable(false),
|
||||
broker,
|
||||
onSuccess
|
||||
}: {
|
||||
open: boolean;
|
||||
broker: CustomsBroker;
|
||||
onSuccess?: () => void;
|
||||
} = $props();
|
||||
|
||||
let formData = $state({
|
||||
name: "",
|
||||
type: "",
|
||||
address: "",
|
||||
postal_code: "",
|
||||
city: "",
|
||||
state: "",
|
||||
phone: "",
|
||||
fax: "",
|
||||
email: "",
|
||||
country: "",
|
||||
tax_id: "",
|
||||
personal_id: "",
|
||||
position: "",
|
||||
license: "",
|
||||
company: "",
|
||||
contact: ""
|
||||
});
|
||||
|
||||
let loading = $state(false);
|
||||
let error = $state<string | null>(null);
|
||||
|
||||
// Inicializar formulario cuando cambia el broker
|
||||
$effect(() => {
|
||||
if (open && broker) {
|
||||
formData = {
|
||||
name: broker.name || "",
|
||||
type: broker.type || "",
|
||||
address: broker.address || "",
|
||||
postal_code: broker.postal_code || "",
|
||||
city: broker.city || "",
|
||||
state: broker.state || "",
|
||||
phone: broker.phone || "",
|
||||
fax: broker.fax || "",
|
||||
email: broker.email || "",
|
||||
country: broker.country || "",
|
||||
tax_id: broker.tax_id || "",
|
||||
personal_id: broker.personal_id || "",
|
||||
position: broker.position || "",
|
||||
license: broker.license || "",
|
||||
company: broker.company || "",
|
||||
contact: broker.contact || ""
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
async function handleSubmit(e: Event) {
|
||||
e.preventDefault();
|
||||
|
||||
if (!companyStore.activeCompany) {
|
||||
error = "No hay compañía seleccionada";
|
||||
return;
|
||||
}
|
||||
|
||||
loading = true;
|
||||
error = null;
|
||||
|
||||
try {
|
||||
const payload: CreateCustomsBrokerData = {
|
||||
broker_key: broker.broker_key, // La clave no se edita
|
||||
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: broker.tenant_id,
|
||||
company_id: companyStore.activeCompany.id.toString()
|
||||
};
|
||||
|
||||
const response = await customsBrokersApi.update(broker.broker_key, payload);
|
||||
|
||||
if (response.error) {
|
||||
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 updating:", e);
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
function handleOpenChange(newOpen: boolean) {
|
||||
open = newOpen;
|
||||
if (!newOpen) {
|
||||
error = null;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<Dialog.Root bind:open onOpenChange={handleOpenChange}>
|
||||
<Dialog.Content class="sm:max-w-[700px] max-h-[90vh] overflow-y-auto">
|
||||
<Dialog.Header>
|
||||
<Dialog.Title>Editar Agente Aduanal</Dialog.Title>
|
||||
<Dialog.Description>
|
||||
Modifica los datos del agente aduanal <span class="font-mono font-semibold">{broker?.broker_key}</span>.
|
||||
</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}
|
||||
|
||||
<!-- 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="edit-broker_key">Clave</Label>
|
||||
<Input
|
||||
id="edit-broker_key"
|
||||
value={broker?.broker_key}
|
||||
disabled
|
||||
class="bg-muted"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<Label for="edit-type">Tipo</Label>
|
||||
<Input
|
||||
id="edit-type"
|
||||
bind:value={formData.type}
|
||||
placeholder="Tipo de agente"
|
||||
maxlength={9}
|
||||
disabled={loading}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<Label for="edit-name">Nombre</Label>
|
||||
<Input
|
||||
id="edit-name"
|
||||
bind:value={formData.name}
|
||||
placeholder="Nombre del agente aduanal"
|
||||
maxlength={80}
|
||||
disabled={loading}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div class="space-y-2">
|
||||
<Label for="edit-license">Patente</Label>
|
||||
<Input
|
||||
id="edit-license"
|
||||
bind:value={formData.license}
|
||||
placeholder="Número de patente"
|
||||
maxlength={4}
|
||||
disabled={loading}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<Label for="edit-company">Empresa</Label>
|
||||
<Input
|
||||
id="edit-company"
|
||||
bind:value={formData.company}
|
||||
placeholder="Empresa del agente"
|
||||
maxlength={200}
|
||||
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="edit-phone">Teléfono</Label>
|
||||
<Input
|
||||
id="edit-phone"
|
||||
bind:value={formData.phone}
|
||||
placeholder="Número telefónico"
|
||||
maxlength={30}
|
||||
disabled={loading}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<Label for="edit-fax">Fax</Label>
|
||||
<Input
|
||||
id="edit-fax"
|
||||
bind:value={formData.fax}
|
||||
placeholder="Número de fax"
|
||||
maxlength={30}
|
||||
disabled={loading}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<Label for="edit-email">Email</Label>
|
||||
<Input
|
||||
id="edit-email"
|
||||
type="email"
|
||||
bind:value={formData.email}
|
||||
placeholder="correo@ejemplo.com"
|
||||
maxlength={100}
|
||||
disabled={loading}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<Label for="edit-contact">Contacto</Label>
|
||||
<Input
|
||||
id="edit-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="edit-address">Dirección</Label>
|
||||
<Input
|
||||
id="edit-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="edit-postal_code">Código Postal</Label>
|
||||
<Input
|
||||
id="edit-postal_code"
|
||||
bind:value={formData.postal_code}
|
||||
placeholder="C.P."
|
||||
maxlength={15}
|
||||
disabled={loading}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<Label for="edit-city">Ciudad</Label>
|
||||
<Input
|
||||
id="edit-city"
|
||||
bind:value={formData.city}
|
||||
placeholder="Ciudad"
|
||||
maxlength={30}
|
||||
disabled={loading}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<Label for="edit-state">Estado</Label>
|
||||
<Input
|
||||
id="edit-state"
|
||||
bind:value={formData.state}
|
||||
placeholder="Estado"
|
||||
maxlength={30}
|
||||
disabled={loading}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<Label for="edit-country">País</Label>
|
||||
<Input
|
||||
id="edit-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="edit-tax_id">RFC</Label>
|
||||
<Input
|
||||
id="edit-tax_id"
|
||||
bind:value={formData.tax_id}
|
||||
placeholder="RFC"
|
||||
maxlength={30}
|
||||
disabled={loading}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<Label for="edit-personal_id">CURP</Label>
|
||||
<Input
|
||||
id="edit-personal_id"
|
||||
bind:value={formData.personal_id}
|
||||
placeholder="CURP"
|
||||
maxlength={20}
|
||||
disabled={loading}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<Label for="edit-position">Posición</Label>
|
||||
<Input
|
||||
id="edit-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}
|
||||
Guardar Cambios
|
||||
{/if}
|
||||
</Button>
|
||||
</Dialog.Footer>
|
||||
</form>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
@@ -2,6 +2,7 @@
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import * as DropdownMenu from "$lib/components/ui/dropdown-menu";
|
||||
import { pedimentosApi, type Pedimento } from "$lib/api/dashboard/a76/pedimentos";
|
||||
import { EllipsisVertical, Pencil, LoaderCircle, Trash2 } from 'lucide-svelte';
|
||||
|
||||
let {
|
||||
item,
|
||||
@@ -62,21 +63,7 @@
|
||||
{#snippet child({ props })}
|
||||
<Button {...props} variant="ghost" size="icon" class="relative size-8 p-0">
|
||||
<span class="sr-only">Abrir menú</span>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<circle cx="12" cy="12" r="1" />
|
||||
<circle cx="12" cy="5" r="1" />
|
||||
<circle cx="12" cy="19" r="1" />
|
||||
</svg>
|
||||
<EllipsisVertical class="h-4 w-4" />
|
||||
</Button>
|
||||
{/snippet}
|
||||
</DropdownMenu.Trigger>
|
||||
@@ -84,63 +71,15 @@
|
||||
<DropdownMenu.Label>Acciones</DropdownMenu.Label>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.Item onclick={handleEdit}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z" />
|
||||
<path d="m15 5 4 4" />
|
||||
</svg>
|
||||
<Pencil class="mr-2 h-4 w-4" />
|
||||
Editar
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.Item onclick={handleDelete} class="text-destructive" 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>
|
||||
<LoaderCircle class="mr-2 h-4 w-4 animate-spin" />
|
||||
{:else}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M3 6h18" />
|
||||
<path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" />
|
||||
<path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" />
|
||||
</svg>
|
||||
<Trash2 class="mr-2 h-4 w-4" />
|
||||
{/if}
|
||||
Eliminar
|
||||
</DropdownMenu.Item>
|
||||
|
||||
@@ -30,8 +30,6 @@
|
||||
original_date: datesData.original_date ? datesData.original_date.substring(0, 10) : '',
|
||||
start_date: datesData.start_date ? datesData.start_date.substring(0, 10) : '',
|
||||
end_date: datesData.end_date ? datesData.end_date.substring(0, 10) : '',
|
||||
capture_date: datesData.capture_date ? datesData.capture_date.substring(0, 10) : '',
|
||||
capture_time: datesData.capture_time || ''
|
||||
};
|
||||
}
|
||||
} else {
|
||||
@@ -48,7 +46,6 @@
|
||||
original_date: '',
|
||||
start_date: '',
|
||||
end_date: '',
|
||||
capture_date: '',
|
||||
capture_time: ''
|
||||
};
|
||||
}
|
||||
@@ -163,27 +160,7 @@
|
||||
type="date"
|
||||
bind:value={formData.end_date}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Fecha de Captura -->
|
||||
<div class="space-y-2">
|
||||
<Label for="capture_date">Fecha de Captura</Label>
|
||||
<Input
|
||||
id="capture_date"
|
||||
type="date"
|
||||
bind:value={formData.capture_date}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Hora de Captura -->
|
||||
<div class="space-y-2">
|
||||
<Label for="capture_time">Hora de Captura</Label>
|
||||
<Input
|
||||
id="capture_time"
|
||||
type="time"
|
||||
bind:value={formData.capture_time}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card.Content>
|
||||
|
||||
@@ -5,26 +5,175 @@
|
||||
import * as Select from '$lib/components/ui/select';
|
||||
import type { Pedimento } from '$lib/api/dashboard/a76/pedimentos';
|
||||
import type { PedimentoCode } from '$lib/api/dashboard/refrence_data/pedimento_codes';
|
||||
import type { CustomsSection } from '$lib/api/dashboard/refrence_data/customs_sections';
|
||||
import type { CustomsBroker } from '$lib/api/dashboard/a76/customs-brokers';
|
||||
import type { ClientProvider } from '$lib/api/dashboard/a76/clients-providers';
|
||||
import type { CodePedimentoRegimen } from '$lib/api/dashboard/refrence_data/code_pedimento_regimens';
|
||||
|
||||
let {
|
||||
pedimento,
|
||||
formData = $bindable(),
|
||||
pedimentoCodes = []
|
||||
pedimentoCodes = [],
|
||||
customsSections = [],
|
||||
customsBrokers = [],
|
||||
clients = [],
|
||||
codePedimentoRegimens = []
|
||||
}: {
|
||||
pedimento: Pedimento | null;
|
||||
formData?: any;
|
||||
pedimentoCodes?: PedimentoCode[];
|
||||
customsSections?: CustomsSection[];
|
||||
customsBrokers?: CustomsBroker[];
|
||||
clients?: ClientProvider[];
|
||||
codePedimentoRegimens?: CodePedimentoRegimen[];
|
||||
} = $props();
|
||||
|
||||
// Debug: verificar que los datos llegan
|
||||
$effect(() => {
|
||||
console.log('pedimentoCodes:', pedimentoCodes.length, 'items');
|
||||
// Extraer regímenes únicos de codePedimentoRegimens
|
||||
const uniqueRegimens = $derived(
|
||||
Array.from(new Set(codePedimentoRegimens.map(r => r.regimen_code).filter((code): code is string => code !== null)))
|
||||
.sort()
|
||||
.map(code => ({ code, label: code }))
|
||||
);
|
||||
|
||||
// Funciones de mapeo entre type_code (E/I) y operation_type (1/2)
|
||||
function typeCodeToOperationType(typeCode: string | null | undefined): number | null {
|
||||
if (!typeCode) return null;
|
||||
// E = Exportación = 1, I = Importación = 2
|
||||
if (typeCode.toUpperCase() === 'E') return 1;
|
||||
if (typeCode.toUpperCase() === 'I') return 2;
|
||||
return null;
|
||||
}
|
||||
|
||||
function operationTypeToTypeCode(operationType: number | null | undefined): string | null {
|
||||
if (operationType === null || operationType === undefined) return null;
|
||||
// 1 = Exportación = E, 2 = Importación = I
|
||||
if (operationType === 1) return 'E';
|
||||
if (operationType === 2) return 'I';
|
||||
return null;
|
||||
}
|
||||
|
||||
// Opciones filtradas para Régimen y Tipo de Operación basadas en las selecciones actuales
|
||||
// NOTA: La Clave NO se filtra, siempre muestra todas las opciones
|
||||
|
||||
const filteredRegimens = $derived(() => {
|
||||
// Si hay clave o tipo de operación seleccionado, filtrar
|
||||
if (formData.pedimento_code || formData.operation_type !== null) {
|
||||
const matches = codePedimentoRegimens.filter(r => {
|
||||
const matchesCode = !formData.pedimento_code || r.pedimento_code === formData.pedimento_code;
|
||||
const matchesType = formData.operation_type === null || r.type_code === operationTypeToTypeCode(formData.operation_type);
|
||||
return matchesCode && matchesType;
|
||||
});
|
||||
const validRegimens = new Set(matches.map(m => m.regimen_code).filter((code): code is string => code !== null));
|
||||
return Array.from(validRegimens).sort().map(code => ({ code, label: code }));
|
||||
}
|
||||
return uniqueRegimens;
|
||||
});
|
||||
|
||||
const filteredOperationTypes = $derived(() => {
|
||||
// Si hay clave o régimen seleccionado, filtrar
|
||||
if (formData.pedimento_code || formData.regime) {
|
||||
const matches = codePedimentoRegimens.filter(r => {
|
||||
const matchesCode = !formData.pedimento_code || r.pedimento_code === formData.pedimento_code;
|
||||
const matchesRegime = !formData.regime || r.regimen_code === formData.regime;
|
||||
return matchesCode && matchesRegime;
|
||||
});
|
||||
const validTypes = new Set(matches.map(m => typeCodeToOperationType(m.type_code)).filter(t => t !== null));
|
||||
return operationOptions.filter(opt => validTypes.has(opt.value));
|
||||
}
|
||||
return operationOptions;
|
||||
});
|
||||
|
||||
// Reactive synchronization between Clave, Régimen, and Tipo de Operación
|
||||
// REGLA: La Clave es el campo principal y NUNCA se modifica automáticamente
|
||||
// Solo se auto-llenan Régimen y Tipo de Operación basándose en la Clave
|
||||
|
||||
// Cuando cambia la Clave del Pedimento
|
||||
$effect(() => {
|
||||
const currentCode = formData.pedimento_code;
|
||||
if (!currentCode) return;
|
||||
|
||||
const matches = codePedimentoRegimens.filter(r => r.pedimento_code === currentCode);
|
||||
|
||||
if (matches.length === 0) return;
|
||||
|
||||
// Verificar si los valores actuales de régimen y tipo son válidos para esta clave
|
||||
const currentIsValid = matches.some(m => {
|
||||
const matchesRegime = !formData.regime || m.regimen_code === formData.regime;
|
||||
const matchesType = formData.operation_type === null || m.type_code === operationTypeToTypeCode(formData.operation_type);
|
||||
return matchesRegime && matchesType;
|
||||
});
|
||||
|
||||
// Si los valores actuales son válidos, NO auto-llenar
|
||||
if (currentIsValid && (formData.regime || formData.operation_type !== null)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Si solo hay un match y no hay valores válidos, auto-llenar
|
||||
if (matches.length === 1) {
|
||||
const match = matches[0];
|
||||
if (match.regimen_code && formData.regime !== match.regimen_code) {
|
||||
formData.regime = match.regimen_code;
|
||||
}
|
||||
const expectedOpType = typeCodeToOperationType(match.type_code);
|
||||
if (expectedOpType !== null && formData.operation_type !== expectedOpType) {
|
||||
formData.operation_type = expectedOpType;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Cuando cambia el Régimen
|
||||
$effect(() => {
|
||||
const currentRegime = formData.regime;
|
||||
if (!currentRegime) return;
|
||||
|
||||
const matches = codePedimentoRegimens.filter(r => r.regimen_code === currentRegime);
|
||||
|
||||
if (matches.length === 0) return;
|
||||
|
||||
// Si hay clave seleccionada, solo validar (NO auto-llenar tipo de operación)
|
||||
if (formData.pedimento_code) {
|
||||
const exactMatch = matches.find(m => m.pedimento_code === formData.pedimento_code);
|
||||
}
|
||||
// Si hay tipo de operación pero no clave, no hacer nada
|
||||
// (el usuario debe seleccionar la clave primero)
|
||||
});
|
||||
|
||||
// Cuando cambia el Tipo de Operación
|
||||
$effect(() => {
|
||||
const currentType = formData.operation_type;
|
||||
if (currentType === null || currentType === undefined) return;
|
||||
|
||||
const expectedTypeCode = operationTypeToTypeCode(currentType);
|
||||
const matches = codePedimentoRegimens.filter(r => r.type_code === expectedTypeCode);
|
||||
|
||||
if (matches.length === 0) return;
|
||||
|
||||
// Si hay clave seleccionada, actualizar régimen (forzar si no hay match exacto)
|
||||
if (formData.pedimento_code) {
|
||||
const exactMatch = matches.find(m => m.pedimento_code === formData.pedimento_code);
|
||||
if (exactMatch?.regimen_code && formData.regime !== exactMatch.regimen_code) {
|
||||
formData.regime = exactMatch.regimen_code;
|
||||
} else if (!exactMatch) {
|
||||
// No hay match exacto - buscar cualquier match con la clave actual
|
||||
const allMatchesForClave = codePedimentoRegimens.filter(r => r.pedimento_code === formData.pedimento_code);
|
||||
if (allMatchesForClave.length > 0) {
|
||||
// Forzar el régimen al primer match disponible para esta clave
|
||||
const firstMatch = allMatchesForClave[0];
|
||||
if (firstMatch.regimen_code) formData.regime = firstMatch.regimen_code;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Si hay régimen pero no clave, no hacer nada
|
||||
// (el usuario debe seleccionar la clave primero)
|
||||
});
|
||||
|
||||
// Obtener el año actual (últimos 2 dígitos)
|
||||
const currentYear = String(new Date().getFullYear()).slice(-2);
|
||||
|
||||
// Inicializar formData con los valores del pedimento (o vacío si es null)
|
||||
if (!formData) {
|
||||
formData = {
|
||||
year: pedimento?.year || '',
|
||||
year: pedimento?.year || currentYear,
|
||||
customs_office: pedimento?.customs_office || '',
|
||||
license: pedimento?.license || '',
|
||||
pedimento_number: pedimento?.pedimento_number || '',
|
||||
@@ -41,6 +190,13 @@
|
||||
};
|
||||
}
|
||||
|
||||
// Asegurar que el año siempre esté actualizado con el año actual
|
||||
$effect(() => {
|
||||
if (formData && !pedimento?.year) {
|
||||
formData.year = currentYear;
|
||||
}
|
||||
});
|
||||
|
||||
const operationOptions = [
|
||||
{ value: 1, label: 'Exportación' },
|
||||
{ value: 2, label: 'Importación' },
|
||||
@@ -85,6 +241,8 @@
|
||||
placeholder="23"
|
||||
maxlength={2}
|
||||
class="text-center"
|
||||
disabled
|
||||
readonly
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -92,15 +250,28 @@
|
||||
<div class="pb-2 text-2xl font-semibold text-muted-foreground">-</div>
|
||||
|
||||
<!-- Aduana -->
|
||||
<div class="space-y-2 w-16">
|
||||
<div class="space-y-2 w-20">
|
||||
<Label for="customs_office">Aduana</Label>
|
||||
<Input
|
||||
id="customs_office"
|
||||
bind:value={formData.customs_office}
|
||||
placeholder="01"
|
||||
maxlength={2}
|
||||
class="text-center"
|
||||
/>
|
||||
<Select.Root
|
||||
type="single"
|
||||
value={formData.customs_office || ''}
|
||||
onValueChange={(v: string) => formData.customs_office = v ?? ''}
|
||||
>
|
||||
<Select.Trigger class="w-full">
|
||||
<span class="truncate">
|
||||
{formData.customs_office || 'Sel...'}
|
||||
</span>
|
||||
</Select.Trigger>
|
||||
<Select.Content class="max-w-[300px] max-h-[300px]">
|
||||
{#each customsSections as section}
|
||||
<Select.Item value={section.customs_code}>
|
||||
<span class="truncate overflow-hidden text-ellipsis whitespace-nowrap" title={`${section.customs_code} - ${section.section_name}`}>
|
||||
{section.customs_code} - {section.section_name}
|
||||
</span>
|
||||
</Select.Item>
|
||||
{/each}
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
</div>
|
||||
|
||||
<!-- Separador -->
|
||||
@@ -109,13 +280,26 @@
|
||||
<!-- Patente -->
|
||||
<div class="space-y-2 w-24">
|
||||
<Label for="license">Patente</Label>
|
||||
<Input
|
||||
id="license"
|
||||
bind:value={formData.license}
|
||||
placeholder="1234"
|
||||
maxlength={4}
|
||||
class="text-center"
|
||||
/>
|
||||
<Select.Root
|
||||
type="single"
|
||||
value={formData.license || ''}
|
||||
onValueChange={(v: string) => formData.license = v ?? ''}
|
||||
>
|
||||
<Select.Trigger class="w-full">
|
||||
<span class="truncate">
|
||||
{formData.license || 'Sel...'}
|
||||
</span>
|
||||
</Select.Trigger>
|
||||
<Select.Content class="max-w-[300px] max-h-[300px]">
|
||||
{#each customsBrokers as broker}
|
||||
<Select.Item value={broker.license}>
|
||||
<span class="truncate overflow-hidden text-ellipsis whitespace-nowrap" title={`${broker.broker_key} - ${broker.name || ''}`}>
|
||||
{broker.broker_key} - {broker.name || ''}
|
||||
</span>
|
||||
</Select.Item>
|
||||
{/each}
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
</div>
|
||||
|
||||
<!-- Separador -->
|
||||
@@ -137,29 +321,24 @@
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<!-- ID del Cliente -->
|
||||
<div class="space-y-2">
|
||||
<Label for="client_id">ID del Cliente</Label>
|
||||
<Input
|
||||
id="client_id"
|
||||
type="number"
|
||||
bind:value={formData.client_id}
|
||||
placeholder="Ej: 123"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Tipo de Operación -->
|
||||
<div class="space-y-2">
|
||||
<Label for="operation_type">Tipo de Operación</Label>
|
||||
<Label for="client_id">Cliente</Label>
|
||||
<Select.Root
|
||||
type="single"
|
||||
value={String(formData.operation_type ?? '')}
|
||||
onValueChange={(v: string) => formData.operation_type = v ? Number(v) : null}
|
||||
value={String(formData.client_id ?? '')}
|
||||
onValueChange={(v: string) => formData.client_id = v ? Number(v) : null}
|
||||
>
|
||||
<Select.Trigger class="w-full">
|
||||
{operationOptions.find(o => o.value === formData.operation_type)?.label || 'Seleccionar...'}
|
||||
<span class="truncate">
|
||||
{clients.find(c => c.id === formData.client_id)?.name || 'Seleccionar cliente...'}
|
||||
</span>
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
{#each operationOptions as option}
|
||||
<Select.Item value={String(option.value)} label={option.label} />
|
||||
<Select.Content class="max-h-[300px]">
|
||||
{#each clients as client}
|
||||
<Select.Item value={String(client.id)} label={client.name}>
|
||||
<span class="truncate overflow-hidden text-ellipsis whitespace-nowrap" title={client.name}>
|
||||
{client.name}
|
||||
</span>
|
||||
</Select.Item>
|
||||
{/each}
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
@@ -176,40 +355,81 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Clave del Pedimento -->
|
||||
<div class="space-y-2">
|
||||
<Label for="pedimento_code">Clave del Pedimento</Label>
|
||||
<Select.Root
|
||||
type="single"
|
||||
value={formData.pedimento_code || ''}
|
||||
onValueChange={(v: string) => formData.pedimento_code = v ?? ''}
|
||||
>
|
||||
<Select.Trigger class="w-full">
|
||||
<span class="truncate">
|
||||
{pedimentoCodes.find(o => o.code === formData.pedimento_code)?.code || 'Seleccionar...'}
|
||||
</span>
|
||||
</Select.Trigger>
|
||||
<Select.Content class="max-w-[600px]">
|
||||
{#each pedimentoCodes as code}
|
||||
<Select.Item value={code.code}>
|
||||
<span class="truncate overflow-hidden text-ellipsis whitespace-nowrap" title={`${code.code} - ${code.description}`}>
|
||||
{code.code} - {code.description}
|
||||
</span>
|
||||
</Select.Item>
|
||||
{/each}
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Régimen -->
|
||||
<div class="space-y-2">
|
||||
<Label for="regime">Régimen</Label>
|
||||
<Input
|
||||
id="regime"
|
||||
bind:value={formData.regime}
|
||||
placeholder="Ej: IMD"
|
||||
/>
|
||||
</div>
|
||||
<!-- Fila: Clave (2), Régimen (3), Tipo de Operación (11) -->
|
||||
<div class="flex items-end gap-2">
|
||||
<!-- Clave del Pedimento -->
|
||||
<div class="space-y-2 w-20">
|
||||
<Label for="pedimento_code">Clave</Label>
|
||||
<Select.Root
|
||||
type="single"
|
||||
value={formData.pedimento_code || ''}
|
||||
onValueChange={(v: string) => formData.pedimento_code = v ?? ''}
|
||||
>
|
||||
<Select.Trigger class="w-full">
|
||||
<span class="truncate">
|
||||
{pedimentoCodes.find(o => o.code === formData.pedimento_code)?.code || 'Sel...'}
|
||||
</span>
|
||||
</Select.Trigger>
|
||||
<Select.Content class="max-w-[200px]">
|
||||
{#each pedimentoCodes as code}
|
||||
<Select.Item value={code.code}>
|
||||
<span class="truncate overflow-hidden text-ellipsis whitespace-nowrap" title={`${code.code} - ${code.description}`}>
|
||||
{code.code} - {code.description}
|
||||
</span>
|
||||
</Select.Item>
|
||||
{/each}
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
</div>
|
||||
|
||||
<!-- Régimen -->
|
||||
<div class="space-y-2 w-24">
|
||||
<Label for="regime">Régimen</Label>
|
||||
<Select.Root
|
||||
type="single"
|
||||
value={formData.regime || ''}
|
||||
onValueChange={(v: string) => formData.regime = v ?? ''}
|
||||
>
|
||||
<Select.Trigger class="w-full">
|
||||
<span class="truncate">
|
||||
{formData.regime || 'Sel...'}
|
||||
</span>
|
||||
</Select.Trigger>
|
||||
<Select.Content class="max-w-[200px]">
|
||||
{#each filteredRegimens() as regimen}
|
||||
<Select.Item value={regimen.code}>
|
||||
<span class="truncate overflow-hidden text-ellipsis whitespace-nowrap" title={regimen.code}>
|
||||
{regimen.code}
|
||||
</span>
|
||||
</Select.Item>
|
||||
{/each}
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
</div>
|
||||
|
||||
<!-- Tipo de Operación -->
|
||||
<div class="space-y-2 flex-1">
|
||||
<Label for="operation_type">Tipo de Operación</Label>
|
||||
<Select.Root
|
||||
type="single"
|
||||
value={String(formData.operation_type ?? '')}
|
||||
onValueChange={(v: string) => formData.operation_type = v ? Number(v) : null}
|
||||
>
|
||||
<Select.Trigger class="w-full">
|
||||
{operationOptions.find(o => o.value === formData.operation_type)?.label || 'Seleccionar...'}
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
{#each filteredOperationTypes() as option}
|
||||
<Select.Item value={String(option.value)} label={option.label} />
|
||||
{/each}
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
|
||||
<!-- Estado -->
|
||||
<div class="space-y-2">
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import * as AlertDialog from "$lib/components/ui/alert-dialog";
|
||||
import { codePedimentoRegimensApi, type CodePedimentoRegimen } from "$lib/api/dashboard/refrence_data/code_pedimento_regimens";
|
||||
import { LoaderCircle } from 'lucide-svelte';
|
||||
|
||||
let {
|
||||
open = $bindable(false),
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import * as AlertDialog from "$lib/components/ui/alert-dialog";
|
||||
import { containersApi, type Container } from "$lib/api/dashboard/refrence_data/containers";
|
||||
import { LoaderCircle } from 'lucide-svelte';
|
||||
|
||||
let {
|
||||
open = $bindable(false),
|
||||
@@ -84,26 +85,7 @@
|
||||
class="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
||||
>
|
||||
{#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>
|
||||
<LoaderCircle class="mr-2 h-4 w-4 animate-spin" />
|
||||
{/if}
|
||||
Eliminar
|
||||
</AlertDialog.Action>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import * as AlertDialog from "$lib/components/ui/alert-dialog";
|
||||
import { customsSectionsApi, type CustomsSection } from "$lib/api/dashboard/refrence_data/customs_sections";
|
||||
import { LoaderCircle } from 'lucide-svelte';
|
||||
|
||||
let {
|
||||
open = $bindable(false),
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import * as AlertDialog from "$lib/components/ui/alert-dialog";
|
||||
import { customsWarehousesApi, type CustomsWarehouse } from "$lib/api/dashboard/refrence_data/customs_warehouses";
|
||||
import { LoaderCircle } from 'lucide-svelte';
|
||||
|
||||
let {
|
||||
open = $bindable(false),
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import * as AlertDialog from "$lib/components/ui/alert-dialog";
|
||||
import { materialTypesApi, type MaterialType } from "$lib/api/dashboard/refrence_data/material_types";
|
||||
import { LoaderCircle } from 'lucide-svelte';
|
||||
|
||||
let {
|
||||
open = $bindable(false),
|
||||
@@ -88,26 +89,7 @@
|
||||
class="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
||||
>
|
||||
{#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>
|
||||
<LoaderCircle class="mr-2 h-4 w-4 animate-spin" />
|
||||
{/if}
|
||||
Eliminar
|
||||
</AlertDialog.Action>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import * as AlertDialog from "$lib/components/ui/alert-dialog";
|
||||
import { paymentMethodsApi, type PaymentMethod } from "$lib/api/dashboard/refrence_data/payment_methods";
|
||||
import { LoaderCircle } from 'lucide-svelte';
|
||||
|
||||
let {
|
||||
open = $bindable(false),
|
||||
@@ -84,26 +85,7 @@
|
||||
class="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
||||
>
|
||||
{#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>
|
||||
<LoaderCircle class="mr-2 h-4 w-4 animate-spin" />
|
||||
{/if}
|
||||
Eliminar
|
||||
</AlertDialog.Action>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import * as AlertDialog from "$lib/components/ui/alert-dialog";
|
||||
import { pedimentoRegimensApi, type PedimentoRegimen } from "$lib/api/dashboard/refrence_data/pedimento_regimens";
|
||||
import { LoaderCircle } from 'lucide-svelte';
|
||||
|
||||
let {
|
||||
open = $bindable(false),
|
||||
@@ -84,26 +85,7 @@
|
||||
class="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
||||
>
|
||||
{#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>
|
||||
<LoaderCircle class="mr-2 h-4 w-4 animate-spin" />
|
||||
{/if}
|
||||
Eliminar
|
||||
</AlertDialog.Action>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import { Input } from "$lib/components/ui/input";
|
||||
import { Label } from "$lib/components/ui/label";
|
||||
import { statesApi, type State, type CreateStateData, type UpdateStateData } from "$lib/api/dashboard/refrence_data/states";
|
||||
import { LoaderCircle } from 'lucide-svelte';
|
||||
|
||||
let {
|
||||
open = $bindable(false),
|
||||
@@ -195,26 +196,7 @@
|
||||
</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>
|
||||
<LoaderCircle class="mr-2 h-4 w-4 animate-spin" />
|
||||
{/if}
|
||||
{isEditing ? "Guardar cambios" : "Crear"}
|
||||
</Button>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import * as AlertDialog from "$lib/components/ui/alert-dialog";
|
||||
import { statesApi, type State } from "$lib/api/dashboard/refrence_data/states";
|
||||
import { LoaderCircle } from 'lucide-svelte';
|
||||
|
||||
let {
|
||||
open = $bindable(false),
|
||||
@@ -96,26 +97,7 @@
|
||||
class="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
||||
>
|
||||
{#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>
|
||||
<LoaderCircle class="mr-2 h-4 w-4 animate-spin" />
|
||||
{/if}
|
||||
Eliminar
|
||||
</AlertDialog.Action>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import * as AlertDialog from "$lib/components/ui/alert-dialog";
|
||||
import { transportModesApi, type TransportMode } from "$lib/api/dashboard/refrence_data/transport_modes";
|
||||
import { LoaderCircle } from 'lucide-svelte';
|
||||
|
||||
let {
|
||||
open = $bindable(false),
|
||||
@@ -84,26 +85,7 @@
|
||||
class="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
||||
>
|
||||
{#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>
|
||||
<LoaderCircle class="mr-2 h-4 w-4 animate-spin" />
|
||||
{/if}
|
||||
Eliminar
|
||||
</AlertDialog.Action>
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
import { Input } from "$lib/components/ui/input/index.js";
|
||||
import { Button } from "$lib/components/ui/button/index.js";
|
||||
import { cn } from "$lib/utils.js";
|
||||
import { FileText, ShieldCheck } from 'lucide-svelte';
|
||||
import type { HTMLAttributes } from "svelte/elements";
|
||||
import { page } from '$app/state';
|
||||
import { enhance } from '$app/forms';
|
||||
@@ -203,14 +204,10 @@
|
||||
<div class="relative w-full h-full flex flex-col items-center justify-center gap-8">
|
||||
<!-- Ícono principal - Escudo con documento -->
|
||||
<div class="relative">
|
||||
<svg class="w-48 h-48 text-blue-600 dark:text-blue-400 opacity-90" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
||||
</svg>
|
||||
<FileText class="w-48 h-48 text-blue-600 dark:text-blue-400 opacity-90" strokeWidth={1.5} />
|
||||
<!-- Escudo de protección superpuesto -->
|
||||
<div class="absolute -bottom-2 -right-2 bg-white dark:bg-slate-800 rounded-full p-2 shadow-lg">
|
||||
<svg class="w-12 h-12 text-green-600 dark:text-green-400" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" d="M2.166 4.999A11.954 11.954 0 0010 1.944 11.954 11.954 0 0017.834 5c.11.65.166 1.32.166 2.001 0 5.225-3.34 9.67-8 11.317C5.34 16.67 2 12.225 2 7c0-.682.057-1.35.166-2.001zm11.541 3.708a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
<ShieldCheck class="w-12 h-12 text-green-600 dark:text-green-400" fill="currentColor" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import * as Card from "$lib/components/ui/card";
|
||||
import { FileText, LayoutGrid, Package } from 'lucide-svelte';
|
||||
</script>
|
||||
|
||||
<div class="space-y-6">
|
||||
@@ -52,78 +53,27 @@
|
||||
</Card.Header>
|
||||
<Card.Content>
|
||||
<div class="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
|
||||
<a
|
||||
href="/dashboard/reference_data/code_pedimento_regimens"
|
||||
class="flex flex-col items-center justify-center rounded-lg border p-6 hover:bg-accent transition-colors"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mb-2"
|
||||
>
|
||||
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
|
||||
<polyline points="14 2 14 8 20 8" />
|
||||
<line x1="16" x2="8" y1="13" y2="13" />
|
||||
<line x1="16" x2="8" y1="17" y2="17" />
|
||||
<polyline points="10 9 9 9 8 9" />
|
||||
</svg>
|
||||
<span class="font-medium">Código Pedimento - Regímenes</span>
|
||||
<span class="text-xs text-muted-foreground">Gestionar relaciones</span>
|
||||
</a>
|
||||
|
||||
<div
|
||||
class="flex flex-col items-center justify-center rounded-lg border p-6 opacity-50 cursor-not-allowed"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mb-2"
|
||||
>
|
||||
<rect width="18" height="18" x="3" y="3" rx="2" ry="2" />
|
||||
<line x1="3" x2="21" y1="9" y2="9" />
|
||||
<line x1="9" x2="9" y1="21" y2="9" />
|
||||
</svg>
|
||||
<span class="font-medium">Catálogo de Tipos</span>
|
||||
<span class="text-xs text-muted-foreground">Próximamente</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex flex-col items-center justify-center rounded-lg border p-6 opacity-50 cursor-not-allowed"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mb-2"
|
||||
>
|
||||
<path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z" />
|
||||
<polyline points="3.27 6.96 12 12.01 20.73 6.96" />
|
||||
<line x1="12" x2="12" y1="22.08" y2="12" />
|
||||
</svg>
|
||||
<span class="font-medium">Reportes</span>
|
||||
<span class="text-xs text-muted-foreground">Próximamente</span>
|
||||
</div>
|
||||
<a
|
||||
href="/dashboard/reference_data/code_pedimento_regimens"
|
||||
class="flex flex-col items-center justify-center rounded-lg border p-6 hover:bg-accent transition-colors"
|
||||
>
|
||||
<FileText class="mb-2" size={24} />
|
||||
<span class="font-medium">Código Pedimento - Regímenes</span>
|
||||
<span class="text-xs text-muted-foreground">Gestionar relaciones</span>
|
||||
</a> <div
|
||||
class="flex flex-col items-center justify-center rounded-lg border p-6 opacity-50 cursor-not-allowed"
|
||||
>
|
||||
<LayoutGrid class="mb-2" size={24} />
|
||||
<span class="font-medium">Catálogo de Tipos</span>
|
||||
<span class="text-xs text-muted-foreground">Próximamente</span>
|
||||
</div> <div
|
||||
class="flex flex-col items-center justify-center rounded-lg border p-6 opacity-50 cursor-not-allowed"
|
||||
>
|
||||
<Package class="mb-2" size={24} />
|
||||
<span class="font-medium">Reportes</span>
|
||||
<span class="text-xs text-muted-foreground">Próximamente</span>
|
||||
</div>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
</div>
|
||||
</div>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
</div>
|
||||
@@ -4,9 +4,9 @@ import { getAuthTokens, authenticatedFetch } from '$lib/server/api';
|
||||
export const load: PageServerLoad = async ({ cookies, fetch, url, parent }) => {
|
||||
// Esperar a que el layout padre valide/refresque el token
|
||||
const parentData = await parent();
|
||||
|
||||
|
||||
const { accessToken } = getAuthTokens(cookies);
|
||||
|
||||
|
||||
if (!accessToken) {
|
||||
return {
|
||||
error: 'No authenticated',
|
||||
@@ -22,20 +22,20 @@ export const load: PageServerLoad = async ({ cookies, fetch, url, parent }) => {
|
||||
// Obtener parámetros de paginación de la URL
|
||||
const page = parseInt(url.searchParams.get('page') || '1');
|
||||
const pageSize = parseInt(url.searchParams.get('page_size') || '50');
|
||||
|
||||
|
||||
// Obtener company_id de múltiples fuentes (en orden de prioridad):
|
||||
// 1. URL query param (permite cambiar vía navegación)
|
||||
// 2. Cookie active_company_id (setted por el team-switcher)
|
||||
// 3. Primera compañía del usuario (fallback)
|
||||
const companyIdParam = url.searchParams.get('company_id');
|
||||
const cookieCompanyId = cookies.get('active_company_id');
|
||||
|
||||
const companyId = companyIdParam
|
||||
|
||||
const companyId = companyIdParam
|
||||
? parseInt(companyIdParam)
|
||||
: cookieCompanyId
|
||||
? parseInt(cookieCompanyId)
|
||||
: parentData.companies?.[0]?.id;
|
||||
|
||||
|
||||
if (!companyId) {
|
||||
return {
|
||||
error: 'No company selected',
|
||||
@@ -47,9 +47,17 @@ export const load: PageServerLoad = async ({ cookies, fetch, url, parent }) => {
|
||||
};
|
||||
}
|
||||
|
||||
// Construir URL con parámetros
|
||||
let apiUrl = `v1/a76/clients-providers?company_id=${companyId}&page=${page}&page_size=${pageSize}`;
|
||||
|
||||
const type = url.searchParams.get('type');
|
||||
if (type && type !== 'both') {
|
||||
apiUrl += `&type=${type}`;
|
||||
}
|
||||
|
||||
// Usar authenticatedFetch para manejar automáticamente el refresh de tokens
|
||||
const response = await authenticatedFetch(
|
||||
`v1/a76/clients-providers?company_id=${companyId}&page=${page}&page_size=${pageSize}`,
|
||||
apiUrl,
|
||||
{},
|
||||
cookies,
|
||||
fetch
|
||||
@@ -62,7 +70,7 @@ export const load: PageServerLoad = async ({ cookies, fetch, url, parent }) => {
|
||||
statusText: response.statusText,
|
||||
error: errorText
|
||||
});
|
||||
|
||||
|
||||
return {
|
||||
error: `Error ${response.status}: ${response.statusText}`,
|
||||
items: [],
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
import CreateEditDialog from '$lib/components/dashboard/clients_and_providers/create-edit-dialog.svelte';
|
||||
import * as Card from '$lib/components/ui/card';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import * as Select from '$lib/components/ui/select';
|
||||
import { Plus, RefreshCw } from 'lucide-svelte';
|
||||
import { page } from '$app/stores';
|
||||
import { goto } from '$app/navigation';
|
||||
import type { PageData } from './$types';
|
||||
import { browser } from '$app/environment';
|
||||
import { companyStore } from '$lib/stores/company.svelte';
|
||||
@@ -16,6 +20,22 @@
|
||||
// Estado para el diálogo de crear
|
||||
let showCreateDialog = $state(false);
|
||||
|
||||
// Estado para el filtro de tipo
|
||||
let selectedType = $state<string>($page.url.searchParams.get('type') || 'both');
|
||||
|
||||
// Actualizar URL cuando cambia el filtro
|
||||
function handleTypeChange(value: string) {
|
||||
selectedType = value;
|
||||
const url = new URL(window.location.href);
|
||||
if (value === 'both') {
|
||||
url.searchParams.delete('type');
|
||||
} else {
|
||||
url.searchParams.set('type', value);
|
||||
}
|
||||
goto(url.toString(), { keepFocus: true, noScroll: true, replaceState: true });
|
||||
reloadData();
|
||||
}
|
||||
|
||||
// Sincronizar token de cookies a localStorage al montar el componente
|
||||
onMount(() => {
|
||||
if (browser) {
|
||||
@@ -77,7 +97,8 @@
|
||||
const response = await clientsProvidersApi.list(
|
||||
companyStore.activeCompany.id,
|
||||
currentPage + 1,
|
||||
pageSize
|
||||
pageSize,
|
||||
selectedType !== 'both' ? { type: selectedType } : undefined
|
||||
);
|
||||
|
||||
if (response.error) {
|
||||
@@ -121,7 +142,8 @@
|
||||
const response = await clientsProvidersApi.list(
|
||||
companyStore.activeCompany.id,
|
||||
1,
|
||||
pageSize
|
||||
pageSize,
|
||||
selectedType !== 'both' ? { type: selectedType } : undefined
|
||||
);
|
||||
|
||||
if (response.error) {
|
||||
@@ -174,21 +196,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<Button onclick={handleCreateClick}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M5 12h14" />
|
||||
<path d="M12 5v14" />
|
||||
</svg>
|
||||
<Plus class="mr-2" size={16} />
|
||||
Nuevo Cliente/Proveedor
|
||||
</Button>
|
||||
</div>
|
||||
@@ -216,25 +224,23 @@
|
||||
{/if}
|
||||
</Card.Description>
|
||||
</div>
|
||||
<Button variant="outline" onclick={reloadData}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" />
|
||||
<path d="M21 3v5h-5" />
|
||||
</svg>
|
||||
<div class="flex items-center gap-2">
|
||||
<Select.Root type="single" value={selectedType} onValueChange={handleTypeChange}>
|
||||
<Select.Trigger class="w-[180px]">
|
||||
{selectedType === 'both' ? 'Todos' : selectedType === 'client' ? 'Clientes' : 'Proveedores'}
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
<Select.Item value="both">Todos</Select.Item>
|
||||
<Select.Item value="client">Clientes</Select.Item>
|
||||
<Select.Item value="provider">Proveedores</Select.Item>
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
<Button variant="outline" onclick={reloadData}>
|
||||
<RefreshCw class="mr-2" size={16} />
|
||||
Actualizar
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Card.Header>
|
||||
<Card.Content>
|
||||
<!-- TanStack DataTable con Infinite Scroll -->
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
import type { PageData } from './$types';
|
||||
import { browser } from '$app/environment';
|
||||
import { companyStore } from '$lib/stores/company.svelte';
|
||||
import { Plus, Search, Trash2 } from 'lucide-svelte';
|
||||
|
||||
// Los datos iniciales vienen del servidor
|
||||
let { data }: { data: PageData } = $props();
|
||||
@@ -175,21 +176,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<Button onclick={handleCreateClick}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M5 12h14" />
|
||||
<path d="M12 5v14" />
|
||||
</svg>
|
||||
<Plus class="mr-2" size={16} />
|
||||
Nuevo Agente Aduanal
|
||||
</Button>
|
||||
</div>
|
||||
@@ -226,44 +213,15 @@
|
||||
Buscando...
|
||||
</div>
|
||||
{:else}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<circle cx="11" cy="11" r="8" />
|
||||
<path d="m21 21-4.3-4.3" />
|
||||
</svg>
|
||||
<Search class="mr-2" size={16} />
|
||||
Buscar
|
||||
{/if}
|
||||
</Button>
|
||||
{#if searchedBroker}
|
||||
<Button type="button" variant="outline" onclick={reloadData}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M3 6h18" />
|
||||
<path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" />
|
||||
<path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" />
|
||||
</svg>
|
||||
Limpiar
|
||||
</Button>
|
||||
{#if searchedBroker}
|
||||
<Button type="button" variant="outline" onclick={reloadData}>
|
||||
<Trash2 class="mr-2" size={16} />
|
||||
Limpiar
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { Input } from '$lib/components/ui/input';
|
||||
import { Label } from '$lib/components/ui/label';
|
||||
import { Plus, Filter, Trash2, RefreshCw } from 'lucide-svelte';
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
// Estado para la lista de classes
|
||||
@@ -255,21 +256,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<Button onclick={handleCreateClick}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M5 12h14" />
|
||||
<path d="M12 5v14" />
|
||||
</svg>
|
||||
<Plus class="mr-2" size={16} />
|
||||
Nueva Clase
|
||||
</Button>
|
||||
</div>
|
||||
@@ -305,38 +292,11 @@
|
||||
|
||||
<div class="flex items-end gap-2 md:col-span-2">
|
||||
<Button type="submit" disabled={loading} class="flex-1">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3" />
|
||||
</svg>
|
||||
<Filter class="mr-2" size={16} />
|
||||
Filtrar
|
||||
</Button>
|
||||
<Button type="button" variant="outline" onclick={clearFilters} disabled={loading}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="M3 6h18" />
|
||||
<path d="m19 6-2 14a2 2 0 0 1-2 2H9a2 2 0 0 1-2-2L5 6" />
|
||||
<path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" />
|
||||
</svg>
|
||||
<Trash2 size={16} />
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -364,21 +324,7 @@
|
||||
</Card.Description>
|
||||
</div>
|
||||
<Button variant="outline" onclick={reloadData}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" />
|
||||
<path d="M21 3v5h-5" />
|
||||
</svg>
|
||||
<RefreshCw class="mr-2" size={16} />
|
||||
Actualizar
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
import type { PageData } from './$types';
|
||||
import { browser } from '$app/environment';
|
||||
import { companyStore } from '$lib/stores/company.svelte';
|
||||
import { Plus, Filter, Trash2, RefreshCw } from 'lucide-svelte';
|
||||
|
||||
// Los datos iniciales vienen del servidor
|
||||
let { data }: { data: PageData } = $props();
|
||||
@@ -260,21 +261,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<Button onclick={handleCreateClick}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M5 12h14" />
|
||||
<path d="M12 5v14" />
|
||||
</svg>
|
||||
<Plus class="mr-2" size={16} />
|
||||
Nuevo Pedimento
|
||||
</Button>
|
||||
</div>
|
||||
@@ -322,38 +309,11 @@
|
||||
|
||||
<div class="flex items-end gap-2">
|
||||
<Button type="submit" disabled={loading} class="flex-1">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3" />
|
||||
</svg>
|
||||
<Filter class="mr-2" size={16} />
|
||||
Filtrar
|
||||
</Button>
|
||||
<Button type="button" variant="outline" onclick={clearFilters} disabled={loading}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="M3 6h18" />
|
||||
<path d="m19 6-2 14a2 2 0 0 1-2 2H9a2 2 0 0 1-2-2L5 6" />
|
||||
<path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" />
|
||||
</svg>
|
||||
<Trash2 size={16} />
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -381,21 +341,7 @@
|
||||
</Card.Description>
|
||||
</div>
|
||||
<Button variant="outline" onclick={reloadData}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" />
|
||||
<path d="M21 3v5h-5" />
|
||||
</svg>
|
||||
<RefreshCw class="mr-2" size={16} />
|
||||
Actualizar
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -9,6 +9,13 @@ export const load: PageServerLoad = async ({ params, cookies, fetch }) => {
|
||||
throw redirect(302, '/login');
|
||||
}
|
||||
|
||||
// Obtener el company_id de la cookie para ambas ramas (new y edit)
|
||||
const companyId = await getActiveCompanyId(cookies, fetch);
|
||||
|
||||
if (!companyId) {
|
||||
throw error(400, 'No se encontró una compañía seleccionada');
|
||||
}
|
||||
|
||||
// Cargar pedimento_codes (datos de referencia)
|
||||
const pedimentoCodesPromise = authenticatedFetch(
|
||||
'v1/public/refrence_data/pedimento-codes?page=1&page_size=100',
|
||||
@@ -17,16 +24,63 @@ export const load: PageServerLoad = async ({ params, cookies, fetch }) => {
|
||||
fetch
|
||||
);
|
||||
|
||||
// Cargar customs_sections (datos de referencia)
|
||||
const customsSectionsPromise = authenticatedFetch(
|
||||
'v1/public/refrence_data/customs-sections?page=1&page_size=100',
|
||||
{},
|
||||
cookies,
|
||||
fetch
|
||||
);
|
||||
|
||||
// Cargar customs_brokers (datos de referencia)
|
||||
const customsBrokersPromise = authenticatedFetch(
|
||||
`v1/a76/customs-brokers?company_id=${companyId}`,
|
||||
{},
|
||||
cookies,
|
||||
fetch
|
||||
);
|
||||
|
||||
// Cargar clientes (para el select de client_id)
|
||||
const clientsPromise = authenticatedFetch(
|
||||
`v1/a76/clients-providers?company_id=${companyId}&type=client&page=1&page_size=1000`,
|
||||
{},
|
||||
cookies,
|
||||
fetch
|
||||
);
|
||||
|
||||
// Cargar code-pedimento-regimens (para interdependencia de campos)
|
||||
const codePedimentoRegimensPromise = authenticatedFetch(
|
||||
'v1/public/refrence_data/code-pedimento-regimens?page=1&page_size=100',
|
||||
{},
|
||||
cookies,
|
||||
fetch
|
||||
);
|
||||
|
||||
// Si el ID es "new", es una creación
|
||||
if (params.id === 'new') {
|
||||
const pedimentoCodesResponse = await pedimentoCodesPromise;
|
||||
const [pedimentoCodesResponse, customsSectionsResponse, customsBrokersResponse, clientsResponse, codePedimentoRegimensResponse] = await Promise.all([
|
||||
pedimentoCodesPromise,
|
||||
customsSectionsPromise,
|
||||
customsBrokersPromise,
|
||||
clientsPromise,
|
||||
codePedimentoRegimensPromise
|
||||
]);
|
||||
|
||||
const pedimentoCodes = pedimentoCodesResponse.ok ? await pedimentoCodesResponse.json() : { items: [] };
|
||||
|
||||
const customsSections = customsSectionsResponse.ok ? await customsSectionsResponse.json() : { items: [] };
|
||||
const customsBrokers = customsBrokersResponse.ok ? await customsBrokersResponse.json() : { items: [] };
|
||||
const clients = clientsResponse.ok ? await clientsResponse.json() : { items: [] };
|
||||
const codePedimentoRegimens = codePedimentoRegimensResponse.ok ? await codePedimentoRegimensResponse.json() : { items: [] };
|
||||
|
||||
return {
|
||||
pedimento: null,
|
||||
pedimentoId: null,
|
||||
isCreate: true,
|
||||
pedimentoCodes: pedimentoCodes.items || []
|
||||
pedimentoCodes: pedimentoCodes.items || [],
|
||||
customsSections: customsSections.items || [],
|
||||
customsBrokers: customsBrokers.items || [],
|
||||
clients: clients.items || [],
|
||||
codePedimentoRegimens: codePedimentoRegimens.items || []
|
||||
};
|
||||
}
|
||||
|
||||
@@ -36,12 +90,7 @@ export const load: PageServerLoad = async ({ params, cookies, fetch }) => {
|
||||
}
|
||||
|
||||
try {
|
||||
// Obtener el company_id de la cookie
|
||||
const companyId = await getActiveCompanyId(cookies, fetch);
|
||||
|
||||
if (!companyId) {
|
||||
throw error(400, 'No se encontró una compañía seleccionada');
|
||||
}
|
||||
|
||||
|
||||
// Cargar el pedimento desde el backend usando authenticatedFetch
|
||||
const response = await authenticatedFetch(
|
||||
@@ -63,15 +112,30 @@ export const load: PageServerLoad = async ({ params, cookies, fetch }) => {
|
||||
|
||||
const pedimento = await response.json();
|
||||
|
||||
// Cargar pedimento_codes
|
||||
const pedimentoCodesResponse = await pedimentoCodesPromise;
|
||||
// Cargar pedimento_codes y customs_sections
|
||||
const [pedimentoCodesResponse, customsSectionsResponse, customsBrokersResponse, clientsResponse, codePedimentoRegimensResponse] = await Promise.all([
|
||||
pedimentoCodesPromise,
|
||||
customsSectionsPromise,
|
||||
customsBrokersPromise,
|
||||
clientsPromise,
|
||||
codePedimentoRegimensPromise
|
||||
]);
|
||||
|
||||
const pedimentoCodes = pedimentoCodesResponse.ok ? await pedimentoCodesResponse.json() : { items: [] };
|
||||
const customsSections = customsSectionsResponse.ok ? await customsSectionsResponse.json() : { items: [] };
|
||||
const customsBrokers = customsBrokersResponse.ok ? await customsBrokersResponse.json() : { items: [] };
|
||||
const clients = clientsResponse.ok ? await clientsResponse.json() : { items: [] };
|
||||
const codePedimentoRegimens = codePedimentoRegimensResponse.ok ? await codePedimentoRegimensResponse.json() : { items: [] };
|
||||
|
||||
return {
|
||||
pedimento,
|
||||
pedimentoId,
|
||||
isCreate: false,
|
||||
pedimentoCodes: pedimentoCodes.items || []
|
||||
pedimentoCodes: pedimentoCodes.items || [],
|
||||
customsSections: customsSections.items || [],
|
||||
customsBrokers: customsBrokers.items || [],
|
||||
clients: clients.items || [],
|
||||
codePedimentoRegimens: codePedimentoRegimens.items || []
|
||||
};
|
||||
} catch (e) {
|
||||
console.error('Error loading pedimento:', e);
|
||||
|
||||
@@ -7,6 +7,18 @@
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { Badge } from '$lib/components/ui/badge';
|
||||
import { Separator } from '$lib/components/ui/separator';
|
||||
import {
|
||||
ArrowLeft,
|
||||
CircleAlert,
|
||||
CircleCheck,
|
||||
FileText,
|
||||
Calendar,
|
||||
CreditCard,
|
||||
Truck,
|
||||
ShieldCheck,
|
||||
LoaderCircle,
|
||||
Save
|
||||
} from 'lucide-svelte';
|
||||
import type { PageData } from './$types';
|
||||
|
||||
// Importar los componentes de cada pestaña (ahora sin botones de guardar propios)
|
||||
@@ -19,12 +31,20 @@
|
||||
// Importar solo la API de pedimentos
|
||||
import { pedimentosApi, type CreatePedimentoData, type UpdatePedimentoData } from '$lib/api/dashboard/a76/pedimentos';
|
||||
import type { PedimentoCode } from '$lib/api/dashboard/refrence_data/pedimento_codes';
|
||||
import type { CustomsSection } from '$lib/api/dashboard/refrence_data/customs_sections';
|
||||
import type { CustomsBroker } from '$lib/api/dashboard/a76/customs-brokers';
|
||||
import type { ClientProvider } from '$lib/api/dashboard/a76/clients-providers';
|
||||
import type { CodePedimentoRegimen } from '$lib/api/dashboard/refrence_data/code_pedimento_regimens';
|
||||
|
||||
interface ExtendedPageData {
|
||||
pedimentoId?: number | null;
|
||||
pedimento?: any;
|
||||
isCreate?: boolean;
|
||||
pedimentoCodes?: PedimentoCode[];
|
||||
customsSections?: CustomsSection[];
|
||||
customsBrokers?: CustomsBroker[];
|
||||
clients?: ClientProvider[];
|
||||
codePedimentoRegimens?: CodePedimentoRegimen[];
|
||||
user?: any;
|
||||
companies?: any[];
|
||||
authenticated?: boolean;
|
||||
@@ -133,8 +153,7 @@
|
||||
datesFormData.payment_date || datesFormData.rectification_payment_date ||
|
||||
datesFormData.extraction_date || datesFormData.submission_date ||
|
||||
datesFormData.eucan_date || datesFormData.original_date ||
|
||||
datesFormData.start_date || datesFormData.end_date ||
|
||||
datesFormData.capture_date || datesFormData.capture_time;
|
||||
datesFormData.start_date || datesFormData.end_date;
|
||||
|
||||
if (hasDateValue) {
|
||||
payload.pedimento_dates = {
|
||||
@@ -148,8 +167,6 @@
|
||||
original_date: datesFormData.original_date || null,
|
||||
start_date: datesFormData.start_date || null,
|
||||
end_date: datesFormData.end_date || null,
|
||||
capture_date: datesFormData.capture_date || null,
|
||||
capture_time: datesFormData.capture_time || null
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -267,20 +284,7 @@
|
||||
<div class="space-y-1">
|
||||
<div class="flex items-center gap-3">
|
||||
<Button variant="ghost" size="icon" onclick={handleBack}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="m12 19-7-7 7-7" />
|
||||
<path d="M19 12H5" />
|
||||
</svg>
|
||||
<ArrowLeft size={20} />
|
||||
</Button>
|
||||
<h1 class="text-3xl font-bold tracking-tight">
|
||||
{#if data.isCreate}
|
||||
@@ -312,21 +316,7 @@
|
||||
<!-- Alertas globales -->
|
||||
{#if error}
|
||||
<Alert.Root variant="destructive">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<circle cx="12" cy="12" r="10" />
|
||||
<line x1="12" x2="12" y1="8" y2="12" />
|
||||
<line x1="12" x2="12.01" y1="16" y2="16" />
|
||||
</svg>
|
||||
<CircleAlert size={16} />
|
||||
<Alert.Title>Error</Alert.Title>
|
||||
<Alert.Description>{error}</Alert.Description>
|
||||
</Alert.Root>
|
||||
@@ -334,217 +324,105 @@
|
||||
|
||||
{#if success}
|
||||
<Alert.Root>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10z" />
|
||||
<path d="m9 12 2 2 4-4" />
|
||||
</svg>
|
||||
<CircleCheck size={16} />
|
||||
<Alert.Title>Éxito</Alert.Title>
|
||||
<Alert.Description>Todos los cambios se guardaron correctamente</Alert.Description>
|
||||
</Alert.Root>
|
||||
{/if}
|
||||
|
||||
<!-- Tabs Navigation -->
|
||||
<Tabs.Root bind:value={activeTab} class="space-y-4">
|
||||
<Tabs.List class="grid w-full grid-cols-5">
|
||||
<Tabs.Trigger value="general" disabled={false}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z" />
|
||||
<polyline points="14 2 14 8 20 8" />
|
||||
</svg>
|
||||
General
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger value="dates" disabled={false}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<rect width="18" height="18" x="3" y="4" rx="2" ry="2" />
|
||||
<line x1="16" x2="16" y1="2" y2="6" />
|
||||
<line x1="8" x2="8" y1="2" y2="6" />
|
||||
<line x1="3" x2="21" y1="10" y2="10" />
|
||||
</svg>
|
||||
Fechas
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger value="payments" disabled={false}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<rect width="20" height="14" x="2" y="5" rx="2" />
|
||||
<line x1="2" x2="22" y1="10" y2="10" />
|
||||
</svg>
|
||||
Pagos
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger value="transport" disabled={false}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M14 18V6a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v11a1 1 0 0 0 1 1h2" />
|
||||
<path d="M15 18H9" />
|
||||
<path d="M19 18h2a1 1 0 0 0 1-1v-3.65a1 1 0 0 0-.22-.624l-3.48-4.35A1 1 0 0 0 17.52 8H14" />
|
||||
<circle cx="17" cy="18" r="2" />
|
||||
<circle cx="7" cy="18" r="2" />
|
||||
</svg>
|
||||
Transporte
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger value="validation" disabled={false}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10" />
|
||||
<path d="m9 12 2 2 4-4" />
|
||||
</svg>
|
||||
Validación
|
||||
</Tabs.Trigger>
|
||||
</Tabs.List>
|
||||
<!-- Contenido de las tabs con padding inferior para el footer flotante -->
|
||||
<div class="pb-48">
|
||||
<Tabs.Root bind:value={activeTab} class="space-y-4">
|
||||
<Tabs.Content value="general">
|
||||
<GeneralTabForm
|
||||
pedimento={data.pedimento}
|
||||
bind:formData={generalFormData}
|
||||
pedimentoCodes={data.pedimentoCodes || []}
|
||||
customsSections={data.customsSections || []}
|
||||
customsBrokers={data.customsBrokers || []}
|
||||
clients={data.clients || []}
|
||||
codePedimentoRegimens={data.codePedimentoRegimens || []}
|
||||
/>
|
||||
</Tabs.Content>
|
||||
|
||||
<Tabs.Content value="general">
|
||||
<GeneralTabForm
|
||||
pedimento={data.pedimento}
|
||||
bind:formData={generalFormData}
|
||||
pedimentoCodes={data.pedimentoCodes || []}
|
||||
/>
|
||||
</Tabs.Content>
|
||||
<Tabs.Content value="dates">
|
||||
<DatesTabForm
|
||||
pedimento={data.pedimento}
|
||||
bind:formData={datesFormData}
|
||||
bind:exists={datesExists}
|
||||
/>
|
||||
</Tabs.Content>
|
||||
|
||||
<Tabs.Content value="dates">
|
||||
<DatesTabForm
|
||||
pedimento={data.pedimento}
|
||||
bind:formData={datesFormData}
|
||||
bind:exists={datesExists}
|
||||
/>
|
||||
</Tabs.Content>
|
||||
<Tabs.Content value="payments">
|
||||
<PaymentsTabForm
|
||||
pedimento={data.pedimento}
|
||||
bind:formData={paymentsFormData}
|
||||
bind:exists={paymentsExists}
|
||||
/>
|
||||
</Tabs.Content>
|
||||
|
||||
<Tabs.Content value="payments">
|
||||
<PaymentsTabForm
|
||||
pedimento={data.pedimento}
|
||||
bind:formData={paymentsFormData}
|
||||
bind:exists={paymentsExists}
|
||||
/>
|
||||
</Tabs.Content>
|
||||
<Tabs.Content value="transport">
|
||||
<TransportTabForm
|
||||
pedimento={data.pedimento}
|
||||
bind:formData={transportFormData}
|
||||
bind:exists={transportExists}
|
||||
/>
|
||||
</Tabs.Content>
|
||||
|
||||
<Tabs.Content value="transport">
|
||||
<TransportTabForm
|
||||
pedimento={data.pedimento}
|
||||
bind:formData={transportFormData}
|
||||
bind:exists={transportExists}
|
||||
/>
|
||||
</Tabs.Content>
|
||||
|
||||
<Tabs.Content value="validation">
|
||||
<ValidationTabForm
|
||||
pedimento={data.pedimento}
|
||||
bind:formData={validationFormData}
|
||||
bind:exists={validationExists}
|
||||
/>
|
||||
</Tabs.Content>
|
||||
</Tabs.Root>
|
||||
|
||||
<!-- Botón de guardar global -->
|
||||
<Card.Root>
|
||||
<Card.Content class="pt-6">
|
||||
<div class="flex justify-end gap-3">
|
||||
<Button type="button" variant="outline" onclick={handleBack} disabled={saving}>
|
||||
Cancelar
|
||||
</Button>
|
||||
<Button onclick={handleSaveAll} disabled={saving}>
|
||||
{#if saving}
|
||||
<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"
|
||||
/>
|
||||
<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"
|
||||
/>
|
||||
</svg>
|
||||
Guardando todos los cambios...
|
||||
{:else}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z" />
|
||||
<polyline points="17 21 17 13 7 13 7 21" />
|
||||
<polyline points="7 3 7 8 15 8" />
|
||||
</svg>
|
||||
Guardar Todos los Cambios
|
||||
{/if}
|
||||
</Button>
|
||||
</div>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
<Tabs.Content value="validation">
|
||||
<ValidationTabForm
|
||||
pedimento={data.pedimento}
|
||||
bind:formData={validationFormData}
|
||||
bind:exists={validationExists}
|
||||
/>
|
||||
</Tabs.Content>
|
||||
</Tabs.Root>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Footer fijo en la parte inferior - Fuera del contenedor principal -->
|
||||
<div class="fixed bottom-0 inset-x-0 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/80 border-t shadow-lg z-50 group-has-[[data-sidebar]]/sidebar-wrapper:left-[var(--sidebar-width)]">
|
||||
<div class="px-4 py-4 space-y-4 max-w-[1400px] mx-auto">
|
||||
<!-- Tabs Navigation -->
|
||||
<Tabs.Root bind:value={activeTab}>
|
||||
<Tabs.List class="grid w-full grid-cols-5">
|
||||
<Tabs.Trigger value="general" disabled={false}>
|
||||
<FileText size={16} class="mr-2" />
|
||||
General
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger value="dates" disabled={false}>
|
||||
<Calendar size={16} class="mr-2" />
|
||||
Fechas
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger value="payments" disabled={false}>
|
||||
<CreditCard size={16} class="mr-2" />
|
||||
Pagos
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger value="transport" disabled={false}>
|
||||
<Truck size={16} class="mr-2" />
|
||||
Transporte
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger value="validation" disabled={false}>
|
||||
<ShieldCheck size={16} class="mr-2" />
|
||||
Validación
|
||||
</Tabs.Trigger>
|
||||
</Tabs.List>
|
||||
</Tabs.Root>
|
||||
|
||||
<!-- Botones de acción -->
|
||||
<div class="flex justify-end gap-3">
|
||||
<Button type="button" variant="outline" onclick={handleBack} disabled={saving}>
|
||||
Cancelar
|
||||
</Button>
|
||||
<Button onclick={handleSaveAll} disabled={saving}>
|
||||
{#if saving}
|
||||
<LoaderCircle class="mr-2 h-4 w-4 animate-spin" />
|
||||
Guardando todos los cambios...
|
||||
{:else}
|
||||
<Save size={16} class="mr-2" />
|
||||
Guardar Todos los Cambios
|
||||
{/if}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import type { PageData } from './$types';
|
||||
import { browser } from '$app/environment';
|
||||
import { Plus, RefreshCw } from 'lucide-svelte';
|
||||
|
||||
// Los datos iniciales vienen del servidor
|
||||
let { data }: { data: PageData } = $props();
|
||||
@@ -120,21 +121,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<Button onclick={handleCreateClick}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M5 12h14" />
|
||||
<path d="M12 5v14" />
|
||||
</svg>
|
||||
<Plus class="mr-2" size={16} />
|
||||
Nuevo Registro
|
||||
</Button>
|
||||
</div>
|
||||
@@ -160,21 +147,7 @@
|
||||
</Card.Description>
|
||||
</div>
|
||||
<Button variant="outline" onclick={reloadData}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" />
|
||||
<path d="M21 3v5h-5" />
|
||||
</svg>
|
||||
<RefreshCw class="mr-2" size={16} />
|
||||
Actualizar
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import type { PageData } from './$types';
|
||||
import { browser } from '$app/environment';
|
||||
import { Plus, RefreshCw } from 'lucide-svelte';
|
||||
|
||||
// Los datos iniciales vienen del servidor
|
||||
let { data }: { data: PageData } = $props();
|
||||
@@ -120,21 +121,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<Button onclick={handleCreateClick}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M5 12h14" />
|
||||
<path d="M12 5v14" />
|
||||
</svg>
|
||||
<Plus class="mr-2" size={16} />
|
||||
Nuevo Contenedor
|
||||
</Button>
|
||||
</div>
|
||||
@@ -160,21 +147,7 @@
|
||||
</Card.Description>
|
||||
</div>
|
||||
<Button variant="outline" onclick={reloadData}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" />
|
||||
<path d="M21 3v5h-5" />
|
||||
</svg>
|
||||
<RefreshCw class="mr-2" size={16} />
|
||||
Actualizar
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import CreateEditDialog from '$lib/components/dashboard/reference_data/countries/create-edit-dialog.svelte';
|
||||
import * as Card from '$lib/components/ui/card';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { Plus, RefreshCw } from 'lucide-svelte';
|
||||
import type { PageData } from './$types';
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
@@ -120,21 +121,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<Button onclick={handleCreateClick}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M5 12h14" />
|
||||
<path d="M12 5v14" />
|
||||
</svg>
|
||||
<Plus class="mr-2" size={16} />
|
||||
Nuevo País
|
||||
</Button>
|
||||
</div>
|
||||
@@ -160,21 +147,7 @@
|
||||
</Card.Description>
|
||||
</div>
|
||||
<Button variant="outline" onclick={reloadData}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" />
|
||||
<path d="M21 3v5h-5" />
|
||||
</svg>
|
||||
<RefreshCw class="mr-2" size={16} />
|
||||
Actualizar
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import CreateEditDialog from '$lib/components/dashboard/reference_data/currency_types/create-edit-dialog.svelte';
|
||||
import * as Card from '$lib/components/ui/card';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { Plus, RefreshCw } from 'lucide-svelte';
|
||||
import type { PageData } from './$types';
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
@@ -120,22 +121,8 @@
|
||||
</p>
|
||||
</div>
|
||||
<Button onclick={handleCreateClick}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M5 12h14" />
|
||||
<path d="M12 5v14" />
|
||||
</svg>
|
||||
Nueva Moneda
|
||||
<Plus class="mr-2" size={16} />
|
||||
Nuevo Tipo de Moneda
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -160,21 +147,7 @@
|
||||
</Card.Description>
|
||||
</div>
|
||||
<Button variant="outline" onclick={reloadData}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" />
|
||||
<path d="M21 3v5h-5" />
|
||||
</svg>
|
||||
<RefreshCw class="mr-2" size={16} />
|
||||
Actualizar
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import type { PageData } from './$types';
|
||||
import { browser } from '$app/environment';
|
||||
import { Plus, RefreshCw } from 'lucide-svelte';
|
||||
|
||||
// Los datos iniciales vienen del servidor
|
||||
let { data }: { data: PageData } = $props();
|
||||
@@ -120,21 +121,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<Button onclick={handleCreateClick}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M5 12h14" />
|
||||
<path d="M12 5v14" />
|
||||
</svg>
|
||||
<Plus class="mr-2" size={16} />
|
||||
Nueva Sección
|
||||
</Button>
|
||||
</div>
|
||||
@@ -160,21 +147,7 @@
|
||||
</Card.Description>
|
||||
</div>
|
||||
<Button variant="outline" onclick={reloadData}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" />
|
||||
<path d="M21 3v5h-5" />
|
||||
</svg>
|
||||
<RefreshCw class="mr-2" size={16} />
|
||||
Actualizar
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import type { PageData } from './$types';
|
||||
import { browser } from '$app/environment';
|
||||
import { Plus, RefreshCw } from 'lucide-svelte';
|
||||
|
||||
// Los datos iniciales vienen del servidor
|
||||
let { data }: { data: PageData } = $props();
|
||||
@@ -120,21 +121,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<Button onclick={handleCreateClick}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M5 12h14" />
|
||||
<path d="M12 5v14" />
|
||||
</svg>
|
||||
<Plus class="mr-2" size={16} />
|
||||
Nuevo Recinto
|
||||
</Button>
|
||||
</div>
|
||||
@@ -160,21 +147,7 @@
|
||||
</Card.Description>
|
||||
</div>
|
||||
<Button variant="outline" onclick={reloadData}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" />
|
||||
<path d="M21 3v5h-5" />
|
||||
</svg>
|
||||
<RefreshCw class="mr-2" size={16} />
|
||||
Actualizar
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import CreateEditDialog from '$lib/components/dashboard/reference_data/incoterms/create-edit-dialog.svelte';
|
||||
import * as Card from '$lib/components/ui/card';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { Plus, RefreshCw } from 'lucide-svelte';
|
||||
import type { PageData } from './$types';
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
@@ -120,21 +121,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<Button onclick={handleCreateClick}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M5 12h14" />
|
||||
<path d="M12 5v14" />
|
||||
</svg>
|
||||
<Plus class="mr-2" size={16} />
|
||||
Nuevo Incoterm
|
||||
</Button>
|
||||
</div>
|
||||
@@ -160,21 +147,7 @@
|
||||
</Card.Description>
|
||||
</div>
|
||||
<Button variant="outline" onclick={reloadData}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" />
|
||||
<path d="M21 3v5h-5" />
|
||||
</svg>
|
||||
<RefreshCw class="mr-2" size={16} />
|
||||
Actualizar
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import CreateEditDialog from '$lib/components/dashboard/reference_data/invoice_types/create-edit-dialog.svelte';
|
||||
import * as Card from '$lib/components/ui/card';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { Plus, RefreshCw } from 'lucide-svelte';
|
||||
import type { PageData } from './$types';
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
@@ -120,21 +121,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<Button onclick={handleCreateClick}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M5 12h14" />
|
||||
<path d="M12 5v14" />
|
||||
</svg>
|
||||
<Plus class="mr-2" size={16} />
|
||||
Nuevo Tipo de Factura
|
||||
</Button>
|
||||
</div>
|
||||
@@ -160,21 +147,7 @@
|
||||
</Card.Description>
|
||||
</div>
|
||||
<Button variant="outline" onclick={reloadData}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" />
|
||||
<path d="M21 3v5h-5" />
|
||||
</svg>
|
||||
<RefreshCw class="mr-2" size={16} />
|
||||
Actualizar
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import type { PageData } from './$types';
|
||||
import { browser } from '$app/environment';
|
||||
import { Plus, RefreshCw } from 'lucide-svelte';
|
||||
|
||||
// Los datos iniciales vienen del servidor
|
||||
let { data }: { data: PageData } = $props();
|
||||
@@ -120,21 +121,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<Button onclick={handleCreateClick}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M5 12h14" />
|
||||
<path d="M12 5v14" />
|
||||
</svg>
|
||||
<Plus class="mr-2" size={16} />
|
||||
Nuevo Tipo de Material
|
||||
</Button>
|
||||
</div>
|
||||
@@ -160,21 +147,7 @@
|
||||
</Card.Description>
|
||||
</div>
|
||||
<Button variant="outline" onclick={reloadData}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" />
|
||||
<path d="M21 3v5h-5" />
|
||||
</svg>
|
||||
<RefreshCw class="mr-2" size={16} />
|
||||
Actualizar
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import type { PageData } from './$types';
|
||||
import { browser } from '$app/environment';
|
||||
import { Plus, RefreshCw } from 'lucide-svelte';
|
||||
|
||||
// Los datos iniciales vienen del servidor
|
||||
let { data }: { data: PageData } = $props();
|
||||
@@ -120,21 +121,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<Button onclick={handleCreateClick}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M5 12h14" />
|
||||
<path d="M12 5v14" />
|
||||
</svg>
|
||||
<Plus class="mr-2" size={16} />
|
||||
Nuevo Método de Pago
|
||||
</Button>
|
||||
</div>
|
||||
@@ -160,21 +147,7 @@
|
||||
</Card.Description>
|
||||
</div>
|
||||
<Button variant="outline" onclick={reloadData}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" />
|
||||
<path d="M21 3v5h-5" />
|
||||
</svg>
|
||||
<RefreshCw class="mr-2" size={16} />
|
||||
Actualizar
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import CreateEditDialog from '$lib/components/dashboard/reference_data/pedimento_codes/create-edit-dialog.svelte';
|
||||
import * as Card from '$lib/components/ui/card';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { Plus, RefreshCw } from 'lucide-svelte';
|
||||
import type { PageData } from './$types';
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
@@ -120,22 +121,8 @@
|
||||
</p>
|
||||
</div>
|
||||
<Button onclick={handleCreateClick}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M5 12h14" />
|
||||
<path d="M12 5v14" />
|
||||
</svg>
|
||||
Nueva Clave de Pedimento
|
||||
<Plus class="mr-2" size={16} />
|
||||
Nuevo Código de Pedimento
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -160,21 +147,7 @@
|
||||
</Card.Description>
|
||||
</div>
|
||||
<Button variant="outline" onclick={reloadData}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" />
|
||||
<path d="M21 3v5h-5" />
|
||||
</svg>
|
||||
<RefreshCw class="mr-2" size={16} />
|
||||
Actualizar
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import type { PageData } from './$types';
|
||||
import { browser } from '$app/environment';
|
||||
import { Plus, RefreshCw } from 'lucide-svelte';
|
||||
|
||||
// Los datos iniciales vienen del servidor
|
||||
let { data }: { data: PageData } = $props();
|
||||
@@ -120,21 +121,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<Button onclick={handleCreateClick}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M5 12h14" />
|
||||
<path d="M12 5v14" />
|
||||
</svg>
|
||||
<Plus class="mr-2" size={16} />
|
||||
Nuevo Régimen de Pedimento
|
||||
</Button>
|
||||
</div>
|
||||
@@ -160,21 +147,7 @@
|
||||
</Card.Description>
|
||||
</div>
|
||||
<Button variant="outline" onclick={reloadData}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" />
|
||||
<path d="M21 3v5h-5" />
|
||||
</svg>
|
||||
<RefreshCw class="mr-2" size={16} />
|
||||
Actualizar
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import CreateEditDialog from '$lib/components/dashboard/reference_data/sectors/create-edit-dialog.svelte';
|
||||
import * as Card from '$lib/components/ui/card';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { Plus, RefreshCw } from 'lucide-svelte';
|
||||
import type { PageData } from './$types';
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
@@ -120,21 +121,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<Button onclick={handleCreateClick}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M5 12h14" />
|
||||
<path d="M12 5v14" />
|
||||
</svg>
|
||||
<Plus class="mr-2" size={16} />
|
||||
Nuevo Sector
|
||||
</Button>
|
||||
</div>
|
||||
@@ -160,21 +147,7 @@
|
||||
</Card.Description>
|
||||
</div>
|
||||
<Button variant="outline" onclick={reloadData}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" />
|
||||
<path d="M21 3v5h-5" />
|
||||
</svg>
|
||||
<RefreshCw class="mr-2" size={16} />
|
||||
Actualizar
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import type { PageData } from './$types';
|
||||
import { browser } from '$app/environment';
|
||||
import { Plus, RefreshCw } from 'lucide-svelte';
|
||||
|
||||
// Los datos iniciales vienen del servidor
|
||||
let { data }: { data: PageData } = $props();
|
||||
@@ -120,21 +121,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<Button onclick={handleCreateClick}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M5 12h14" />
|
||||
<path d="M12 5v14" />
|
||||
</svg>
|
||||
<Plus class="mr-2" size={16} />
|
||||
Nuevo Estado
|
||||
</Button>
|
||||
</div>
|
||||
@@ -160,21 +147,7 @@
|
||||
</Card.Description>
|
||||
</div>
|
||||
<Button variant="outline" onclick={reloadData}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" />
|
||||
<path d="M21 3v5h-5" />
|
||||
</svg>
|
||||
<RefreshCw class="mr-2" size={16} />
|
||||
Actualizar
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import type { PageData } from './$types';
|
||||
import { browser } from '$app/environment';
|
||||
import { Plus, RefreshCw } from 'lucide-svelte';
|
||||
|
||||
// Los datos iniciales vienen del servidor
|
||||
let { data }: { data: PageData } = $props();
|
||||
@@ -120,21 +121,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<Button onclick={handleCreateClick}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M5 12h14" />
|
||||
<path d="M12 5v14" />
|
||||
</svg>
|
||||
<Plus class="mr-2" size={16} />
|
||||
Nuevo Modo de Transporte
|
||||
</Button>
|
||||
</div>
|
||||
@@ -160,21 +147,7 @@
|
||||
</Card.Description>
|
||||
</div>
|
||||
<Button variant="outline" onclick={reloadData}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" />
|
||||
<path d="M21 3v5h-5" />
|
||||
</svg>
|
||||
<RefreshCw class="mr-2" size={16} />
|
||||
Actualizar
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import CreateEditDialog from '$lib/components/dashboard/reference_data/transport_types/create-edit-dialog.svelte';
|
||||
import * as Card from '$lib/components/ui/card';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { Plus, RefreshCw } from 'lucide-svelte';
|
||||
import type { PageData } from './$types';
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
@@ -120,21 +121,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<Button onclick={handleCreateClick}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M5 12h14" />
|
||||
<path d="M12 5v14" />
|
||||
</svg>
|
||||
<Plus class="mr-2" size={16} />
|
||||
Nuevo Tipo de Transporte
|
||||
</Button>
|
||||
</div>
|
||||
@@ -160,21 +147,7 @@
|
||||
</Card.Description>
|
||||
</div>
|
||||
<Button variant="outline" onclick={reloadData}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" />
|
||||
<path d="M21 3v5h-5" />
|
||||
</svg>
|
||||
<RefreshCw class="mr-2" size={16} />
|
||||
Actualizar
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import CreateEditDialog from '$lib/components/dashboard/reference_data/valuation_methods/create-edit-dialog.svelte';
|
||||
import * as Card from '$lib/components/ui/card';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { Plus, RefreshCw } from 'lucide-svelte';
|
||||
import type { PageData } from './$types';
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
@@ -120,21 +121,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<Button onclick={handleCreateClick}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M5 12h14" />
|
||||
<path d="M12 5v14" />
|
||||
</svg>
|
||||
<Plus size={16} class="mr-2" />
|
||||
Nuevo Método de Valoración
|
||||
</Button>
|
||||
</div>
|
||||
@@ -160,21 +147,7 @@
|
||||
</Card.Description>
|
||||
</div>
|
||||
<Button variant="outline" onclick={reloadData}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-2"
|
||||
>
|
||||
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" />
|
||||
<path d="M21 3v5h-5" />
|
||||
</svg>
|
||||
<RefreshCw size={16} class="mr-2" />
|
||||
Actualizar
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user