feat: implement automatic URL updates and filter application for invoice dashboard

This commit is contained in:
AlexeerCT
2025-12-19 11:19:30 -06:00
parent e937f48de4
commit f8fbfb0c4b
2 changed files with 60 additions and 24 deletions

View File

@@ -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>

View File

@@ -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}