feat: implement automatic URL updates and filter application for invoice dashboard
This commit is contained in:
@@ -57,6 +57,46 @@
|
||||
}
|
||||
});
|
||||
|
||||
// Efecto para actualizar la URL cuando cambien los filtros
|
||||
$effect(() => {
|
||||
if (browser) {
|
||||
const params = new URLSearchParams();
|
||||
|
||||
if (filters.operation_type) params.set('operation_type', filters.operation_type);
|
||||
if (filters.invoice_type) params.set('invoice_type', filters.invoice_type);
|
||||
if (filters.invoice_number) params.set('invoice_number', filters.invoice_number);
|
||||
if (filters.project_number) params.set('project_number', filters.project_number);
|
||||
if (filters.year) params.set('year', filters.year);
|
||||
|
||||
const queryString = params.toString();
|
||||
const newUrl = queryString ? `?${queryString}` : window.location.pathname;
|
||||
|
||||
// Solo actualizar si la URL es diferente (evitar loops infinitos)
|
||||
if (window.location.search !== (queryString ? `?${queryString}` : '')) {
|
||||
window.history.replaceState({}, '', newUrl);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Efecto para aplicar filtros automáticamente cuando cambian
|
||||
let filterTimeout: ReturnType<typeof setTimeout> | null = null;
|
||||
$effect(() => {
|
||||
// Observar cambios en los filtros
|
||||
const _ = {
|
||||
operation_type: filters.operation_type,
|
||||
invoice_type: filters.invoice_type,
|
||||
invoice_number: filters.invoice_number,
|
||||
project_number: filters.project_number,
|
||||
year: filters.year
|
||||
};
|
||||
|
||||
// Debounce para evitar múltiples llamadas rápidas
|
||||
if (filterTimeout) clearTimeout(filterTimeout);
|
||||
filterTimeout = setTimeout(() => {
|
||||
applyFilters();
|
||||
}, 300); // Esperar 300ms después del último cambio
|
||||
});
|
||||
|
||||
// Sincronizar token de cookies a localStorage al montar el componente
|
||||
onMount(() => {
|
||||
if (browser) {
|
||||
@@ -269,19 +309,16 @@
|
||||
}
|
||||
|
||||
function handleCreateClick() {
|
||||
// Construir URL con los filtros actuales como query parameters
|
||||
const params = new URLSearchParams();
|
||||
// Leer los filtros actuales desde la URL (que ya se actualizó con el $effect)
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
|
||||
// Mapear operation_type de 'imp'/'exp' a números 1/2
|
||||
if (filters.operation_type) {
|
||||
const operationTypeNumber = filters.operation_type === 'exp' ? 1 : 2;
|
||||
const operationType = params.get('operation_type');
|
||||
if (operationType) {
|
||||
const operationTypeNumber = operationType === 'exp' ? 1 : 2;
|
||||
params.set('operation_type', operationTypeNumber.toString());
|
||||
}
|
||||
|
||||
if (filters.invoice_type) {
|
||||
params.set('invoice_type', filters.invoice_type);
|
||||
}
|
||||
|
||||
const queryString = params.toString();
|
||||
const url = queryString
|
||||
? `/dashboard/invoices/edit/new?${queryString}`
|
||||
@@ -358,10 +395,10 @@
|
||||
<Card.Root>
|
||||
<Card.Header>
|
||||
<Card.Title>Filtros</Card.Title>
|
||||
<Card.Description>Filtra las facturas por diferentes criterios</Card.Description>
|
||||
<Card.Description>Filtra las facturas por diferentes criterios (los filtros se aplican automáticamente)</Card.Description>
|
||||
</Card.Header>
|
||||
<Card.Content>
|
||||
<form onsubmit={(e) => { e.preventDefault(); applyFilters(); }} class="grid grid-cols-1 md:grid-cols-5 gap-4">
|
||||
<div class="grid grid-cols-1 md:grid-cols-5 gap-4">
|
||||
<div class="space-y-2">
|
||||
<Label for="filter-operation-type">Tipo de Operación</Label>
|
||||
<select
|
||||
@@ -415,17 +452,7 @@
|
||||
maxlength={4}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex items-end gap-2 md:col-span-5">
|
||||
<Button type="submit" disabled={loading} class="flex-1">
|
||||
<Filter class="mr-2" size={16} />
|
||||
Filtrar
|
||||
</Button>
|
||||
<Button type="button" variant="outline" onclick={clearFilters} disabled={loading}>
|
||||
<Trash2 size={16} />
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
import LogisticsTabForm from '$lib/components/dashboard/invoices/edit/logistics-tab-form.svelte';
|
||||
|
||||
// Importar la API de facturas
|
||||
import { invoicesApi, type CreateInvoiceData, type UpdateInvoiceData } from '$lib/api/dashboard/a76/invoices';
|
||||
import { invoicesApi, type CreateInvoiceData, type UpdateInvoiceData, type OperationType } from '$lib/api/dashboard/a76/invoices';
|
||||
import type { InvoiceType } from '$lib/api/dashboard/refrence_data/invoice_types';
|
||||
import type { CustomsBroker } from '$lib/api/dashboard/a76/customs-brokers';
|
||||
import type { ClientProvider } from '$lib/api/dashboard/a76/clients-providers';
|
||||
@@ -110,8 +110,10 @@
|
||||
|
||||
// Construir el payload unificado
|
||||
const payload: CreateInvoiceData | UpdateInvoiceData = {
|
||||
// Datos generales
|
||||
operation_type: generalFormData?.operation_type || undefined,
|
||||
// Datos generales - convertir operation_type de número a string
|
||||
operation_type: generalFormData?.operation_type
|
||||
? (generalFormData.operation_type === 1 ? 'exp' : 'imp') as OperationType
|
||||
: undefined,
|
||||
invoice_type: generalFormData?.invoice_type || undefined,
|
||||
invoice_number: generalFormData?.invoice_number || undefined,
|
||||
project_number: generalFormData?.project_number || undefined,
|
||||
@@ -265,7 +267,14 @@
|
||||
</Button>
|
||||
<h1 class="text-3xl font-bold tracking-tight">
|
||||
{#if data.isCreate}
|
||||
{@const invoiceType = generalFormData?.invoice_type || data.filters?.invoice_type}
|
||||
{@const invoiceTypeInfo = invoiceType ? data.invoiceTypes?.find(t => t.key === invoiceType) : null}
|
||||
Nueva Factura
|
||||
{#if invoiceTypeInfo}
|
||||
<span class="text-muted-foreground font-normal text-2xl">
|
||||
- {invoiceTypeInfo.description}
|
||||
</span>
|
||||
{/if}
|
||||
{:else}
|
||||
Factura #{data.invoice.id}
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user