diff --git a/backend/api/v1/modules/a76/pedmientos/services/pedimentos.py b/backend/api/v1/modules/a76/pedmientos/services/pedimentos.py index 09a607df..a58756f6 100644 --- a/backend/api/v1/modules/a76/pedmientos/services/pedimentos.py +++ b/backend/api/v1/modules/a76/pedmientos/services/pedimentos.py @@ -3,9 +3,10 @@ Service layer for Pedimentos CRUD operations """ import logging +import re from typing import Any, Dict, List, Optional -from sqlalchemy import desc +from sqlalchemy import desc, func from sqlalchemy.orm import Session, joinedload from sqlalchemy.orm import selectinload from sqlalchemy.exc import IntegrityError @@ -95,10 +96,21 @@ class PedimentosService: if filters.get("status"): query = query.filter(Pedimentos.status == filters["status"]) if filters.get("client_id"): - query = query.filter( - Pedimentos.client_id == filters["client_id"]) + query = query.filter(Pedimentos.client_id == filters["client_id"]) if filters.get("year"): query = query.filter(Pedimentos.year == filters["year"]) + if filters.get("pedimento"): + raw_value = str(filters["pedimento"]) + # Normalizar: dejar solo dígitos (ignorar guiones, espacios, etc.) + normalized = re.sub(r"\D", "", raw_value) + if normalized: + ped_key_expr = func.concat( + func.coalesce(Pedimentos.year, ""), + func.coalesce(func.substr(Pedimentos.customs_office, 1, 2), ""), + func.coalesce(Pedimentos.license, ""), + func.coalesce(Pedimentos.pedimento_number, ""), + ) + query = query.filter(ped_key_expr.ilike(f"%{normalized}%")) total = query.count() diff --git a/backend/api/v1/modules/public/reference_data/incoterms/routes.py b/backend/api/v1/modules/public/reference_data/incoterms/routes.py index 02b278fc..261cfddc 100644 --- a/backend/api/v1/modules/public/reference_data/incoterms/routes.py +++ b/backend/api/v1/modules/public/reference_data/incoterms/routes.py @@ -15,11 +15,22 @@ router = APIRouter(prefix="/incoterms") async def list_incoterms( page: int = Query(1, ge=1, description="Número de página"), page_size: int = Query(50, ge=1, le=100, description="Tamaño de página"), + code: str = Query(None, description="Filtrar por clave"), + description: str = Query(None, description="Filtrar por descripción"), db: Session = Depends(get_core_db), current_user: dict = Depends(get_current_user), ): skip = (page - 1) * page_size query = db.query(Incoterm) + + if code: + query = query.filter(Incoterm.code.ilike(f"%{code}%")) + if description: + query = query.filter( + (Incoterm.description_es.ilike(f"%{description}%")) | + (Incoterm.description_en.ilike(f"%{description}%")) + ) + items = query.offset(skip).limit(page_size).all() total = query.count() return { diff --git a/frontend/src/app.css b/frontend/src/app.css index 6c344082..627e3836 100644 --- a/frontend/src/app.css +++ b/frontend/src/app.css @@ -121,3 +121,45 @@ @apply bg-background text-foreground overflow-x-hidden; } } + +@layer components { + .catalog-table-shell { + @apply rounded-md border border-border/80 bg-card shadow-sm; + } + + .catalog-table-scroll { + @apply relative w-full flex-1 overflow-auto bg-card; + } + + .catalog-table-header { + @apply sticky top-0 z-20 border-b border-border/80 bg-card/95 shadow-sm backdrop-blur-md; + } + + .catalog-table-head-cell { + @apply whitespace-nowrap text-sm font-semibold text-foreground/90; + } + + .catalog-table-row { + @apply transition-colors hover:bg-accent/35; + } + + .catalog-table-row-selected { + @apply bg-accent/65 text-accent-foreground hover:bg-accent/65; + } + + .catalog-table-sticky-left { + @apply sticky left-0 border-r border-border/70 bg-card shadow-[4px_0_12px_-6px_rgba(0,0,0,0.12)] dark:shadow-[4px_0_12px_-6px_rgba(0,0,0,0.35)]; + } + + .catalog-table-sticky-right { + @apply sticky right-0 border-l border-border/70 bg-card shadow-[-4px_0_12px_-6px_rgba(0,0,0,0.08)] dark:shadow-[-4px_0_12px_-6px_rgba(0,0,0,0.25)]; + } + + .catalog-table-sticky-row-hover { + @apply bg-card group-hover/inv-list:bg-accent/35; + } + + .catalog-table-sticky-row-selected { + @apply bg-accent/65 text-accent-foreground; + } +} diff --git a/frontend/src/lib/api/dashboard/a76/general_catalogs/multi-currency-types.ts b/frontend/src/lib/api/dashboard/a76/general_catalogs/multi-currency-types.ts index fb415397..a565026a 100644 --- a/frontend/src/lib/api/dashboard/a76/general_catalogs/multi-currency-types.ts +++ b/frontend/src/lib/api/dashboard/a76/general_catalogs/multi-currency-types.ts @@ -40,11 +40,14 @@ import type { ApiResponse } from '$lib/api'; export async function getMultiCurrencyTypes( companyId: number, page?: number, - pageSize?: number + pageSize?: number, + filters?: { currency_type_code?: string; country_key?: string } ): Promise> { const params = new URLSearchParams({ company_id: companyId.toString() }); if (page) params.append('page', page.toString()); if (pageSize) params.append('page_size', pageSize.toString()); + if (filters?.currency_type_code) params.append('currency_type_code', filters.currency_type_code); + if (filters?.country_key) params.append('country_key', filters.country_key); return api.get(`/v1/a76/multi-currency-types/?${params.toString()}`); } diff --git a/frontend/src/lib/api/dashboard/a76/pedimentos.ts b/frontend/src/lib/api/dashboard/a76/pedimentos.ts index dd876a08..9c5e93ec 100644 --- a/frontend/src/lib/api/dashboard/a76/pedimentos.ts +++ b/frontend/src/lib/api/dashboard/a76/pedimentos.ts @@ -273,6 +273,7 @@ export interface UpdatePedimentoData { export interface PedimentoFilters { status?: string; client_id?: number; + pedimento?: string; year?: string; sort_by?: string; sort_order?: 'asc' | 'desc' | string; diff --git a/frontend/src/lib/api/dashboard/reference_data/code_pedimento_regimens.ts b/frontend/src/lib/api/dashboard/reference_data/code_pedimento_regimens.ts index 4b927437..7bb4fa45 100644 --- a/frontend/src/lib/api/dashboard/reference_data/code_pedimento_regimens.ts +++ b/frontend/src/lib/api/dashboard/reference_data/code_pedimento_regimens.ts @@ -35,13 +35,18 @@ export interface UpdateCodePedimentoRegimenData { */ export const codePedimentoRegimensApi = { /** - * Lista todos los code pedimento regimens con paginación + * Lista todos los code pedimento regimens con paginación y búsqueda + * @param page - Número de página (por defecto 1) + * @param pageSize - Tamaño de página (por defecto 50) + * @param search - Término de búsqueda (opcional) */ - list: (page = 1, pageSize = 50) => - api.get( - // CORRECTO: Slash antes del signo '?' - `/v1/public/reference_data/code-pedimento-regimens/?page=${page}&page_size=${pageSize}` - ), + list: (page = 1, pageSize = 50, search?: string) => { + let url = `/v1/public/reference_data/code-pedimento-regimens/?page=${page}&page_size=${pageSize}`; + if (search) { + url += `&search=${encodeURIComponent(search)}`; + } + return api.get(url); + }, /** * Obtiene un por ID diff --git a/frontend/src/lib/api/dashboard/reference_data/containers.ts b/frontend/src/lib/api/dashboard/reference_data/containers.ts index 67f240d6..9e4d300b 100644 --- a/frontend/src/lib/api/dashboard/reference_data/containers.ts +++ b/frontend/src/lib/api/dashboard/reference_data/containers.ts @@ -31,15 +31,18 @@ export interface UpdateContainerData { */ export const containersApi = { /** - * Lista todos los containers con paginación + * Lista todos los containers con paginación y búsqueda * @param page - Número de página (por defecto 1) * @param pageSize - Tamaño de página (por defecto 50) + * @param search - Término de búsqueda (opcional) */ - list: (page = 1, pageSize = 50) => - api.get( - // CORRECTO: Slash antes del ? - `/v1/public/reference_data/containers/?page=${page}&page_size=${pageSize}` - ), + list: (page = 1, pageSize = 50, search?: string) => { + let url = `/v1/public/reference_data/containers/?page=${page}&page_size=${pageSize}`; + if (search) { + url += `&search=${encodeURIComponent(search)}`; + } + return api.get(url); + }, /** * Obtiene un container por ID diff --git a/frontend/src/lib/api/dashboard/reference_data/currency_types.ts b/frontend/src/lib/api/dashboard/reference_data/currency_types.ts index 387e1f3f..9199365f 100644 --- a/frontend/src/lib/api/dashboard/reference_data/currency_types.ts +++ b/frontend/src/lib/api/dashboard/reference_data/currency_types.ts @@ -34,15 +34,18 @@ export interface UpdateCurrencyTypeData { */ export const currencyTypesApi = { /** - * Lista todos los tipos de moneda con paginación + * Lista todos los tipos de moneda con paginación y búsqueda * @param page - Número de página (por defecto 1) * @param pageSize - Tamaño de página (por defecto 50) + * @param search - Término de búsqueda (opcional) */ - list: (page = 1, pageSize = 50) => - api.get( - // CORREGIDO: Añadido '/' antes del '?' - `/v1/public/reference_data/currency-types/?page=${page}&page_size=${pageSize}` - ), + list: (page = 1, pageSize = 50, search?: string) => { + let url = `/v1/public/reference_data/currency-types/?page=${page}&page_size=${pageSize}`; + if (search) { + url += `&search=${encodeURIComponent(search)}`; + } + return api.get(url); + }, /** * Obtiene un tipo de moneda por código diff --git a/frontend/src/lib/api/dashboard/reference_data/customs_sections.ts b/frontend/src/lib/api/dashboard/reference_data/customs_sections.ts index e73934d8..e0cafb6e 100644 --- a/frontend/src/lib/api/dashboard/reference_data/customs_sections.ts +++ b/frontend/src/lib/api/dashboard/reference_data/customs_sections.ts @@ -31,14 +31,18 @@ export interface UpdateCustomsSectionData { */ export const customsSectionsApi = { /** - * Lista todas las secciones aduaneras con paginación + * Lista todas las secciones aduaneras con paginación y búsqueda * @param page - Número de página (por defecto 1) * @param pageSize - Tamaño de página (por defecto 50) + * @param search - Término de búsqueda (opcional) */ - list: (page = 1, pageSize = 50) => - api.get( - `/v1/public/reference_data/customs-sections/?page=${page}&page_size=${pageSize}` - ), + list: (page = 1, pageSize = 50, search?: string) => { + let url = `/v1/public/reference_data/customs-sections/?page=${page}&page_size=${pageSize}`; + if (search) { + url += `&search=${encodeURIComponent(search)}`; + } + return api.get(url); + }, /** * Obtiene una sección aduanera por código diff --git a/frontend/src/lib/api/dashboard/reference_data/customs_warehouses.ts b/frontend/src/lib/api/dashboard/reference_data/customs_warehouses.ts index eae2b955..4e90751e 100644 --- a/frontend/src/lib/api/dashboard/reference_data/customs_warehouses.ts +++ b/frontend/src/lib/api/dashboard/reference_data/customs_warehouses.ts @@ -34,15 +34,18 @@ export interface UpdateCustomsWarehouseData { */ export const customsWarehousesApi = { /** - * Lista todos los recintos fiscalizados con paginación + * Lista todos los recintos fiscalizados con paginación y búsqueda * @param page - Número de página (por defecto 1) * @param pageSize - Tamaño de página (por defecto 50) + * @param search - Término de búsqueda (opcional) */ - list: (page = 1, pageSize = 50) => - api.get( - // CORREGIDO: Añadido '/' antes del '?' - `/v1/public/reference_data/customs-warehouses/?page=${page}&page_size=${pageSize}` - ), + list: (page = 1, pageSize = 50, search?: string) => { + let url = `/v1/public/reference_data/customs-warehouses/?page=${page}&page_size=${pageSize}`; + if (search) { + url += `&search=${encodeURIComponent(search)}`; + } + return api.get(url); + }, /** * Obtiene un recinto fiscalizado por clave compuesta (key + customs) diff --git a/frontend/src/lib/api/dashboard/reference_data/incoterms.ts b/frontend/src/lib/api/dashboard/reference_data/incoterms.ts index 2543824e..4e49deb1 100644 --- a/frontend/src/lib/api/dashboard/reference_data/incoterms.ts +++ b/frontend/src/lib/api/dashboard/reference_data/incoterms.ts @@ -34,15 +34,18 @@ export interface UpdateIncotermData { */ export const incotermsApi = { /** - * Lista todos los incoterms con paginación + * Lista todos los incoterms con paginación y filtros * @param page - Número de página (por defecto 1) * @param pageSize - Tamaño de página (por defecto 50) + * @param code - Filtrar por clave (opcional) + * @param description - Filtrar por descripción (opcional) */ - list: (page = 1, pageSize = 50) => - api.get( - // CORREGIDO: Añadido '/' antes del '?' - `/v1/public/reference_data/incoterms/?page=${page}&page_size=${pageSize}` - ), + list: (page = 1, pageSize = 50, code?: string, description?: string) => { + let url = `/v1/public/reference_data/incoterms/?page=${page}&page_size=${pageSize}`; + if (code) url += `&code=${encodeURIComponent(code)}`; + if (description) url += `&description=${encodeURIComponent(description)}`; + return api.get(url); + }, /** * Obtiene un incoterm por código diff --git a/frontend/src/lib/api/dashboard/reference_data/invoice_types.ts b/frontend/src/lib/api/dashboard/reference_data/invoice_types.ts index 87a7c264..91a90ba8 100644 --- a/frontend/src/lib/api/dashboard/reference_data/invoice_types.ts +++ b/frontend/src/lib/api/dashboard/reference_data/invoice_types.ts @@ -38,12 +38,13 @@ export interface UpdateInvoiceTypeData { */ export const invoiceTypesApi = { /** - * Lista todos los tipos de factura con paginación + * Lista todos los tipos de factura con paginación y búsqueda * @param page - Número de página (por defecto 1) * @param pageSize - Tamaño de página (por defecto 50) * @param operation - Filtrar por tipo de operación (imp, exp) + * @param search - Término de búsqueda (opcional) */ - list: (page = 1, pageSize = 50, operation?: string) => { + list: (page = 1, pageSize = 50, operation?: string, search?: string) => { const params = new URLSearchParams({ page: page.toString(), page_size: pageSize.toString() @@ -51,8 +52,10 @@ export const invoiceTypesApi = { if (operation) { params.append('operation', operation); } + if (search) { + params.append('search', search); + } return api.get( - // CORREGIDO: Añadido '/' antes del '?' `/v1/public/reference_data/invoice-types/?${params.toString()}` ); }, diff --git a/frontend/src/lib/api/dashboard/reference_data/material_types.ts b/frontend/src/lib/api/dashboard/reference_data/material_types.ts index d2db1ab3..a4d89267 100644 --- a/frontend/src/lib/api/dashboard/reference_data/material_types.ts +++ b/frontend/src/lib/api/dashboard/reference_data/material_types.ts @@ -34,12 +34,13 @@ */ export const materialTypesApi = { /** - * Lista todos los tipos de material con paginación + * Lista todos los tipos de material con paginación y búsqueda * @param page - Número de página (por defecto 1) * @param pageSize - Tamaño de página (por defecto 50) * @param type - Filtrar por tipo (ACTIVO FIJO, MATERIALES, PRODUCTOS) + * @param search - Término de búsqueda (opcional) */ - list: (page = 1, pageSize = 50, type?: string) => { + list: (page = 1, pageSize = 50, type?: string, search?: string) => { const params = new URLSearchParams({ page: page.toString(), page_size: pageSize.toString() @@ -47,8 +48,10 @@ export const materialTypesApi = { if (type) { params.append('type', type); } + if (search) { + params.append('search', search); + } return api.get( - // CORRECTO: Ya tiene el '/' antes del '?' `/v1/public/reference_data/material-types/?${params.toString()}` ); }, diff --git a/frontend/src/lib/api/dashboard/reference_data/payment_methods.ts b/frontend/src/lib/api/dashboard/reference_data/payment_methods.ts index e0bcbcaf..7253e13b 100644 --- a/frontend/src/lib/api/dashboard/reference_data/payment_methods.ts +++ b/frontend/src/lib/api/dashboard/reference_data/payment_methods.ts @@ -31,15 +31,18 @@ export interface UpdatePaymentMethodData { */ export const paymentMethodsApi = { /** - * Lista todos los métodos de pago con paginación + * Lista todos los métodos de pago con paginación y búsqueda * @param page - Número de página (por defecto 1) * @param pageSize - Tamaño de página (por defecto 50) + * @param search - Término de búsqueda (opcional) */ - list: (page = 1, pageSize = 50) => - api.get( - // CORREGIDO: Añadido '/' antes del '?' - `/v1/public/reference_data/payment-methods/?page=${page}&page_size=${pageSize}` - ), + list: (page = 1, pageSize = 50, search?: string) => { + let url = `/v1/public/reference_data/payment-methods/?page=${page}&page_size=${pageSize}`; + if (search) { + url += `&search=${encodeURIComponent(search)}`; + } + return api.get(url); + }, /** * Obtiene un método de pago por key diff --git a/frontend/src/lib/api/dashboard/reference_data/pedimento_codes.ts b/frontend/src/lib/api/dashboard/reference_data/pedimento_codes.ts index 6a5cb837..5d62d34f 100644 --- a/frontend/src/lib/api/dashboard/reference_data/pedimento_codes.ts +++ b/frontend/src/lib/api/dashboard/reference_data/pedimento_codes.ts @@ -31,15 +31,18 @@ export interface UpdatePedimentoCodeData { */ export const pedimentoCodesApi = { /** - * Lista todas las claves de pedimento con paginación + * Lista todas las claves de pedimento con paginación y búsqueda * @param page - Número de página (por defecto 1) * @param pageSize - Tamaño de página (por defecto 50) + * @param search - Término de búsqueda (opcional) */ - list: (page = 1, pageSize = 50) => - api.get( - // CORREGIDO: Añadido '/' antes del '?' - `/v1/public/reference_data/pedimento-codes/?page=${page}&page_size=${pageSize}` - ), + list: (page = 1, pageSize = 50, search?: string) => { + let url = `/v1/public/reference_data/pedimento-codes/?page=${page}&page_size=${pageSize}`; + if (search) { + url += `&search=${encodeURIComponent(search)}`; + } + return api.get(url); + }, /** * Obtiene una clave de pedimento por code diff --git a/frontend/src/lib/api/dashboard/reference_data/pedimento_regimens.ts b/frontend/src/lib/api/dashboard/reference_data/pedimento_regimens.ts index 9466a70d..124c9a7b 100644 --- a/frontend/src/lib/api/dashboard/reference_data/pedimento_regimens.ts +++ b/frontend/src/lib/api/dashboard/reference_data/pedimento_regimens.ts @@ -31,15 +31,18 @@ export interface UpdatePedimentoRegimenData { */ export const pedimentoRegimensApi = { /** - * Lista todos los regímenes de pedimento con paginación + * Lista todos los regímenes de pedimento con paginación y búsqueda * @param page - Número de página (por defecto 1) * @param pageSize - Tamaño de página (por defecto 50) + * @param search - Término de búsqueda (opcional) */ - list: (page = 1, pageSize = 50) => - api.get( - // CORREGIDO: Añadido '/' antes del '?' - `/v1/public/reference_data/pedimento-regimens/?page=${page}&page_size=${pageSize}` - ), + list: (page = 1, pageSize = 50, search?: string) => { + let url = `/v1/public/reference_data/pedimento-regimens/?page=${page}&page_size=${pageSize}`; + if (search) { + url += `&search=${encodeURIComponent(search)}`; + } + return api.get(url); + }, /** * Obtiene un régimen de pedimento por code diff --git a/frontend/src/lib/api/dashboard/reference_data/states.ts b/frontend/src/lib/api/dashboard/reference_data/states.ts index 93a1db35..f7baf99d 100644 --- a/frontend/src/lib/api/dashboard/reference_data/states.ts +++ b/frontend/src/lib/api/dashboard/reference_data/states.ts @@ -37,15 +37,18 @@ export interface UpdateStateData { */ export const statesApi = { /** - * Lista todos los estados con paginación + * Lista todos los estados con paginación y búsqueda * @param page - Número de página (por defecto 1) * @param pageSize - Tamaño de página (por defecto 50) + * @param search - Término de búsqueda (opcional) */ - list: (page = 1, pageSize = 50) => - api.get( - // CORREGIDO: Añadido '/' antes de '?' - `/v1/public/reference_data/states/?page=${page}&page_size=${pageSize}` - ), + list: (page = 1, pageSize = 50, search?: string) => { + let url = `/v1/public/reference_data/states/?page=${page}&page_size=${pageSize}`; + if (search) { + url += `&search=${encodeURIComponent(search)}`; + } + return api.get(url); + }, /** * Obtiene un estado por m3_key diff --git a/frontend/src/lib/api/dashboard/reference_data/transport_modes.ts b/frontend/src/lib/api/dashboard/reference_data/transport_modes.ts index 5bb23ad9..a16b9a4e 100644 --- a/frontend/src/lib/api/dashboard/reference_data/transport_modes.ts +++ b/frontend/src/lib/api/dashboard/reference_data/transport_modes.ts @@ -31,14 +31,18 @@ export interface UpdateTransportModeData { */ export const transportModesApi = { /** - * Lista todos los modos de transporte con paginación + * Lista todos los modos de transporte con paginación y búsqueda * @param page - Número de página (por defecto 1) * @param pageSize - Tamaño de página (por defecto 50) + * @param search - Término de búsqueda (opcional) */ - list: (page = 1, pageSize = 50) => - api.get( - `/v1/public/reference_data/transport-modes/?page=${page}&page_size=${pageSize}` - ), + list: (page = 1, pageSize = 50, search?: string) => { + let url = `/v1/public/reference_data/transport-modes/?page=${page}&page_size=${pageSize}`; + if (search) { + url += `&search=${encodeURIComponent(search)}`; + } + return api.get(url); + }, /** * Obtiene un modo de transporte por key diff --git a/frontend/src/lib/api/dashboard/reference_data/transport_types.ts b/frontend/src/lib/api/dashboard/reference_data/transport_types.ts index 12b162b1..6b473373 100644 --- a/frontend/src/lib/api/dashboard/reference_data/transport_types.ts +++ b/frontend/src/lib/api/dashboard/reference_data/transport_types.ts @@ -31,12 +31,18 @@ export interface UpdateTransportTypeData { */ export const transportTypesApi = { /** - * Lista todos los tipos de transporte con paginación + * Lista todos los tipos de transporte con paginación y búsqueda + * @param page - Número de página (por defecto 1) + * @param pageSize - Tamaño de página (por defecto 50) + * @param search - Término de búsqueda (opcional) */ - list: (page = 1, pageSize = 50) => - api.get( - `/v1/public/reference_data/transport-types/?page=${page}&page_size=${pageSize}` - ), + list: (page = 1, pageSize = 50, search?: string) => { + let url = `/v1/public/reference_data/transport-types/?page=${page}&page_size=${pageSize}`; + if (search) { + url += `&search=${encodeURIComponent(search)}`; + } + return api.get(url); + }, /** * Obtiene un tipo de transporte por transport_code diff --git a/frontend/src/lib/api/dashboard/reference_data/valuation_methods.ts b/frontend/src/lib/api/dashboard/reference_data/valuation_methods.ts index df4a320c..6f3badb8 100644 --- a/frontend/src/lib/api/dashboard/reference_data/valuation_methods.ts +++ b/frontend/src/lib/api/dashboard/reference_data/valuation_methods.ts @@ -31,15 +31,18 @@ export interface UpdateValuationMethodData { */ export const valuationMethodsApi = { /** - * Lista todos los métodos de valoración con paginación + * Lista todos los métodos de valoración con paginación y búsqueda * @param page - Número de página (por defecto 1) * @param pageSize - Tamaño de página (por defecto 50) + * @param search - Término de búsqueda (opcional) */ - list: (page = 1, pageSize = 50) => - api.get( - // CORREGIDO: Añadido '/' antes del '?' - `/v1/public/reference_data/valuation-methods/?page=${page}&page_size=${pageSize}` - ), + list: (page = 1, pageSize = 50, search?: string) => { + let url = `/v1/public/reference_data/valuation-methods/?page=${page}&page_size=${pageSize}`; + if (search) { + url += `&search=${encodeURIComponent(search)}`; + } + return api.get(url); + }, /** * Obtiene un método de valoración por key diff --git a/frontend/src/lib/components/dashboard/clients_and_providers/data-table.svelte b/frontend/src/lib/components/dashboard/clients_and_providers/data-table.svelte index 4c448e3d..2f4a88e7 100644 --- a/frontend/src/lib/components/dashboard/clients_and_providers/data-table.svelte +++ b/frontend/src/lib/components/dashboard/clients_and_providers/data-table.svelte @@ -60,7 +60,10 @@
-
+
{#each table.getHeaderGroups() as headerGroup (headerGroup.id)} diff --git a/frontend/src/lib/components/dashboard/common/infinite-data-table.svelte b/frontend/src/lib/components/dashboard/common/infinite-data-table.svelte new file mode 100644 index 00000000..5fbee4e3 --- /dev/null +++ b/frontend/src/lib/components/dashboard/common/infinite-data-table.svelte @@ -0,0 +1,152 @@ + + +
+
+ + + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} + {@const headerList = headerGroup.headers} + {@const lastHeaderColId = headerList[headerList.length - 1]?.column.id} + + {#each headerList as header (header.id)} + {@const colId = header.column.id} + + {#if !header.isPlaceholder} + + {/if} + + {/each} + + {/each} + + + {#if table.getRowModel().rows.length} + {#each table.getRowModel().rows as row (row.id)} + {@const visibleCells = row.getVisibleCells()} + {@const lastCellColId = visibleCells[visibleCells.length - 1]?.column.id} + + {#each visibleCells as cell (cell.id)} + {@const colId = cell.column.id} + + + + {/each} + + {/each} + {:else} + + + {emptyMessage} + + + {/if} + + {#if hasMore} + + +
+ {#if loading} +
+
+ Cargando más registros... +
+ {:else} +
+ + Desplázate para cargar más + +
+ {/if} +
+
+
+ {/if} +
+
+
+
diff --git a/frontend/src/lib/components/dashboard/export/manifest/data-table.svelte b/frontend/src/lib/components/dashboard/export/manifest/data-table.svelte index 0cdb9644..ec6893aa 100644 --- a/frontend/src/lib/components/dashboard/export/manifest/data-table.svelte +++ b/frontend/src/lib/components/dashboard/export/manifest/data-table.svelte @@ -71,7 +71,10 @@
-
+
{#each table.getHeaderGroups() as headerGroup (headerGroup.id)} diff --git a/frontend/src/lib/components/dashboard/general_catalogs/doda/data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/doda/data-table.svelte index b96d47d8..483cc79e 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/doda/data-table.svelte +++ b/frontend/src/lib/components/dashboard/general_catalogs/doda/data-table.svelte @@ -67,14 +67,18 @@ }); -
-
- - +
+
+
+ + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} {#each headerGroup.headers as header (header.id)} - + {#if !header.isPlaceholder} onRowClick?.(row.original)} - class="cursor-pointer transition-colors {row.getIsSelected() - ? 'bg-gray-300 dark:bg-gray-600' - : 'hover:bg-gray-100 dark:hover:bg-gray-700'}" + class="cursor-pointer {row.getIsSelected() ? 'catalog-table-row-selected' : 'catalog-table-row'}" > {#each row.getVisibleCells() as cell (cell.id)} @@ -103,7 +105,7 @@ {:else} - + No hay resultados. @@ -128,6 +130,7 @@ {/if} - + +
diff --git a/frontend/src/lib/components/dashboard/general_catalogs/inpc/data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/inpc/data-table.svelte index 3712b6f3..21ade40a 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/inpc/data-table.svelte +++ b/frontend/src/lib/components/dashboard/general_catalogs/inpc/data-table.svelte @@ -38,67 +38,69 @@ } -
- - - {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - - {#each headerGroup.headers as header (header.id)} - - {#if !header.isPlaceholder} - - {/if} - - {/each} - - {/each} - - - {#if table.getRowModel().rows.length} - {#each table.getRowModel().rows as row (row.id)} - - {#each row.getVisibleCells() as cell (cell.id)} - - - +
+
+ + + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} + + {#each headerGroup.headers as header (header.id)} + + {#if !header.isPlaceholder} + + {/if} + {/each} {/each} - {:else} - - - No hay resultados. - - - {/if} - - -
- -
-
- Total: {totalItems} registros + + + {#if table.getRowModel().rows.length} + {#each table.getRowModel().rows as row (row.id)} + + {#each row.getVisibleCells() as cell (cell.id)} + + + + {/each} + + {/each} + {:else} + + + No hay resultados. + + + {/if} + + +
+ +
+
+ Total: {totalItems} registros +
+ +
- -
diff --git a/frontend/src/lib/components/dashboard/general_catalogs/legends/data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/legends/data-table.svelte index 72fb9bf3..e1efce5b 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/legends/data-table.svelte +++ b/frontend/src/lib/components/dashboard/general_catalogs/legends/data-table.svelte @@ -40,67 +40,69 @@ const currentPage = $derived(Number($page.url.searchParams.get('page') || 1)); -
- - - {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - - {#each headerGroup.headers as header (header.id)} - - {#if !header.isPlaceholder} - - {/if} - +
+
+ + + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} + + {#each headerGroup.headers as header (header.id)} + + {#if !header.isPlaceholder} + + {/if} + + {/each} + {/each} - - {/each} - - - {#each table.getRowModel().rows as row (row.id)} - - {#each row.getVisibleCells() as cell (cell.id)} - - - + + + {#each table.getRowModel().rows as row (row.id)} + + {#each row.getVisibleCells() as cell (cell.id)} + + + + {/each} + + {:else} + + + No hay resultados. + + {/each} - - {:else} - - - No hay resultados. - - - {/each} - - -
+ + +
-
-
- Total: {totalItems} registros +
+
+ Total: {totalItems} registros +
+
+ + +
+
-
- - -
-
diff --git a/frontend/src/lib/components/dashboard/general_catalogs/sectors/SectorsList.svelte b/frontend/src/lib/components/dashboard/general_catalogs/sectors/SectorsList.svelte index 78137b1f..dd8be92c 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/sectors/SectorsList.svelte +++ b/frontend/src/lib/components/dashboard/general_catalogs/sectors/SectorsList.svelte @@ -1,9 +1,8 @@ -
+ +
-

{title}

+

{title}

- + -
-
- - +
+ Listado de Sectores +
+
+ + +
- -
+ +
+
- + - Clave - Descripción - Estatus + Clave + Descripción + Estatus @@ -150,7 +154,7 @@ {:else} {#each sectors as sector} - + {sector.key} {sector.description} @@ -174,15 +178,13 @@ {/if} -
- -
-
- Mostrando {sectors.length} de {total} registros
- -
+ +
Mostrando {sectors.length} de {total} registros
+ + +
diff --git a/frontend/src/lib/components/dashboard/goods/fractions/CanadianFractionList.svelte b/frontend/src/lib/components/dashboard/goods/fractions/CanadianFractionList.svelte index 7513162c..17d936e1 100644 --- a/frontend/src/lib/components/dashboard/goods/fractions/CanadianFractionList.svelte +++ b/frontend/src/lib/components/dashboard/goods/fractions/CanadianFractionList.svelte @@ -1,5 +1,5 @@ -
-
-
-
- -
- - +
+ + +
+ Listado de Fracciones Canadienses +
+
+ + +
+
-
- -
- -
- - - - Fracción - Descripción - País - Unidad - ADV - Acciones - - - - {#if fractions.length === 0 && !loading} - - No se encontraron resultados - - {:else} - {#each fractions as fraction} + + +
+
+ + - {fraction.fraction} - {fraction.description || '-'} - {fraction.country_code} - {fraction.unit_of_measure || '-'} - {fraction.ad_valorem ?? '-'} - -
- - -
-
+ Fracción + Descripción + País + Unidad + ADV + Acciones
- {/each} - {/if} - {#if loading} - - -
- -
-
-
- {/if} - -
-
+ + + {#if fractions.length === 0 && !loading} + + No se encontraron resultados + + {:else} + {#each fractions as fraction} + + {fraction.fraction} + {fraction.description || '-'} + {fraction.country_code} + {fraction.unit_of_measure || '-'} + {fraction.ad_valorem ?? '-'} + +
+ + +
+
+
+ {/each} + {/if} + {#if loading} + + +
+ +
+
+
+ {/if} +
+ +
+
+
+ + - -
+
Mostrando {fractions.length} de {totalItems} registros
- import { onMount, untrack } from 'svelte'; + import { untrack } from 'svelte'; import { getHistoricalFractions, deleteHistoricalFraction, @@ -8,23 +8,27 @@ import * as Table from '$lib/components/ui/table'; import { Input } from '$lib/components/ui/input'; import { Button } from '$lib/components/ui/button'; + import * as Card from '$lib/components/ui/card'; import { Search, Loader2, Plus, Pencil, Trash2 } from 'lucide-svelte'; import { toast } from 'svelte-sonner'; import HistoricalFractionDialog from './HistoricalFractionDialog.svelte'; - import { companyStore } from '$lib/stores/company.svelte'; +import { companyStore } from '$lib/stores/company.svelte'; - let fractions = $state([]); - let loading = $state(false); - let historicalFraction = $state(''); - let page = $state(1); - let totalItems = $state(0); - let totalPages = $state(0); - let pageSize = 50; +let { title = 'Fracciones históricas' }: { title?: string } = $props(); - let searchTimeout: ReturnType; - let observer: IntersectionObserver; - let sentinel: HTMLDivElement; +let fractions = $state([]); +let loading = $state(false); +let historicalFraction = $state(''); +let page = $state(1); +let totalItems = $state(0); +let totalPages = $state(0); +let pageSize = 50; + +let searchTimeout: ReturnType; +let observer: IntersectionObserver; +let sentinel: HTMLDivElement; +let scrollContainer: HTMLDivElement; // Infinite scroll state let hasMore = $state(true); @@ -138,7 +142,10 @@ loadFractions(false); } }, - { rootMargin: '100px' } + { + root: scrollContainer || null, + rootMargin: '100px' + } ); if (sentinel) observer.observe(sentinel); @@ -163,117 +170,116 @@ }); -
-
-
-
- -
- - -
-
+ +
+ +
+
+

{title}

+

+ Gestiona las fracciones históricas de la tarifa. +

-
-
- - - - Fracción - Tipo - UM - País - Fecha Pub. - Fecha Fin - IGI - IGE - Acciones - - - - {#if fractions.length === 0 && !loading} - - No se encontraron resultados - - {:else} - {#each fractions as fraction} - - {fraction.historical_fraction} - {fraction.fraction_type || '-'} - {fraction.unit_of_measure_code || '-'} - {fraction.country || '-'} - {fraction.publication_date - ? new Date(fraction.publication_date).toLocaleDateString() - : '-'} - {fraction.end_date - ? new Date(fraction.end_date).toLocaleDateString() - : '-'} - {fraction.import_tax_rate ?? '-'} - {fraction.export_tax_rate ?? '-'} - -
- - -
-
-
- {/each} - {/if} - {#if loading} - - -
- -
-
-
- {/if} -
-
-
+ + +
+ Listado de Fracciones Históricas +
+
+ + +
+
+
+
+ +
+
+ + + + Fracción + Tipo + UM + País + Fecha Pub. + Fecha Fin + IGI + IGE + Acciones + + + + {#if fractions.length === 0 && !loading} + + No se encontraron resultados + + {:else} + {#each fractions as fraction} + + {fraction.historical_fraction} + {fraction.fraction_type || '-'} + {fraction.unit_of_measure_code || '-'} + {fraction.country || '-'} + {fraction.publication_date ? new Date(fraction.publication_date).toLocaleDateString() : '-'} + {fraction.end_date ? new Date(fraction.end_date).toLocaleDateString() : '-'} + {fraction.import_tax_rate ?? '-'} + {fraction.export_tax_rate ?? '-'} + +
+ + +
+
+
+ {/each} + {/if} + {#if loading} + + +
+ +
+
+
+ {/if} +
+
+
+
+
+
+
- -
+
Mostrando {fractions.length} de {totalItems} registros
import { Input } from '$lib/components/ui/input'; import { Button } from '$lib/components/ui/button'; - import { Label } from '$lib/components/ui/label'; + import * as Card from '$lib/components/ui/card'; import { Table, TableBody, @@ -17,7 +17,7 @@ type TariffFraction } from '$lib/api/dashboard/a76/general_catalogs/tariff-fractions'; import { companyStore } from '$lib/stores/company.svelte'; - import { onMount, untrack } from 'svelte'; + import { untrack } from 'svelte'; import * as AlertDialog from '$lib/components/ui/alert-dialog'; import TariffFractionFormDialog from './TariffFractionFormDialog.svelte'; import { toast } from 'svelte-sonner'; @@ -43,6 +43,7 @@ let searchTimeout: ReturnType; let observer: IntersectionObserver; let sentinel: HTMLDivElement; + let scrollContainer: HTMLDivElement; // Infinite scroll state let hasMore = $state(true); @@ -121,7 +122,7 @@ handlePageChange(currentPage + 1); } }, - { rootMargin: '100px' } + { root: scrollContainer || null, rootMargin: '100px' } ); if (sentinel) observer.observe(sentinel); @@ -180,108 +181,118 @@ }); -
+
-

{title}

+

{title}

{#if !readOnly} - {/if}
-
-
- - -
-
- -
- - - - Clave - Fracción - Descripción - {#if catalog === 'mex'} - NICO - U.M.T - {:else} - Unidad - {/if} - Adv. Impo - Adv. Expo - {#if !readOnly} - Acciones - {/if} - - - - {#if fractions.length === 0 && !isLoading} - - - No se encontraron resultados - - - {:else} - {#each fractions as fraction} + + +
+ Listado de Fracciones +
+
+ + +
+
+
+
+ +
+
+
+ - {fraction.um_code || fraction.code} - {fraction.fraction} - - {fraction.description} - + Clave + Fracción + Descripción {#if catalog === 'mex'} - {fraction.nico || '-'} - {fraction.umt || '-'} + NICO + U.M.T {:else} - {fraction.umt || '-'} + Unidad {/if} - {fraction.adv_impo || '-'} - {fraction.adv_expo || '-'} + Adv. Impo + Adv. Expo {#if !readOnly} - -
- - -
-
+ Acciones {/if}
- {/each} - {/if} - {#if isLoading} - - -
- -
-
-
- {/if} - -
-
+ + + {#if fractions.length === 0 && !isLoading} + + + No se encontraron resultados + + + {:else} + {#each fractions as fraction} + + {fraction.um_code || fraction.code} + {fraction.fraction} + + {fraction.description} + + {#if catalog === 'mex'} + {fraction.nico || '-'} + {fraction.umt || '-'} + {:else} + {fraction.umt || '-'} + {/if} + {fraction.adv_impo || '-'} + {fraction.adv_expo || '-'} + {#if !readOnly} + +
+ + +
+
+ {/if} +
+ {/each} + {/if} + {#if isLoading} + + +
+ +
+
+
+ {/if} +
+ +
+
+
+ + - -
+
Mostrando {fractions.length} de {totalFractions} registros
diff --git a/frontend/src/lib/components/dashboard/goods/parts/data-table.svelte b/frontend/src/lib/components/dashboard/goods/parts/data-table.svelte index 2154fe75..6c3212bb 100644 --- a/frontend/src/lib/components/dashboard/goods/parts/data-table.svelte +++ b/frontend/src/lib/components/dashboard/goods/parts/data-table.svelte @@ -91,7 +91,10 @@
-
+
{#each table.getHeaderGroups() as headerGroup (headerGroup.id)} diff --git a/frontend/src/lib/components/dashboard/invoices/data-table.svelte b/frontend/src/lib/components/dashboard/invoices/data-table.svelte index 870a2c38..3fc036ce 100644 --- a/frontend/src/lib/components/dashboard/invoices/data-table.svelte +++ b/frontend/src/lib/components/dashboard/invoices/data-table.svelte @@ -99,9 +99,13 @@
-
- - +
+
+ + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} {@const headerList = headerGroup.headers} {@const lastHeaderColId = headerList[headerList.length - 1]?.column.id} @@ -111,9 +115,9 @@ onRowClick && onRowClick(row.original)} > {#each visibleCells as cell (cell.id)} @@ -202,12 +204,12 @@ {/if} - + +
diff --git a/frontend/src/lib/components/dashboard/pedimentos/data-table.svelte b/frontend/src/lib/components/dashboard/pedimentos/data-table.svelte index f2141ae7..eb51c5d2 100644 --- a/frontend/src/lib/components/dashboard/pedimentos/data-table.svelte +++ b/frontend/src/lib/components/dashboard/pedimentos/data-table.svelte @@ -97,16 +97,25 @@
-
- - +
+
+ + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} {#each headerGroup.headers as header (header.id)} - + {@const colId = header.column.id} + {#if !header.isPlaceholder}
diff --git a/frontend/src/lib/components/dashboard/reference_data/code_pedimento_regimens/columns.ts b/frontend/src/lib/components/dashboard/reference_data/code_pedimento_regimens/columns.ts index 41ae7ce2..065745f5 100644 --- a/frontend/src/lib/components/dashboard/reference_data/code_pedimento_regimens/columns.ts +++ b/frontend/src/lib/components/dashboard/reference_data/code_pedimento_regimens/columns.ts @@ -12,19 +12,6 @@ export type CodePedimentoRegimen = { export function createColumns(onSuccess?: () => void): ColumnDef[] { return [ - { - accessorKey: "id", - header: "ID", - cell: ({ row }) => { - const idSnippet = createRawSnippet<[{ id: number }]>((getId) => { - const { id } = getId(); - return { - render: () => `
${id}
` - }; - }); - return renderSnippet(idSnippet, { id: row.original.id }); - } - }, { accessorKey: "pedimento_code", header: "Código Pedimento", diff --git a/frontend/src/lib/components/dashboard/reference_data/code_pedimento_regimens/data-table-actions.svelte b/frontend/src/lib/components/dashboard/reference_data/code_pedimento_regimens/data-table-actions.svelte index 18c91f2d..faa561f9 100644 --- a/frontend/src/lib/components/dashboard/reference_data/code_pedimento_regimens/data-table-actions.svelte +++ b/frontend/src/lib/components/dashboard/reference_data/code_pedimento_regimens/data-table-actions.svelte @@ -3,9 +3,7 @@ import { Button } from "$lib/components/ui/button/index.js"; import * as DropdownMenu from "$lib/components/ui/dropdown-menu/index.js"; import type { CodePedimentoRegimen } from "./columns.js"; - import CreateEditDialog from "./create-edit-dialog.svelte"; import DetailsDialog from "./details-dialog.svelte"; - import DeleteDialog from "./delete-dialog.svelte"; let { item, @@ -16,8 +14,6 @@ } = $props(); let showDetailsDialog = $state(false); - let showEditDialog = $state(false); - let showDeleteDialog = $state(false); function handleCopyId() { navigator.clipboard.writeText(item.id.toString()); @@ -26,14 +22,6 @@ function handleViewDetails() { showDetailsDialog = true; } - - function handleEdit() { - showEditDialog = true; - } - - function handleDelete() { - showDeleteDialog = true; - } @@ -54,13 +42,8 @@ Ver detalles - Editar - - Eliminar - - diff --git a/frontend/src/lib/components/dashboard/reference_data/code_pedimento_regimens/data-table.svelte b/frontend/src/lib/components/dashboard/reference_data/code_pedimento_regimens/data-table.svelte index 4c448e3d..1e44175d 100644 --- a/frontend/src/lib/components/dashboard/reference_data/code_pedimento_regimens/data-table.svelte +++ b/frontend/src/lib/components/dashboard/reference_data/code_pedimento_regimens/data-table.svelte @@ -59,65 +59,67 @@ }); -
-
- - +
+
+ + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} - + {/each} - + {/each} - - + + {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} - + {/each} - + {:else} - - + + + {/each} - + {#if hasMore} - - -
+
+ + {/if} - - + +
{#if !header.isPlaceholder} {/if} - +
- +
No hay resultados. - - +
+
{#if loading} -
-
- Cargando más... +
+
+ Cargando más registros...
{:else} -
- Desplázate para cargar más +
+ + Desplázate para cargar más +
{/if}
- - +
diff --git a/frontend/src/lib/components/dashboard/reference_data/containers/data-table-actions.svelte b/frontend/src/lib/components/dashboard/reference_data/containers/data-table-actions.svelte index 07f22b3b..9689ba27 100644 --- a/frontend/src/lib/components/dashboard/reference_data/containers/data-table-actions.svelte +++ b/frontend/src/lib/components/dashboard/reference_data/containers/data-table-actions.svelte @@ -3,9 +3,7 @@ import { Button } from "$lib/components/ui/button/index.js"; import * as DropdownMenu from "$lib/components/ui/dropdown-menu/index.js"; import type { Container } from "./columns.js"; - import CreateEditDialog from "./create-edit-dialog.svelte"; import DetailsDialog from "./details-dialog.svelte"; - import DeleteDialog from "./delete-dialog.svelte"; let { item, @@ -16,8 +14,6 @@ } = $props(); let showDetailsDialog = $state(false); - let showEditDialog = $state(false); - let showDeleteDialog = $state(false); function handleCopyId() { navigator.clipboard.writeText(item.key.toString()); @@ -26,14 +22,6 @@ function handleViewDetails() { showDetailsDialog = true; } - - function handleEdit() { - showEditDialog = true; - } - - function handleDelete() { - showDeleteDialog = true; - } @@ -54,13 +42,8 @@ Ver detalles - Editar - - Eliminar - - diff --git a/frontend/src/lib/components/dashboard/reference_data/containers/data-table.svelte b/frontend/src/lib/components/dashboard/reference_data/containers/data-table.svelte index 4c448e3d..1e44175d 100644 --- a/frontend/src/lib/components/dashboard/reference_data/containers/data-table.svelte +++ b/frontend/src/lib/components/dashboard/reference_data/containers/data-table.svelte @@ -59,65 +59,67 @@ }); -
-
- - +
+
+ + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} - + {/each} - + {/each} - - + + {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} - + {/each} - + {:else} - - + + + {/each} - + {#if hasMore} - - -
+
+ + {/if} - - + +
{#if !header.isPlaceholder} {/if} - +
- +
No hay resultados. - - +
+
{#if loading} -
-
- Cargando más... +
+
+ Cargando más registros...
{:else} -
- Desplázate para cargar más +
+ + Desplázate para cargar más +
{/if}
- - +
diff --git a/frontend/src/lib/components/dashboard/reference_data/countries/data-table-actions.svelte b/frontend/src/lib/components/dashboard/reference_data/countries/data-table-actions.svelte index cd8ee7db..fce57c19 100644 --- a/frontend/src/lib/components/dashboard/reference_data/countries/data-table-actions.svelte +++ b/frontend/src/lib/components/dashboard/reference_data/countries/data-table-actions.svelte @@ -3,9 +3,7 @@ import { Button } from "$lib/components/ui/button/index.js"; import * as DropdownMenu from "$lib/components/ui/dropdown-menu/index.js"; import type { Country } from "./columns.js"; - import CreateEditDialog from "./create-edit-dialog.svelte"; import DetailsDialog from "./details-dialog.svelte"; - import DeleteDialog from "./delete-dialog.svelte"; let { item, @@ -16,8 +14,6 @@ } = $props(); let showDetailsDialog = $state(false); - let showEditDialog = $state(false); - let showDeleteDialog = $state(false); function handleCopyId() { navigator.clipboard.writeText(item.m3_key.toString()); @@ -26,14 +22,6 @@ function handleViewDetails() { showDetailsDialog = true; } - - function handleEdit() { - showEditDialog = true; - } - - function handleDelete() { - showDeleteDialog = true; - } @@ -54,13 +42,8 @@ Ver detalles - Editar - - Eliminar - - diff --git a/frontend/src/lib/components/dashboard/reference_data/countries/data-table.svelte b/frontend/src/lib/components/dashboard/reference_data/countries/data-table.svelte index 4c448e3d..1e44175d 100644 --- a/frontend/src/lib/components/dashboard/reference_data/countries/data-table.svelte +++ b/frontend/src/lib/components/dashboard/reference_data/countries/data-table.svelte @@ -59,65 +59,67 @@ }); -
-
- - +
+
+ + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} - + {/each} - + {/each} - - + + {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} - + {/each} - + {:else} - - + + + {/each} - + {#if hasMore} - - -
+
+ + {/if} - - + +
{#if !header.isPlaceholder} {/if} - +
- +
No hay resultados. - - +
+
{#if loading} -
-
- Cargando más... +
+
+ Cargando más registros...
{:else} -
- Desplázate para cargar más +
+ + Desplázate para cargar más +
{/if}
- - +
diff --git a/frontend/src/lib/components/dashboard/reference_data/currency_types/data-table-actions.svelte b/frontend/src/lib/components/dashboard/reference_data/currency_types/data-table-actions.svelte index 63dd58c3..69d90ade 100644 --- a/frontend/src/lib/components/dashboard/reference_data/currency_types/data-table-actions.svelte +++ b/frontend/src/lib/components/dashboard/reference_data/currency_types/data-table-actions.svelte @@ -3,9 +3,7 @@ import { Button } from "$lib/components/ui/button/index.js"; import * as DropdownMenu from "$lib/components/ui/dropdown-menu/index.js"; import type { CurrencyType } from "./columns.js"; - import CreateEditDialog from "./create-edit-dialog.svelte"; import DetailsDialog from "./details-dialog.svelte"; - import DeleteDialog from "./delete-dialog.svelte"; let { item, @@ -16,8 +14,6 @@ } = $props(); let showDetailsDialog = $state(false); - let showEditDialog = $state(false); - let showDeleteDialog = $state(false); function handleCopyId() { navigator.clipboard.writeText(item.code.toString()); @@ -26,14 +22,6 @@ function handleViewDetails() { showDetailsDialog = true; } - - function handleEdit() { - showEditDialog = true; - } - - function handleDelete() { - showDeleteDialog = true; - } @@ -54,13 +42,8 @@ Ver detalles - Editar - - Eliminar - - diff --git a/frontend/src/lib/components/dashboard/reference_data/currency_types/data-table.svelte b/frontend/src/lib/components/dashboard/reference_data/currency_types/data-table.svelte index 4c448e3d..1e44175d 100644 --- a/frontend/src/lib/components/dashboard/reference_data/currency_types/data-table.svelte +++ b/frontend/src/lib/components/dashboard/reference_data/currency_types/data-table.svelte @@ -59,65 +59,67 @@ }); -
-
- - +
+
+ + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} - + {/each} - + {/each} - - + + {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} - + {/each} - + {:else} - - + + + {/each} - + {#if hasMore} - - -
+
+ + {/if} - - + +
{#if !header.isPlaceholder} {/if} - +
- +
No hay resultados. - - +
+
{#if loading} -
-
- Cargando más... +
+
+ Cargando más registros...
{:else} -
- Desplázate para cargar más +
+ + Desplázate para cargar más +
{/if}
- - +
diff --git a/frontend/src/lib/components/dashboard/reference_data/customs_sections/data-table-actions.svelte b/frontend/src/lib/components/dashboard/reference_data/customs_sections/data-table-actions.svelte index 3ffd2ee3..8dcf4a58 100644 --- a/frontend/src/lib/components/dashboard/reference_data/customs_sections/data-table-actions.svelte +++ b/frontend/src/lib/components/dashboard/reference_data/customs_sections/data-table-actions.svelte @@ -3,9 +3,7 @@ import { Button } from "$lib/components/ui/button/index.js"; import * as DropdownMenu from "$lib/components/ui/dropdown-menu/index.js"; import type { CustomsSection } from "./columns.js"; - import CreateEditDialog from "./create-edit-dialog.svelte"; import DetailsDialog from "./details-dialog.svelte"; - import DeleteDialog from "./delete-dialog.svelte"; let { item, @@ -16,8 +14,6 @@ } = $props(); let showDetailsDialog = $state(false); - let showEditDialog = $state(false); - let showDeleteDialog = $state(false); function handleCopyId() { navigator.clipboard.writeText(item.customs_code.toString()); @@ -26,14 +22,6 @@ function handleViewDetails() { showDetailsDialog = true; } - - function handleEdit() { - showEditDialog = true; - } - - function handleDelete() { - showDeleteDialog = true; - } @@ -54,13 +42,8 @@ Ver detalles - Editar - - Eliminar - - diff --git a/frontend/src/lib/components/dashboard/reference_data/customs_sections/data-table.svelte b/frontend/src/lib/components/dashboard/reference_data/customs_sections/data-table.svelte index 4c448e3d..0e0ae059 100644 --- a/frontend/src/lib/components/dashboard/reference_data/customs_sections/data-table.svelte +++ b/frontend/src/lib/components/dashboard/reference_data/customs_sections/data-table.svelte @@ -59,65 +59,67 @@ }); -
-
- - +
+
+ + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} - + {/each} - + {/each} - - + + {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} - + {/each} - + {:else} - - + + + {/each} - + {#if hasMore} - - -
+
+ + {/if} - - + +
{#if !header.isPlaceholder} {/if} - +
- +
No hay resultados. - - +
+
{#if loading} -
-
- Cargando más... +
+
+ Cargando más registros...
{:else} -
- Desplázate para cargar más +
+ + Desplázate para cargar más +
{/if}
- - +
diff --git a/frontend/src/lib/components/dashboard/reference_data/customs_warehouses/data-table-actions.svelte b/frontend/src/lib/components/dashboard/reference_data/customs_warehouses/data-table-actions.svelte index d204b9c0..3fd6f9fe 100644 --- a/frontend/src/lib/components/dashboard/reference_data/customs_warehouses/data-table-actions.svelte +++ b/frontend/src/lib/components/dashboard/reference_data/customs_warehouses/data-table-actions.svelte @@ -3,9 +3,7 @@ import { Button } from "$lib/components/ui/button/index.js"; import * as DropdownMenu from "$lib/components/ui/dropdown-menu/index.js"; import type { CustomsWarehouse } from "./columns.js"; - import CreateEditDialog from "./create-edit-dialog.svelte"; import DetailsDialog from "./details-dialog.svelte"; - import DeleteDialog from "./delete-dialog.svelte"; let { item, @@ -16,8 +14,6 @@ } = $props(); let showDetailsDialog = $state(false); - let showEditDialog = $state(false); - let showDeleteDialog = $state(false); function handleCopyId() { navigator.clipboard.writeText(`${item.key}|${item.customs}`); @@ -26,14 +22,6 @@ function handleViewDetails() { showDetailsDialog = true; } - - function handleEdit() { - showEditDialog = true; - } - - function handleDelete() { - showDeleteDialog = true; - } @@ -54,13 +42,8 @@ Ver detalles - Editar - - Eliminar - - diff --git a/frontend/src/lib/components/dashboard/reference_data/customs_warehouses/data-table.svelte b/frontend/src/lib/components/dashboard/reference_data/customs_warehouses/data-table.svelte index 4c448e3d..1e44175d 100644 --- a/frontend/src/lib/components/dashboard/reference_data/customs_warehouses/data-table.svelte +++ b/frontend/src/lib/components/dashboard/reference_data/customs_warehouses/data-table.svelte @@ -59,65 +59,67 @@ }); -
-
- - +
+
+ + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} - + {/each} - + {/each} - - + + {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} - + {/each} - + {:else} - - + + + {/each} - + {#if hasMore} - - -
+
+ + {/if} - - + +
{#if !header.isPlaceholder} {/if} - +
- +
No hay resultados. - - +
+
{#if loading} -
-
- Cargando más... +
+
+ Cargando más registros...
{:else} -
- Desplázate para cargar más +
+ + Desplázate para cargar más +
{/if}
- - +
diff --git a/frontend/src/lib/components/dashboard/reference_data/incoterms/data-table-actions.svelte b/frontend/src/lib/components/dashboard/reference_data/incoterms/data-table-actions.svelte index ce9a6cbe..9ea03340 100644 --- a/frontend/src/lib/components/dashboard/reference_data/incoterms/data-table-actions.svelte +++ b/frontend/src/lib/components/dashboard/reference_data/incoterms/data-table-actions.svelte @@ -3,9 +3,7 @@ import { Button } from "$lib/components/ui/button/index.js"; import * as DropdownMenu from "$lib/components/ui/dropdown-menu/index.js"; import type { Incoterm } from "./columns.js"; - import CreateEditDialog from "./create-edit-dialog.svelte"; import DetailsDialog from "./details-dialog.svelte"; - import DeleteDialog from "./delete-dialog.svelte"; let { item, @@ -16,8 +14,6 @@ } = $props(); let showDetailsDialog = $state(false); - let showEditDialog = $state(false); - let showDeleteDialog = $state(false); function handleCopyId() { navigator.clipboard.writeText(item.code.toString()); @@ -26,14 +22,6 @@ function handleViewDetails() { showDetailsDialog = true; } - - function handleEdit() { - showEditDialog = true; - } - - function handleDelete() { - showDeleteDialog = true; - } @@ -54,13 +42,8 @@ Ver detalles - Editar - - Eliminar - - diff --git a/frontend/src/lib/components/dashboard/reference_data/incoterms/data-table.svelte b/frontend/src/lib/components/dashboard/reference_data/incoterms/data-table.svelte index 3d5b2a66..c144ded1 100644 --- a/frontend/src/lib/components/dashboard/reference_data/incoterms/data-table.svelte +++ b/frontend/src/lib/components/dashboard/reference_data/incoterms/data-table.svelte @@ -3,104 +3,114 @@ type ColumnDef, getCoreRowModel } from "@tanstack/table-core"; + import { onMount } from "svelte"; import { createSvelteTable, FlexRender } from "$lib/components/ui/data-table/index.js"; import * as Table from "$lib/components/ui/table/index.js"; import { Button } from "$lib/components/ui/button"; - import { goto } from "$app/navigation"; - import { page } from "$app/stores"; type DataTableProps = { columns: ColumnDef[]; data: TData[]; - pageCount: number; - totalItems: number; + loading: boolean; + hasMore: boolean; + loadMore: () => void; }; let { data, columns, - pageCount, - totalItems + loading, + hasMore, + loadMore }: DataTableProps = $props(); const table = createSvelteTable({ get data() { return data; }, get columns() { return columns; }, - getCoreRowModel: getCoreRowModel(), - manualPagination: true, - get pageCount() { return pageCount; }, + getCoreRowModel: getCoreRowModel() }); - function handlePageChange(newPage: number) { - const url = new URL($page.url); - url.searchParams.set('page', newPage.toString()); - goto(url, { keepFocus: true, noScroll: true }); - } + let scrollContainer = $state(); + let loadingTrigger = $state(); - const currentPage = $derived(Number($page.url.searchParams.get('page') || 1)); + onMount(() => { + const observer = new IntersectionObserver( + (entries) => { + const [entry] = entries; + if (entry.isIntersecting && hasMore && !loading) { + loadMore(); + } + }, + { root: scrollContainer, threshold: 0.1 } + ); + + if (loadingTrigger) observer.observe(loadingTrigger); + + return () => observer.disconnect(); + }); -
- - - {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - - {#each headerGroup.headers as header (header.id)} - - {#if !header.isPlaceholder} +
+
+ + + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} + + {#each headerGroup.headers as header (header.id)} + + {/each} + + {/each} + + + {#each table.getRowModel().rows as row (row.id)} + + {#each row.getVisibleCells() as cell (cell.id)} + + {/each} + + {:else} + + + + {/each} + + + {#if hasMore} + + + + {/if} + +
+ {#if !header.isPlaceholder} + + {/if} +
- {/if} - - {/each} - - {/each} - - - {#each table.getRowModel().rows as row (row.id)} - - {#each row.getVisibleCells() as cell (cell.id)} - - - - {/each} - - {:else} - - - No hay resultados. - - - {/each} - - - - -
-
- Total: {totalItems} registros -
-
- - +
+ No hay resultados. +
+
+ {#if loading} +
+
+ Cargando más registros... +
+ {:else} +
+ + Desplázate para cargar más + +
+ {/if} +
+
diff --git a/frontend/src/lib/components/dashboard/reference_data/invoice_types/data-table-actions.svelte b/frontend/src/lib/components/dashboard/reference_data/invoice_types/data-table-actions.svelte index be22d1e5..4fab7cbe 100644 --- a/frontend/src/lib/components/dashboard/reference_data/invoice_types/data-table-actions.svelte +++ b/frontend/src/lib/components/dashboard/reference_data/invoice_types/data-table-actions.svelte @@ -3,9 +3,7 @@ import { Button } from "$lib/components/ui/button/index.js"; import * as DropdownMenu from "$lib/components/ui/dropdown-menu/index.js"; import type { InvoiceType } from "./columns.js"; - import CreateEditDialog from "./create-edit-dialog.svelte"; import DetailsDialog from "./details-dialog.svelte"; - import DeleteDialog from "./delete-dialog.svelte"; let { item, @@ -16,8 +14,6 @@ } = $props(); let showDetailsDialog = $state(false); - let showEditDialog = $state(false); - let showDeleteDialog = $state(false); function handleCopyId() { navigator.clipboard.writeText(item.key.toString()); @@ -26,14 +22,6 @@ function handleViewDetails() { showDetailsDialog = true; } - - function handleEdit() { - showEditDialog = true; - } - - function handleDelete() { - showDeleteDialog = true; - } @@ -54,13 +42,8 @@ Ver detalles - Editar - - Eliminar - - diff --git a/frontend/src/lib/components/dashboard/reference_data/invoice_types/data-table.svelte b/frontend/src/lib/components/dashboard/reference_data/invoice_types/data-table.svelte index 4c448e3d..1e44175d 100644 --- a/frontend/src/lib/components/dashboard/reference_data/invoice_types/data-table.svelte +++ b/frontend/src/lib/components/dashboard/reference_data/invoice_types/data-table.svelte @@ -59,65 +59,67 @@ }); -
-
- - +
+
+ + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} - + {/each} - + {/each} - - + + {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} - + {/each} - + {:else} - - + + + {/each} - + {#if hasMore} - - -
+
+ + {/if} - - + +
{#if !header.isPlaceholder} {/if} - +
- +
No hay resultados. - - +
+
{#if loading} -
-
- Cargando más... +
+
+ Cargando más registros...
{:else} -
- Desplázate para cargar más +
+ + Desplázate para cargar más +
{/if}
- - +
diff --git a/frontend/src/lib/components/dashboard/reference_data/material_types/data-table-actions.svelte b/frontend/src/lib/components/dashboard/reference_data/material_types/data-table-actions.svelte index 8b64e467..d1f070f7 100644 --- a/frontend/src/lib/components/dashboard/reference_data/material_types/data-table-actions.svelte +++ b/frontend/src/lib/components/dashboard/reference_data/material_types/data-table-actions.svelte @@ -3,9 +3,7 @@ import { Button } from "$lib/components/ui/button/index.js"; import * as DropdownMenu from "$lib/components/ui/dropdown-menu/index.js"; import type { MaterialType } from "./columns.js"; - import CreateEditDialog from "./create-edit-dialog.svelte"; import DetailsDialog from "./details-dialog.svelte"; - import DeleteDialog from "./delete-dialog.svelte"; let { item, @@ -16,8 +14,6 @@ } = $props(); let showDetailsDialog = $state(false); - let showEditDialog = $state(false); - let showDeleteDialog = $state(false); function handleCopyId() { navigator.clipboard.writeText(item.key.toString()); @@ -26,14 +22,6 @@ function handleViewDetails() { showDetailsDialog = true; } - - function handleEdit() { - showEditDialog = true; - } - - function handleDelete() { - showDeleteDialog = true; - } @@ -54,13 +42,8 @@ Ver detalles - Editar - - Eliminar - - diff --git a/frontend/src/lib/components/dashboard/reference_data/material_types/data-table.svelte b/frontend/src/lib/components/dashboard/reference_data/material_types/data-table.svelte index 4c448e3d..1e44175d 100644 --- a/frontend/src/lib/components/dashboard/reference_data/material_types/data-table.svelte +++ b/frontend/src/lib/components/dashboard/reference_data/material_types/data-table.svelte @@ -59,65 +59,67 @@ }); -
-
- - +
+
+ + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} - + {/each} - + {/each} - - + + {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} - + {/each} - + {:else} - - + + + {/each} - + {#if hasMore} - - -
+
+ + {/if} - - + +
{#if !header.isPlaceholder} {/if} - +
- +
No hay resultados. - - +
+
{#if loading} -
-
- Cargando más... +
+
+ Cargando más registros...
{:else} -
- Desplázate para cargar más +
+ + Desplázate para cargar más +
{/if}
- - +
diff --git a/frontend/src/lib/components/dashboard/reference_data/payment_methods/data-table-actions.svelte b/frontend/src/lib/components/dashboard/reference_data/payment_methods/data-table-actions.svelte index faea7dde..f36a0c6a 100644 --- a/frontend/src/lib/components/dashboard/reference_data/payment_methods/data-table-actions.svelte +++ b/frontend/src/lib/components/dashboard/reference_data/payment_methods/data-table-actions.svelte @@ -3,9 +3,7 @@ import { Button } from "$lib/components/ui/button/index.js"; import * as DropdownMenu from "$lib/components/ui/dropdown-menu/index.js"; import type { PaymentMethod } from "./columns.js"; - import CreateEditDialog from "./create-edit-dialog.svelte"; import DetailsDialog from "./details-dialog.svelte"; - import DeleteDialog from "./delete-dialog.svelte"; let { item, @@ -16,8 +14,6 @@ } = $props(); let showDetailsDialog = $state(false); - let showEditDialog = $state(false); - let showDeleteDialog = $state(false); function handleCopyId() { navigator.clipboard.writeText(item.key.toString()); @@ -26,14 +22,6 @@ function handleViewDetails() { showDetailsDialog = true; } - - function handleEdit() { - showEditDialog = true; - } - - function handleDelete() { - showDeleteDialog = true; - } @@ -54,13 +42,8 @@ Ver detalles - Editar - - Eliminar - - diff --git a/frontend/src/lib/components/dashboard/reference_data/payment_methods/data-table.svelte b/frontend/src/lib/components/dashboard/reference_data/payment_methods/data-table.svelte index 4c448e3d..1e44175d 100644 --- a/frontend/src/lib/components/dashboard/reference_data/payment_methods/data-table.svelte +++ b/frontend/src/lib/components/dashboard/reference_data/payment_methods/data-table.svelte @@ -59,65 +59,67 @@ }); -
-
- - +
+
+ + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} - + {/each} - + {/each} - - + + {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} - + {/each} - + {:else} - - + + + {/each} - + {#if hasMore} - - -
+
+ + {/if} - - + +
{#if !header.isPlaceholder} {/if} - +
- +
No hay resultados. - - +
+
{#if loading} -
-
- Cargando más... +
+
+ Cargando más registros...
{:else} -
- Desplázate para cargar más +
+ + Desplázate para cargar más +
{/if}
- - +
diff --git a/frontend/src/lib/components/dashboard/reference_data/pedimento_codes/data-table-actions.svelte b/frontend/src/lib/components/dashboard/reference_data/pedimento_codes/data-table-actions.svelte index 21b69276..5bfd8144 100644 --- a/frontend/src/lib/components/dashboard/reference_data/pedimento_codes/data-table-actions.svelte +++ b/frontend/src/lib/components/dashboard/reference_data/pedimento_codes/data-table-actions.svelte @@ -3,9 +3,7 @@ import { Button } from "$lib/components/ui/button/index.js"; import * as DropdownMenu from "$lib/components/ui/dropdown-menu/index.js"; import type { PedimentoCode } from "./columns.js"; - import CreateEditDialog from "./create-edit-dialog.svelte"; import DetailsDialog from "./details-dialog.svelte"; - import DeleteDialog from "./delete-dialog.svelte"; let { item, @@ -16,8 +14,6 @@ } = $props(); let showDetailsDialog = $state(false); - let showEditDialog = $state(false); - let showDeleteDialog = $state(false); function handleCopyId() { navigator.clipboard.writeText(item.code.toString()); @@ -26,14 +22,6 @@ function handleViewDetails() { showDetailsDialog = true; } - - function handleEdit() { - showEditDialog = true; - } - - function handleDelete() { - showDeleteDialog = true; - } @@ -54,13 +42,8 @@ Ver detalles - Editar - - Eliminar - - diff --git a/frontend/src/lib/components/dashboard/reference_data/pedimento_codes/data-table.svelte b/frontend/src/lib/components/dashboard/reference_data/pedimento_codes/data-table.svelte index 4c448e3d..1e44175d 100644 --- a/frontend/src/lib/components/dashboard/reference_data/pedimento_codes/data-table.svelte +++ b/frontend/src/lib/components/dashboard/reference_data/pedimento_codes/data-table.svelte @@ -59,65 +59,67 @@ }); -
-
- - +
+
+ + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} - + {/each} - + {/each} - - + + {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} - + {/each} - + {:else} - - + + + {/each} - + {#if hasMore} - - -
+
+ + {/if} - - + +
{#if !header.isPlaceholder} {/if} - +
- +
No hay resultados. - - +
+
{#if loading} -
-
- Cargando más... +
+
+ Cargando más registros...
{:else} -
- Desplázate para cargar más +
+ + Desplázate para cargar más +
{/if}
- - +
diff --git a/frontend/src/lib/components/dashboard/reference_data/pedimento_regimens/data-table-actions.svelte b/frontend/src/lib/components/dashboard/reference_data/pedimento_regimens/data-table-actions.svelte index 42b87981..dc4d01ad 100644 --- a/frontend/src/lib/components/dashboard/reference_data/pedimento_regimens/data-table-actions.svelte +++ b/frontend/src/lib/components/dashboard/reference_data/pedimento_regimens/data-table-actions.svelte @@ -3,9 +3,7 @@ import { Button } from "$lib/components/ui/button/index.js"; import * as DropdownMenu from "$lib/components/ui/dropdown-menu/index.js"; import type { PedimentoRegimen } from "./columns.js"; - import CreateEditDialog from "./create-edit-dialog.svelte"; import DetailsDialog from "./details-dialog.svelte"; - import DeleteDialog from "./delete-dialog.svelte"; let { item, @@ -16,8 +14,6 @@ } = $props(); let showDetailsDialog = $state(false); - let showEditDialog = $state(false); - let showDeleteDialog = $state(false); function handleCopyId() { navigator.clipboard.writeText(item.code.toString()); @@ -26,14 +22,6 @@ function handleViewDetails() { showDetailsDialog = true; } - - function handleEdit() { - showEditDialog = true; - } - - function handleDelete() { - showDeleteDialog = true; - } @@ -54,13 +42,8 @@ Ver detalles - Editar - - Eliminar - - diff --git a/frontend/src/lib/components/dashboard/reference_data/pedimento_regimens/data-table.svelte b/frontend/src/lib/components/dashboard/reference_data/pedimento_regimens/data-table.svelte index 4c448e3d..1e44175d 100644 --- a/frontend/src/lib/components/dashboard/reference_data/pedimento_regimens/data-table.svelte +++ b/frontend/src/lib/components/dashboard/reference_data/pedimento_regimens/data-table.svelte @@ -59,65 +59,67 @@ }); -
-
- - +
+
+ + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} - + {/each} - + {/each} - - + + {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} - + {/each} - + {:else} - - + + + {/each} - + {#if hasMore} - - -
+
+ + {/if} - - + +
{#if !header.isPlaceholder} {/if} - +
- +
No hay resultados. - - +
+
{#if loading} -
-
- Cargando más... +
+
+ Cargando más registros...
{:else} -
- Desplázate para cargar más +
+ + Desplázate para cargar más +
{/if}
- - +
diff --git a/frontend/src/lib/components/dashboard/reference_data/sectors/create-edit-dialog.svelte b/frontend/src/lib/components/dashboard/reference_data/sectors/create-edit-dialog.svelte index 1da14dbf..460e1202 100644 --- a/frontend/src/lib/components/dashboard/reference_data/sectors/create-edit-dialog.svelte +++ b/frontend/src/lib/components/dashboard/reference_data/sectors/create-edit-dialog.svelte @@ -25,6 +25,19 @@ let loading = $state(false); let error = $state(null); + function getActiveCompanyId(): number | null { + const fromStore = companyStore.activeCompany?.id; + if (fromStore) return fromStore; + if (typeof document === 'undefined') return null; + const cookie = document.cookie + .split('; ') + .find((row) => row.startsWith('active_company_id=')) + ?.split('=')[1]; + if (!cookie) return null; + const parsed = Number(cookie); + return Number.isFinite(parsed) ? parsed : null; + } + // Actualizar formData cuando item cambia $effect(() => { if (item) { @@ -49,7 +62,7 @@ loading = true; error = null; - const companyId = companyStore.activeCompany?.id; + const companyId = getActiveCompanyId(); if (!companyId) { error = 'No hay empresa activa seleccionada'; loading = false; diff --git a/frontend/src/lib/components/dashboard/reference_data/sectors/data-table.svelte b/frontend/src/lib/components/dashboard/reference_data/sectors/data-table.svelte index 4c448e3d..1e44175d 100644 --- a/frontend/src/lib/components/dashboard/reference_data/sectors/data-table.svelte +++ b/frontend/src/lib/components/dashboard/reference_data/sectors/data-table.svelte @@ -59,65 +59,67 @@ }); -
-
- - +
+
+ + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} - + {/each} - + {/each} - - + + {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} - + {/each} - + {:else} - - + + + {/each} - + {#if hasMore} - - -
+
+ + {/if} - - + +
{#if !header.isPlaceholder} {/if} - +
- +
No hay resultados. - - +
+
{#if loading} -
-
- Cargando más... +
+
+ Cargando más registros...
{:else} -
- Desplázate para cargar más +
+ + Desplázate para cargar más +
{/if}
- - +
diff --git a/frontend/src/lib/components/dashboard/reference_data/sectors/delete-dialog.svelte b/frontend/src/lib/components/dashboard/reference_data/sectors/delete-dialog.svelte index 9e92fb82..920913e9 100644 --- a/frontend/src/lib/components/dashboard/reference_data/sectors/delete-dialog.svelte +++ b/frontend/src/lib/components/dashboard/reference_data/sectors/delete-dialog.svelte @@ -18,10 +18,23 @@ let loading = $state(false); let error = $state(null); + function getActiveCompanyId(): number | null { + const fromStore = companyStore.activeCompany?.id; + if (fromStore) return fromStore; + if (typeof document === 'undefined') return null; + const cookie = document.cookie + .split('; ') + .find((row) => row.startsWith('active_company_id=')) + ?.split('=')[1]; + if (!cookie) return null; + const parsed = Number(cookie); + return Number.isFinite(parsed) ? parsed : null; + } + async function handleDelete() { if (!item) return; - const companyId = companyStore.activeCompany?.id; + const companyId = getActiveCompanyId(); if (!companyId) { error = 'No hay empresa activa seleccionada'; return; diff --git a/frontend/src/lib/components/dashboard/reference_data/states/data-table.svelte b/frontend/src/lib/components/dashboard/reference_data/states/data-table.svelte index 4c448e3d..1e44175d 100644 --- a/frontend/src/lib/components/dashboard/reference_data/states/data-table.svelte +++ b/frontend/src/lib/components/dashboard/reference_data/states/data-table.svelte @@ -59,65 +59,67 @@ }); -
-
- - +
+
+ + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} - + {/each} - + {/each} - - + + {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} - + {/each} - + {:else} - - + + + {/each} - + {#if hasMore} - - -
+
+ + {/if} - - + +
{#if !header.isPlaceholder} {/if} - +
- +
No hay resultados. - - +
+
{#if loading} -
-
- Cargando más... +
+
+ Cargando más registros...
{:else} -
- Desplázate para cargar más +
+ + Desplázate para cargar más +
{/if}
- - +
diff --git a/frontend/src/lib/components/dashboard/reference_data/transport_modes/data-table-actions.svelte b/frontend/src/lib/components/dashboard/reference_data/transport_modes/data-table-actions.svelte index 9159af82..5855ea10 100644 --- a/frontend/src/lib/components/dashboard/reference_data/transport_modes/data-table-actions.svelte +++ b/frontend/src/lib/components/dashboard/reference_data/transport_modes/data-table-actions.svelte @@ -3,9 +3,7 @@ import { Button } from "$lib/components/ui/button/index.js"; import * as DropdownMenu from "$lib/components/ui/dropdown-menu/index.js"; import type { TransportMode } from "./columns.js"; - import CreateEditDialog from "./create-edit-dialog.svelte"; import DetailsDialog from "./details-dialog.svelte"; - import DeleteDialog from "./delete-dialog.svelte"; let { item, @@ -16,8 +14,6 @@ } = $props(); let showDetailsDialog = $state(false); - let showEditDialog = $state(false); - let showDeleteDialog = $state(false); function handleCopyId() { navigator.clipboard.writeText(item.key.toString()); @@ -26,14 +22,6 @@ function handleViewDetails() { showDetailsDialog = true; } - - function handleEdit() { - showEditDialog = true; - } - - function handleDelete() { - showDeleteDialog = true; - } @@ -54,13 +42,8 @@ Ver detalles - Editar - - Eliminar - - diff --git a/frontend/src/lib/components/dashboard/reference_data/transport_modes/data-table.svelte b/frontend/src/lib/components/dashboard/reference_data/transport_modes/data-table.svelte index 4c448e3d..1e44175d 100644 --- a/frontend/src/lib/components/dashboard/reference_data/transport_modes/data-table.svelte +++ b/frontend/src/lib/components/dashboard/reference_data/transport_modes/data-table.svelte @@ -59,65 +59,67 @@ }); -
-
- - +
+
+ + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} - + {/each} - + {/each} - - + + {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} - + {/each} - + {:else} - - + + + {/each} - + {#if hasMore} - - -
+
+ + {/if} - - + +
{#if !header.isPlaceholder} {/if} - +
- +
No hay resultados. - - +
+
{#if loading} -
-
- Cargando más... +
+
+ Cargando más registros...
{:else} -
- Desplázate para cargar más +
+ + Desplázate para cargar más +
{/if}
- - +
diff --git a/frontend/src/lib/components/dashboard/reference_data/transport_types/data-table-actions.svelte b/frontend/src/lib/components/dashboard/reference_data/transport_types/data-table-actions.svelte index 6c4f2e5b..de253afb 100644 --- a/frontend/src/lib/components/dashboard/reference_data/transport_types/data-table-actions.svelte +++ b/frontend/src/lib/components/dashboard/reference_data/transport_types/data-table-actions.svelte @@ -3,9 +3,7 @@ import { Button } from "$lib/components/ui/button/index.js"; import * as DropdownMenu from "$lib/components/ui/dropdown-menu/index.js"; import type { TransportType } from "./columns.js"; - import CreateEditDialog from "./create-edit-dialog.svelte"; import DetailsDialog from "./details-dialog.svelte"; - import DeleteDialog from "./delete-dialog.svelte"; let { item, @@ -16,8 +14,6 @@ } = $props(); let showDetailsDialog = $state(false); - let showEditDialog = $state(false); - let showDeleteDialog = $state(false); function handleCopyId() { navigator.clipboard.writeText(item.transport_code.toString()); @@ -26,14 +22,6 @@ function handleViewDetails() { showDetailsDialog = true; } - - function handleEdit() { - showEditDialog = true; - } - - function handleDelete() { - showDeleteDialog = true; - } @@ -54,13 +42,8 @@ Ver detalles - Editar - - Eliminar - - diff --git a/frontend/src/lib/components/dashboard/reference_data/transport_types/data-table.svelte b/frontend/src/lib/components/dashboard/reference_data/transport_types/data-table.svelte index 4c448e3d..1e44175d 100644 --- a/frontend/src/lib/components/dashboard/reference_data/transport_types/data-table.svelte +++ b/frontend/src/lib/components/dashboard/reference_data/transport_types/data-table.svelte @@ -59,65 +59,67 @@ }); -
-
- - +
+
+ + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} - + {/each} - + {/each} - - + + {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} - + {/each} - + {:else} - - + + + {/each} - + {#if hasMore} - - -
+
+ + {/if} - - + +
{#if !header.isPlaceholder} {/if} - +
- +
No hay resultados. - - +
+
{#if loading} -
-
- Cargando más... +
+
+ Cargando más registros...
{:else} -
- Desplázate para cargar más +
+ + Desplázate para cargar más +
{/if}
- - +
diff --git a/frontend/src/lib/components/dashboard/reference_data/valuation_methods/data-table-actions.svelte b/frontend/src/lib/components/dashboard/reference_data/valuation_methods/data-table-actions.svelte index cf14da9a..f4bf003f 100644 --- a/frontend/src/lib/components/dashboard/reference_data/valuation_methods/data-table-actions.svelte +++ b/frontend/src/lib/components/dashboard/reference_data/valuation_methods/data-table-actions.svelte @@ -3,9 +3,7 @@ import { Button } from "$lib/components/ui/button/index.js"; import * as DropdownMenu from "$lib/components/ui/dropdown-menu/index.js"; import type { ValuationMethod } from "./columns.js"; - import CreateEditDialog from "./create-edit-dialog.svelte"; import DetailsDialog from "./details-dialog.svelte"; - import DeleteDialog from "./delete-dialog.svelte"; let { item, @@ -16,8 +14,6 @@ } = $props(); let showDetailsDialog = $state(false); - let showEditDialog = $state(false); - let showDeleteDialog = $state(false); function handleCopyId() { navigator.clipboard.writeText(item.key.toString()); @@ -26,14 +22,6 @@ function handleViewDetails() { showDetailsDialog = true; } - - function handleEdit() { - showEditDialog = true; - } - - function handleDelete() { - showDeleteDialog = true; - } @@ -54,13 +42,8 @@ Ver detalles - Editar - - Eliminar - - diff --git a/frontend/src/lib/components/dashboard/reference_data/valuation_methods/data-table.svelte b/frontend/src/lib/components/dashboard/reference_data/valuation_methods/data-table.svelte index 4c84570d..17039f91 100644 --- a/frontend/src/lib/components/dashboard/reference_data/valuation_methods/data-table.svelte +++ b/frontend/src/lib/components/dashboard/reference_data/valuation_methods/data-table.svelte @@ -60,65 +60,67 @@ -
-
- - +
+
+ + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} - + {/each} - + {/each} - - + + {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} - + {/each} - + {:else} - - + + + {/each} - + {#if hasMore} - - -
+
+ + {/if} - - + +
{#if !header.isPlaceholder} {/if} - +
- +
No hay resultados. - - +
+
{#if loading} -
-
- Cargando más... +
+
+ Cargando más registros...
{:else} -
- Desplázate para cargar más +
+ + Desplázate para cargar más +
{/if}
- - +
diff --git a/frontend/src/lib/components/dashboard/seal/data-table.svelte b/frontend/src/lib/components/dashboard/seal/data-table.svelte index 207266e0..954785f8 100644 --- a/frontend/src/lib/components/dashboard/seal/data-table.svelte +++ b/frontend/src/lib/components/dashboard/seal/data-table.svelte @@ -18,8 +18,8 @@ let { data, columns, loading = false, hasMore = false, loadMore }: Props = $props(); - let scrollContainer: HTMLDivElement; - let observer: IntersectionObserver; + let scrollContainer = $state(); + let loadingTrigger = $state(); let options = $derived>({ get data() { @@ -34,8 +34,7 @@ onMount(() => { if (!loadMore) return; - // Create intersection observer for infinite scroll - observer = new IntersectionObserver( + const observer = new IntersectionObserver( (entries) => { const [entry] = entries; if (entry.isIntersecting && hasMore && !loading && loadMore) { @@ -48,26 +47,24 @@ } ); - // Observe the last row - const lastRow = scrollContainer?.querySelector('tbody tr:last-child'); - if (lastRow) { - observer.observe(lastRow); + if (loadingTrigger) { + observer.observe(loadingTrigger); } return () => { - observer?.disconnect(); + observer.disconnect(); }; }); -
-
+
+
- + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} {#each headerGroup.headers as header (header.id)} - + {#if !header.isPlaceholder} {#each row.getVisibleCells() as cell (cell.id)} - + {/each} - - {#if loading} + + {#if hasMore} - - Cargando... + +
+ {#if loading} +
+
+ Cargando más registros... +
+ {:else} +
+ + Desplázate para cargar más + +
+ {/if} +
{/if} diff --git a/frontend/src/lib/components/ui/sidebar/sidebar-inset.svelte b/frontend/src/lib/components/ui/sidebar/sidebar-inset.svelte index d862761d..5d9598f5 100644 --- a/frontend/src/lib/components/ui/sidebar/sidebar-inset.svelte +++ b/frontend/src/lib/components/ui/sidebar/sidebar-inset.svelte @@ -14,7 +14,7 @@ bind:this={ref} data-slot="sidebar-inset" class={cn( - "bg-background relative flex w-full flex-1 flex-col", + "bg-background relative flex min-h-0 w-full flex-1 flex-col overflow-hidden", "md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm", className )} diff --git a/frontend/src/lib/components/ui/sidebar/sidebar-provider.svelte b/frontend/src/lib/components/ui/sidebar/sidebar-provider.svelte index 5b0d0aa2..f9f8f9dc 100644 --- a/frontend/src/lib/components/ui/sidebar/sidebar-provider.svelte +++ b/frontend/src/lib/components/ui/sidebar/sidebar-provider.svelte @@ -42,7 +42,7 @@ data-slot="sidebar-wrapper" style="--sidebar-width: {SIDEBAR_WIDTH}; --sidebar-width-icon: {SIDEBAR_WIDTH_ICON}; {style}" class={cn( - "group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full", + "group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex h-svh w-full overflow-hidden", className )} bind:this={ref} diff --git a/frontend/src/lib/config/shortcuts/dashboard/reference_data/common/factory.ts b/frontend/src/lib/config/shortcuts/dashboard/reference_data/common/factory.ts index 562c133e..6a487710 100644 --- a/frontend/src/lib/config/shortcuts/dashboard/reference_data/common/factory.ts +++ b/frontend/src/lib/config/shortcuts/dashboard/reference_data/common/factory.ts @@ -4,19 +4,24 @@ import type { ShortcutDef } from '$lib/stores/shortcut-store'; * Reusable shortcuts for simple reference data catalogs. */ export const obtenerAtajosReferenceDataSimple = (acciones: { - manejarNuevo: () => void; + manejarNuevo?: () => void; manejarActualizar: () => void; }): ShortcutDef[] => { - return [ - { + const atajos: ShortcutDef[] = []; + + if (acciones.manejarNuevo) { + atajos.push({ key: 'Alt+Shift+N', description: 'Nuevo Registro', action: acciones.manejarNuevo - }, - { - key: 'Alt+Shift+R', - description: 'Actualizar Lista', - action: acciones.manejarActualizar - } - ]; + }); + } + + atajos.push({ + key: 'Alt+Shift+R', + description: 'Actualizar Lista', + action: acciones.manejarActualizar + }); + + return atajos; }; diff --git a/frontend/src/routes/dashboard/+layout.svelte b/frontend/src/routes/dashboard/+layout.svelte index 12e28e3f..b9cca54b 100644 --- a/frontend/src/routes/dashboard/+layout.svelte +++ b/frontend/src/routes/dashboard/+layout.svelte @@ -141,7 +141,7 @@ -->
-
+
{#if csvImportBanner} -
+

{m['sidebar.audit_logs_title']()}

diff --git a/frontend/src/routes/dashboard/audit_logs/bitacora-tab.svelte b/frontend/src/routes/dashboard/audit_logs/bitacora-tab.svelte index da1e2bd7..0269e9e3 100644 --- a/frontend/src/routes/dashboard/audit_logs/bitacora-tab.svelte +++ b/frontend/src/routes/dashboard/audit_logs/bitacora-tab.svelte @@ -8,7 +8,6 @@ import * as Card from '$lib/components/ui/card'; import { Button } from '$lib/components/ui/button'; import { Input } from '$lib/components/ui/input'; - import { Label } from '$lib/components/ui/label'; import * as Table from '$lib/components/ui/table'; import { RefreshCw, Search } from 'lucide-svelte'; @@ -153,106 +152,78 @@
-
- -
- -
- - - Filtros - - -
-
- -
- - -
-
- -
- - -
- -
- - -
- -
- - -
- -
- - -
-
-
- -
-
-
-
-
- Registros - Total: {total} registros encontrados + Bitácora de Auditoría + Mostrando {logs.length} de {total} registros +
+
+
+ + +
+ + + + - + + +
diff --git a/frontend/src/routes/dashboard/audit_logs/files-tab.svelte b/frontend/src/routes/dashboard/audit_logs/files-tab.svelte index 051df209..fc652973 100644 --- a/frontend/src/routes/dashboard/audit_logs/files-tab.svelte +++ b/frontend/src/routes/dashboard/audit_logs/files-tab.svelte @@ -80,58 +80,53 @@
-
-
-

{m['sidebar.audit_logs_files_title']()}

-

{displayPath || m['sidebar.audit_logs_files_root']()}

-
- -
- - - -
- {#each breadcrumbs as crumb, idx} - {#if idx > 0} - / - {/if} - {#if idx === breadcrumbs.length - 1} - - {crumb.display_name} - - {:else} - - {/if} - {/each} -
-
-
- - - {m['sidebar.audit_logs_files_list_title']()} + +
+
+ {m['sidebar.audit_logs_files_title']()} + +
+ {#each breadcrumbs as crumb, idx} + {#if idx > 0} + / + {/if} + {#if idx === breadcrumbs.length - 1} + + {crumb.display_name} + + {:else} + + {/if} + {/each} + {#if breadcrumbs.length === 0} + {m['sidebar.audit_logs_files_root']()} + {/if} +
+
+
+ +
- + {#if error} -
+
{m['sidebar.audit_logs_files_error_prefix']()} {error}
{/if} -
+
- + {m['sidebar.audit_logs_files_col_name']()} @@ -163,7 +158,7 @@ {:else} {#each folders as folder} void loadPath(folder.path)} > @@ -178,7 +173,7 @@ {/each} {#each files as file} - + {file.display_name} diff --git a/frontend/src/routes/dashboard/audit_logs/tasks-tab.svelte b/frontend/src/routes/dashboard/audit_logs/tasks-tab.svelte index 957e4c1e..e81ba92b 100644 --- a/frontend/src/routes/dashboard/audit_logs/tasks-tab.svelte +++ b/frontend/src/routes/dashboard/audit_logs/tasks-tab.svelte @@ -6,9 +6,9 @@ type UnifiedTaskStatus } from '$lib/api/dashboard/a76/tasks'; import { companyStore } from '$lib/stores/company.svelte'; + import * as Card from '$lib/components/ui/card'; import { Button } from '$lib/components/ui/button'; import { Input } from '$lib/components/ui/input'; - import * as Select from '$lib/components/ui/select'; import * as Dialog from '$lib/components/ui/dialog'; import { Badge } from '$lib/components/ui/badge'; @@ -146,106 +146,116 @@ }); -
-
- -
+
+ + +
+
+ Tareas del Sistema + Total: {total} tareas encontradas +
+
+ + + + +
+
+
+ + {#if error} +
+ {error} +
+ {/if} -
- - - - - Todos - En cola - En progreso - Completadas - Fallidas - - - -
- - {#if error} -
- {error} -
- {/if} - -
- - - - - - - - - - - - - {#if tasks.length === 0 && !loading} - - - - {:else if tasks.length === 0 && loading} - - - - {:else} - {#each tasks as task} - void openDetail(task)} - > - - - - - - +
+
Task IDTipoEstadoProgresoReintentosActualizado
Sin tareas registradas
Cargando...
{task.task_id}{task.task_group} / {task.task_name} - {statusLabel(task.status)} - ({task.celery_state_raw}) - - {formatPercent(task)} - {task.progress?.message ? ` · ${task.progress.message}` : ''} - {task.retries ?? 0}{new Date(task.updated_at).toLocaleString()}
+ + + + + + + + - {/each} - {/if} - -
Task IDTipoEstadoProgresoReintentosActualizado
-
- -
-
Total: {total}
-
- - Página {page} - + + + {#if tasks.length === 0 && !loading} + + Sin tareas registradas + + {:else if tasks.length === 0 && loading} + + Cargando... + + {:else} + {#each tasks as task} + void openDetail(task)} + > + {task.task_id} + {task.task_group} / {task.task_name} + + {statusLabel(task.status)} + ({task.celery_state_raw}) + + + {formatPercent(task)} + {task.progress?.message ? ` · ${task.progress.message}` : ''} + + {task.retries ?? 0} + {new Date(task.updated_at).toLocaleString()} + + {/each} + {/if} + + +
+ +
+
Total: {total}
+
+ + Página {page} + +
-
+
-
-
-
-

GESTIÓN ADUANAL

-

Administración de Agentes y Secciones Aduanales

+
+
+
+

Gestión Aduanal

+

Administración de Agentes y Secciones Aduanales

- + -
-
+
+

Filtros

@@ -228,7 +228,7 @@
@@ -237,7 +237,7 @@
@@ -246,8 +246,8 @@
-
-
+
+

Listado

@@ -260,7 +260,7 @@
-
+
-
+

Detalles del Agente @@ -407,6 +405,8 @@ + +

import { page } from '$app/stores'; - import DataTable from '$lib/components/dashboard/general_catalogs/classification_concepts/data-table.svelte'; + import InfiniteDataTable from '$lib/components/dashboard/common/infinite-data-table.svelte'; + import * as Card from '$lib/components/ui/card'; import { createColumns } from '$lib/components/dashboard/general_catalogs/classification_concepts/columns'; import CreateDialog from '$lib/components/dashboard/general_catalogs/classification/create-edit-dialog.svelte'; import { Button } from '$lib/components/ui/button'; import { Input } from '$lib/components/ui/input'; - import { Plus } from 'lucide-svelte'; + import { Plus, RefreshCw } from 'lucide-svelte'; import { goto } from '$app/navigation'; import { browser } from '$app/environment'; import { useShortcuts } from '$lib/hooks/use-shortcuts'; import { obtenerAtajosListaClasificacion } from '$lib/config/shortcuts/dashboard/general_catalogs/classification/list'; + import { getClassificationConcepts } from '$lib/api/dashboard/a76/general_catalogs/classification-concepts'; + import { companyStore } from '$lib/stores/company.svelte'; let { data } = $props(); let dialogOpen = $state(false); + let error = $state(data.error || null); // Atajos useShortcuts( @@ -28,17 +32,54 @@ let searchDesc = $state($page.url.searchParams.get('description') || ''); let timeout: ReturnType; - function handleSuccess() { - const url = new URL($page.url); - goto(url, { invalidateAll: true }); - } - const columns = $derived(createColumns(handleSuccess)); - function handleSearch() { + let allItems = $state(data.classifications?.items || []); + let currentPage = $state(data.classifications?.page || 1); + let pageSize = $state(data.classifications?.page_size || 50); + let totalItems = $state(data.classifications?.total || 0); + let loading = $state(false); + let hasMore = $derived(allItems.length < totalItems); + + $effect(() => { + if (data.classifications) { + allItems = data.classifications.items || []; + currentPage = data.classifications.page || 1; + totalItems = data.classifications.total || 0; + pageSize = data.classifications.page_size || pageSize; + } + }); + + async function handleSearch() { if (!browser) return; clearTimeout(timeout); - timeout = setTimeout(() => { + timeout = setTimeout(async () => { + if (!companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchClassification) filters.classification = searchClassification; + if (searchDesc) filters.description = searchDesc; + + const response = await getClassificationConcepts( + 1, + pageSize, + companyStore.activeCompany.id, + filters + ); + if (response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (err) { + error = 'Error aplicando filtros'; + console.error('Error applying filters:', err); + } finally { + loading = false; + } + const url = new URL($page.url); if (searchClassification) url.searchParams.set('classification', searchClassification); else url.searchParams.delete('classification'); @@ -46,47 +87,131 @@ if (searchDesc) url.searchParams.set('description', searchDesc); else url.searchParams.delete('description'); - url.searchParams.set('page', '1'); - goto(url, { keepFocus: true, noScroll: true }); + history.replaceState(history.state, '', url); }, 500); } + + async function loadMore() { + if (loading || !hasMore || !companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchClassification) filters.classification = searchClassification; + if (searchDesc) filters.description = searchDesc; + + const response = await getClassificationConcepts( + currentPage + 1, + pageSize, + companyStore.activeCompany.id, + filters + ); + if (response.data?.items) { + allItems = [...allItems, ...response.data.items]; + currentPage += 1; + totalItems = response.data.total; + } + } catch (err) { + error = 'Error cargando mas datos'; + console.error('Error loading more classifications:', err); + } finally { + loading = false; + } + } + + async function reloadData() { + if (!companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchClassification) filters.classification = searchClassification; + if (searchDesc) filters.description = searchDesc; + + const response = await getClassificationConcepts( + 1, + pageSize, + companyStore.activeCompany.id, + filters + ); + if (response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (err) { + error = 'Error al recargar datos'; + console.error('Error reloading classifications:', err); + } finally { + loading = false; + } + } + + function handleSuccess() { + reloadData(); + } -
+

Clasificaciones de Conceptos

Gestión del catálogo de clasificaciones de conceptos

- -
- -
-
- -
-
- +
+ +
- + {#if error} +
+ {error} +
+ {/if} + + + +
+ Listado de Clasificaciones +
+ + +
+
+
+ +
+ +
+
+
+ +
+ Mostrando {allItems.length} de {totalItems} registros +
import { page } from '$app/stores'; - import DataTable from '$lib/components/dashboard/general_catalogs/company/data-table.svelte'; + import InfiniteDataTable from '$lib/components/dashboard/common/infinite-data-table.svelte'; import { createColumns } from '$lib/components/dashboard/general_catalogs/company/columns'; + import * as Card from '$lib/components/ui/card'; import { Button } from '$lib/components/ui/button'; import { Input } from '$lib/components/ui/input'; - import { Plus } from 'lucide-svelte'; + import { Plus, RefreshCw } from 'lucide-svelte'; import { goto } from '$app/navigation'; import { browser } from '$app/environment'; import * as m from '$lib/paraglide/messages.js'; import { useShortcuts } from '$lib/hooks/use-shortcuts'; import { obtenerAtajosListaEmpresa } from '$lib/config/shortcuts/dashboard/general_catalogs/company_information/list'; + import { getCompanies } from '$lib/api/dashboard/a76/general_catalogs/company'; let { data } = $props(); @@ -24,16 +26,53 @@ }) ); let dialogOpen = $state(false); + let error = $state(data.error || null); // Filtros let searchName = $state($page.url.searchParams.get('name') || ''); let searchRfc = $state($page.url.searchParams.get('rfc') || ''); let timeout: ReturnType; - function handleSearch() { + let allItems = $state(data.companies?.items || []); + let currentPage = $state(data.companies?.page || 1); + let pageSize = $state(data.companies?.page_size || 50); + let totalItems = $state(data.companies?.total || 0); + let loading = $state(false); + let hasMore = $derived(allItems.length < totalItems); + + $effect(() => { + if (data.companies) { + allItems = data.companies.items || []; + currentPage = data.companies.page || 1; + totalItems = data.companies.total || 0; + pageSize = data.companies.page_size || pageSize; + } + }); + + async function handleSearch() { if (!browser) return; clearTimeout(timeout); - timeout = setTimeout(() => { + timeout = setTimeout(async () => { + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchName) filters.name = searchName; + if (searchRfc) filters.rfc = searchRfc; + + const response = await getCompanies(1, pageSize, filters); + if (response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (err) { + error = 'Error aplicando filtros'; + console.error('Error applying filters:', err); + } finally { + loading = false; + } + const url = new URL($page.url); if (searchName) url.searchParams.set('name', searchName); else url.searchParams.delete('name'); @@ -41,44 +80,118 @@ if (searchRfc) url.searchParams.set('rfc', searchRfc); else url.searchParams.delete('rfc'); - url.searchParams.set('page', '1'); - goto(url, { keepFocus: true, noScroll: true }); + history.replaceState(history.state, '', url); }, 500); } + async function loadMore() { + if (loading || !hasMore) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchName) filters.name = searchName; + if (searchRfc) filters.rfc = searchRfc; + + const response = await getCompanies(currentPage + 1, pageSize, filters); + if (response.data?.items) { + allItems = [...allItems, ...response.data.items]; + currentPage += 1; + totalItems = response.data.total; + } + } catch (err) { + error = 'Error cargando mas datos'; + console.error('Error loading more companies:', err); + } finally { + loading = false; + } + } + + async function reloadData() { + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchName) filters.name = searchName; + if (searchRfc) filters.rfc = searchRfc; + + const response = await getCompanies(1, pageSize, filters); + if (response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (err) { + error = 'Error al recargar datos'; + console.error('Error reloading companies:', err); + } finally { + loading = false; + } + } + function handleSuccess() { - const url = new URL($page.url); - goto(url, { invalidateAll: true }); + reloadData(); } -
+

Información de Empresas

Gestión de información de empresas

- -
- -
-
- -
-
- +
+ +
-
- + {#if error} +
+ {error} +
+ {/if} + + + +
+ Listado de Empresas +
+ + +
+
+
+ +
+ +
+
+
+ +
+ Mostrando {allItems.length} de {totalItems} registros
diff --git a/frontend/src/routes/dashboard/general_catalogs/concepts/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/concepts/+page.svelte index 63507986..33c48136 100644 --- a/frontend/src/routes/dashboard/general_catalogs/concepts/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/concepts/+page.svelte @@ -1,21 +1,25 @@ -
+

Conceptos

Gestión del catálogo de conceptos

- -
- -
-
- -
-
- +
+ +
-
- + {#if error} +
+ {error} +
+ {/if} + + + +
+ Listado de Conceptos +
+ + +
+
+
+ +
+ +
+
+
+ +
+ Mostrando {allItems.length} de {totalItems} registros
{#if dialogOpen} diff --git a/frontend/src/routes/dashboard/general_catalogs/customs_broker_concepts/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/customs_broker_concepts/+page.svelte index 0f19a0c1..a049231d 100644 --- a/frontend/src/routes/dashboard/general_catalogs/customs_broker_concepts/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/customs_broker_concepts/+page.svelte @@ -1,21 +1,24 @@ -
+

Conceptos de Agente Aduanal

Gestión del catálogo de conceptos de agente aduanal

- -
- -
-
- -
-
- +
+ +
-
- + {#if error} +
+ {error} +
+ {/if} + + + +
+ Listado de Conceptos de Agente Aduanal +
+ + +
+
+
+ +
+ +
+
+
+ +
+ Mostrando {allItems.length} de {totalItems} registros
{#if activeCompanyId} diff --git a/frontend/src/routes/dashboard/general_catalogs/doda/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/doda/+page.svelte index 80684dce..258c3647 100644 --- a/frontend/src/routes/dashboard/general_catalogs/doda/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/doda/+page.svelte @@ -3,7 +3,6 @@ import { goto } from '$app/navigation'; import { browser } from '$app/environment'; import { getDodas, deleteDoda, type Doda } from '$lib/api/dashboard/a76/general_catalogs/doda'; - import * as Card from '$lib/components/ui/card'; import { toast } from 'svelte-sonner'; import { Plus, @@ -16,6 +15,7 @@ LayoutGrid, Printer } from 'lucide-svelte'; + import * as Card from '$lib/components/ui/card'; import * as Select from '$lib/components/ui/select'; import { companyStore } from '$lib/stores/company.svelte'; import DataTable from '$lib/components/dashboard/general_catalogs/doda/data-table.svelte'; @@ -23,7 +23,6 @@ import CreateEditDialog from '$lib/components/dashboard/general_catalogs/doda/create-edit-dialog.svelte'; import { Button } from '$lib/components/ui/button'; import { Input } from '$lib/components/ui/input'; - import { Label } from '$lib/components/ui/label'; import { Separator } from '$lib/components/ui/separator'; import { useShortcuts } from '$lib/hooks/use-shortcuts'; import { obtenerAtajosListaDoda } from '$lib/config/shortcuts/dashboard/general_catalogs/doda/list'; @@ -194,60 +193,45 @@ } -
-
-
-

DODA

+
+
+
+

DODA

Gestiona tus Documentos de Operación Aduanera (DODA)

- +
+ + +
- + -
-
- Filtros Avanzados - Refina tu búsqueda mediante múltiples criterios -
- -
-
- -
-
- +
+ Listado de DODA +
- +
-
- -
- - -
- -
- + (filters.status = v)} > - - {filters.status || 'Todos los estatus'} + + {filters.status || 'Estatus'} Todos @@ -257,21 +241,17 @@ ELIMINADO -
- -
- (filters.operation_type = v)} > - + {filters.operation_type === 'I' ? 'Importación' : filters.operation_type === 'E' ? 'Exportación' - : 'Todas'} + : 'Operación'} Todas @@ -279,38 +259,35 @@ E - Exportación +
+ + +
+ +
- - -
-
- Listado de DODAs - - Mostrando {allItems.length} de {totalItems} registros - -
- -
-
- - - -
+
+ Mostrando {allItems.length} de {totalItems} registros + + Filtros activos: {Object.values(filters).filter((value) => value !== '').length} +
+ +
-
- - {#if dialogOpen} {/if} diff --git a/frontend/src/routes/dashboard/general_catalogs/doda/edit/[[id]]/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/doda/edit/[[id]]/+page.svelte index 67e241a0..db7208ec 100644 --- a/frontend/src/routes/dashboard/general_catalogs/doda/edit/[[id]]/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/doda/edit/[[id]]/+page.svelte @@ -262,7 +262,7 @@ > -

{title}

+

{title}

Catálogos Generales / Doda

diff --git a/frontend/src/routes/dashboard/general_catalogs/drivers/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/drivers/+page.svelte index 03a29c1c..0f089351 100644 --- a/frontend/src/routes/dashboard/general_catalogs/drivers/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/drivers/+page.svelte @@ -1,11 +1,12 @@ -
+
-

Conductores

+

Conductores

Gestión del catálogo de conductores

- +
-
- - -
+ +
Listado de Conductores
+ {#if loading && data.length === 0}
Cargando conductores...
{:else}
{/if}
+
- {#if loading && data.length === 0} -
- Cargando conductores... -
- {:else} - - {/if} +
Mostrando {data.length} de {totalItems} registros
diff --git a/frontend/src/routes/dashboard/general_catalogs/electronic_notices/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/electronic_notices/+page.svelte index 3c3fa9f7..7aa48435 100644 --- a/frontend/src/routes/dashboard/general_catalogs/electronic_notices/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/electronic_notices/+page.svelte @@ -2,17 +2,21 @@ import { page } from '$app/stores'; import { goto } from '$app/navigation'; import { browser } from '$app/environment'; - import DataTable from '$lib/components/dashboard/general_catalogs/electronic_notices/data-table.svelte'; + import InfiniteDataTable from '$lib/components/dashboard/common/infinite-data-table.svelte'; import { createColumns } from '$lib/components/dashboard/general_catalogs/electronic_notices/columns.js'; import CreateEditDialog from '$lib/components/dashboard/general_catalogs/electronic_notices/create-edit-dialog.svelte'; + import * as Card from '$lib/components/ui/card'; import { Button } from '$lib/components/ui/button'; import { Input } from '$lib/components/ui/input'; - import { Plus } from 'lucide-svelte'; + import { Plus, RefreshCw } from 'lucide-svelte'; import { useShortcuts } from '$lib/hooks/use-shortcuts'; import { obtenerAtajosListaAvisosElectrónicos } from '$lib/config/shortcuts/dashboard/general_catalogs/electronic_notices/list'; + import { getElectronicNotices } from '$lib/api/dashboard/a76/general_catalogs/electronic-notices'; + import { companyStore } from '$lib/stores/company.svelte'; let { data } = $props(); let dialogOpen = $state(false); + let error = $state(data.error || null); // Atajos useShortcuts( @@ -28,10 +32,52 @@ let searchPedimento = $state($page.url.searchParams.get('pedimento') || ''); let timeout: ReturnType; - function handleSearch() { + let allItems = $state(data.notices?.items || []); + let currentPage = $state(data.notices?.page || 1); + let pageSize = $state(data.notices?.page_size || 50); + let totalItems = $state(data.notices?.total || 0); + let loading = $state(false); + let hasMore = $derived(allItems.length < totalItems); + + $effect(() => { + if (data.notices) { + allItems = data.notices.items || []; + currentPage = data.notices.page || 1; + totalItems = data.notices.total || 0; + pageSize = data.notices.page_size || pageSize; + } + }); + + async function handleSearch() { if (!browser) return; clearTimeout(timeout); - timeout = setTimeout(() => { + timeout = setTimeout(async () => { + if (!companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchNotice) filters.notice_number = searchNotice; + if (searchPedimento) filters.pedimento = searchPedimento; + + const response = await getElectronicNotices( + 1, + pageSize, + filters, + companyStore.activeCompany.id + ); + if (response?.items) { + allItems = response.items; + currentPage = 1; + totalItems = response.total; + } + } catch (err) { + error = 'Error aplicando filtros'; + console.error('Error applying filters:', err); + } finally { + loading = false; + } + const url = new URL($page.url); if (searchNotice) url.searchParams.set('notice_number', searchNotice); else url.searchParams.delete('notice_number'); @@ -39,54 +85,92 @@ if (searchPedimento) url.searchParams.set('pedimento', searchPedimento); else url.searchParams.delete('pedimento'); - url.searchParams.set('page', '1'); - goto(url, { keepFocus: true, noScroll: true }); + history.replaceState(history.state, '', url); }, 500); } + async function loadMore() { + if (loading || !hasMore || !companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchNotice) filters.notice_number = searchNotice; + if (searchPedimento) filters.pedimento = searchPedimento; + + const response = await getElectronicNotices( + currentPage + 1, + pageSize, + filters, + companyStore.activeCompany.id + ); + if (response?.items) { + allItems = [...allItems, ...response.items]; + currentPage += 1; + totalItems = response.total; + } + } catch (err) { + error = 'Error cargando mas datos'; + console.error('Error loading more electronic notices:', err); + } finally { + loading = false; + } + } + + async function reloadData() { + if (!companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchNotice) filters.notice_number = searchNotice; + if (searchPedimento) filters.pedimento = searchPedimento; + + const response = await getElectronicNotices( + 1, + pageSize, + filters, + companyStore.activeCompany.id + ); + if (response?.items) { + allItems = response.items; + currentPage = 1; + totalItems = response.total; + } + } catch (err) { + error = 'Error al recargar datos'; + console.error('Error reloading electronic notices:', err); + } finally { + loading = false; + } + } + function handleSuccess() { - const url = new URL($page.url); - goto(url, { invalidateAll: true }); + reloadData(); } -
+

Avisos Electrónicos

Gestión del catálogo de avisos electrónicos

- +
-
-
- + {#if error} +
+ {error}
-
- -
-
+ {/if} -
- -
+ +
Listado de Avisos
+
+
+ +
Mostrando {allItems.length} de {totalItems} registros
diff --git a/frontend/src/routes/dashboard/general_catalogs/equivalencies/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/equivalencies/+page.svelte index d86f780d..51a76f07 100644 --- a/frontend/src/routes/dashboard/general_catalogs/equivalencies/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/equivalencies/+page.svelte @@ -4,16 +4,20 @@ import { browser } from '$app/environment'; import type { Equivalency } from '$lib/api/dashboard/a76/general_catalogs/equivalencies'; import { createCatalogColumns } from '$lib/components/dashboard/general_catalogs/equivalencies/catalog-columns'; - import DataTable from '$lib/components/dashboard/general_catalogs/equivalencies/data-table.svelte'; + import InfiniteDataTable from '$lib/components/dashboard/common/infinite-data-table.svelte'; + import * as Card from '$lib/components/ui/card'; import { Button } from '$lib/components/ui/button'; import { Input } from '$lib/components/ui/input'; - import { Plus } from 'lucide-svelte'; + import { Plus, RefreshCw } from 'lucide-svelte'; import { useShortcuts } from '$lib/hooks/use-shortcuts'; import { obtenerAtajosListaEquivalencias } from '$lib/config/shortcuts/dashboard/general_catalogs/equivalencies/list'; import DataEquivalenciesDialog from '$lib/components/dashboard/general_catalogs/equivalencies/data-equivalencies-dialog.svelte'; import type { PageData } from './$types'; + import { getEquivalencies } from '$lib/api/dashboard/a76/general_catalogs/equivalencies'; + import { companyStore } from '$lib/stores/company.svelte'; let { data }: { data: PageData } = $props(); + let error = $state(data.error || null); let dataDialogOpen = $state(false); let selectedEquivalency = $state(null); @@ -36,22 +40,115 @@ let searchFrom = $state($page.url.searchParams.get('from_unit_code') || ''); let timeout: ReturnType; - function handleSearch() { + let allItems = $state(data.equivalencies?.items || []); + let currentPage = $state(data.equivalencies?.page || 1); + let pageSize = $state(data.equivalencies?.page_size || 50); + let totalItems = $state(data.equivalencies?.total || 0); + let loading = $state(false); + let hasMore = $derived(allItems.length < totalItems); + + $effect(() => { + if (data.equivalencies) { + allItems = data.equivalencies.items || []; + currentPage = data.equivalencies.page || 1; + totalItems = data.equivalencies.total || 0; + pageSize = data.equivalencies.page_size || pageSize; + } + }); + + async function handleSearch() { if (!browser) return; clearTimeout(timeout); - timeout = setTimeout(() => { + timeout = setTimeout(async () => { + if (!companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchFrom) filters.from_unit_code = searchFrom; + + const response = await getEquivalencies( + 1, + pageSize, + companyStore.activeCompany.id, + filters + ); + if (response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (err) { + error = 'Error aplicando filtros'; + console.error('Error applying filters:', err); + } finally { + loading = false; + } + const url = new URL($page.url); if (searchFrom) url.searchParams.set('from_unit_code', searchFrom); else url.searchParams.delete('from_unit_code'); - url.searchParams.set('page', '1'); - goto(url, { keepFocus: true, noScroll: true }); + history.replaceState(history.state, '', url); }, 500); } + async function loadMore() { + if (loading || !hasMore || !companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchFrom) filters.from_unit_code = searchFrom; + + const response = await getEquivalencies( + currentPage + 1, + pageSize, + companyStore.activeCompany.id, + filters + ); + if (response.data?.items) { + allItems = [...allItems, ...response.data.items]; + currentPage += 1; + totalItems = response.data.total; + } + } catch (err) { + error = 'Error cargando mas datos'; + console.error('Error loading more equivalencies:', err); + } finally { + loading = false; + } + } + + async function reloadData() { + if (!companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchFrom) filters.from_unit_code = searchFrom; + + const response = await getEquivalencies( + 1, + pageSize, + companyStore.activeCompany.id, + filters + ); + if (response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (err) { + error = 'Error al recargar datos'; + console.error('Error reloading equivalencies:', err); + } finally { + loading = false; + } + } + function handleSuccess() { - const url = new URL($page.url); - goto(url, { invalidateAll: true }); + reloadData(); } function handleOpenInsertItems(equivalency: Equivalency) { @@ -67,13 +164,13 @@ } -
+

Equivalencias

Catálogo de equivalencias

- +
-
-
- + {#if error} +
+ {error}
-
+ {/if} - + +
Listado de Equivalencias
+
+
+ +
Mostrando {allItems.length} de {totalItems} registros
(data.error || null); // Atajos useShortcuts( @@ -29,10 +33,52 @@ let searchDesc = $state($page.url.searchParams.get('description') || ''); let timeout: ReturnType; - function handleSearch() { + let allItems = $state(data.errors?.items || []); + let currentPage = $state(data.errors?.page || 1); + let pageSize = $state(data.errors?.page_size || 50); + let totalItems = $state(data.errors?.total || 0); + let loading = $state(false); + let hasMore = $derived(allItems.length < totalItems); + + $effect(() => { + if (data.errors) { + allItems = data.errors.items || []; + currentPage = data.errors.page || 1; + totalItems = data.errors.total || 0; + pageSize = data.errors.page_size || pageSize; + } + }); + + async function handleSearch() { if (!browser) return; clearTimeout(timeout); - timeout = setTimeout(() => { + timeout = setTimeout(async () => { + if (!companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchCode) filters.code = searchCode; + if (searchDesc) filters.description = searchDesc; + + const response = await getErrorCatalogs( + companyStore.activeCompany.id, + 1, + pageSize, + filters + ); + if (response?.items) { + allItems = response.items; + currentPage = 1; + totalItems = response.total; + } + } catch (err) { + error = 'Error aplicando filtros'; + console.error('Error applying filters:', err); + } finally { + loading = false; + } + const url = new URL($page.url); if (searchCode) url.searchParams.set('code', searchCode); else url.searchParams.delete('code'); @@ -40,50 +86,92 @@ if (searchDesc) url.searchParams.set('description', searchDesc); else url.searchParams.delete('description'); - url.searchParams.set('page', '1'); - goto(url, { keepFocus: true, noScroll: true }); + history.replaceState(history.state, '', url); }, 500); } + async function loadMore() { + if (loading || !hasMore || !companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchCode) filters.code = searchCode; + if (searchDesc) filters.description = searchDesc; + + const response = await getErrorCatalogs( + companyStore.activeCompany.id, + currentPage + 1, + pageSize, + filters + ); + if (response?.items) { + allItems = [...allItems, ...response.items]; + currentPage += 1; + totalItems = response.total; + } + } catch (err) { + error = 'Error cargando mas datos'; + console.error('Error loading more error catalogs:', err); + } finally { + loading = false; + } + } + + async function reloadData() { + if (!companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchCode) filters.code = searchCode; + if (searchDesc) filters.description = searchDesc; + + const response = await getErrorCatalogs( + companyStore.activeCompany.id, + 1, + pageSize, + filters + ); + if (response?.items) { + allItems = response.items; + currentPage = 1; + totalItems = response.total; + } + } catch (err) { + error = 'Error al recargar datos'; + console.error('Error reloading error catalogs:', err); + } finally { + loading = false; + } + } + function handleSuccess() { - const url = new URL($page.url); - goto(url, { invalidateAll: true }); + reloadData(); } -
+

Errores de Facturación

Gestión del catálogo de errores de facturación

- +
-
-
- + {#if error} +
+ {error}
-
- -
-
+ {/if} -
- -
+ +
Listado de Errores
+
+
+ +
Mostrando {allItems.length} de {totalItems} registros
diff --git a/frontend/src/routes/dashboard/general_catalogs/exchange-rate/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/exchange-rate/+page.svelte index d2c20235..a68435cb 100644 --- a/frontend/src/routes/dashboard/general_catalogs/exchange-rate/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/exchange-rate/+page.svelte @@ -4,17 +4,21 @@ import { browser } from '$app/environment'; import { createColumns } from '$lib/components/dashboard/exchange_rate/columns'; import CreateEditDialog from '$lib/components/dashboard/exchange_rate/create-edit-dialog.svelte'; - import DataTable from '$lib/components/dashboard/exchange_rate/data-table.svelte'; + import InfiniteDataTable from '$lib/components/dashboard/common/infinite-data-table.svelte'; + import * as Card from '$lib/components/ui/card'; import { Button } from '$lib/components/ui/button'; import { Input } from '$lib/components/ui/input'; - import { Plus } from 'lucide-svelte'; + import { Plus, RefreshCw } from 'lucide-svelte'; import { useShortcuts } from '$lib/hooks/use-shortcuts'; import { obtenerAtajosListaTiposCambio } from '$lib/config/shortcuts/dashboard/general_catalogs/exchange_rate/list'; import type { PageData } from './$types'; + import { getExchangeRates } from '$lib/api/dashboard/a76/general_catalogs/exchange-rate'; + import { companyStore } from '$lib/stores/company.svelte'; let { data }: { data: PageData } = $props(); let createDialogOpen = $state(false); + let error = $state(data.error || null); // Atajos useShortcuts( @@ -36,55 +40,127 @@ let searchCurrency = $state($page.url.searchParams.get('local_currency') || ''); let timeout: ReturnType; - function handleSearch() { + let allItems = $state(data.exchange_rates?.items || []); + let currentPage = $state(data.exchange_rates?.page || 1); + let pageSize = $state(data.exchange_rates?.page_size || 50); + let totalItems = $state(data.exchange_rates?.total || 0); + let loading = $state(false); + let hasMore = $derived(allItems.length < totalItems); + + $effect(() => { + if (data.exchange_rates) { + allItems = data.exchange_rates.items || []; + currentPage = data.exchange_rates.page || 1; + totalItems = data.exchange_rates.total || 0; + pageSize = data.exchange_rates.page_size || pageSize; + } + }); + + async function handleSearch() { if (!browser) return; clearTimeout(timeout); - timeout = setTimeout(() => { + timeout = setTimeout(async () => { + if (!companyStore.activeCompany) return; + loading = true; + error = null; + try { + const response = await getExchangeRates(companyStore.activeCompany.id, { + local_currency: searchCurrency || undefined, + page: 1, + page_size: pageSize + }); + if (response.data) { + allItems = response.data.items; + currentPage = response.data.page || 1; + totalItems = response.data.total || 0; + } + } catch (err) { + error = 'Error aplicando filtros'; + console.error('Error applying filters:', err); + } finally { + loading = false; + } + const url = new URL($page.url); if (searchCurrency) url.searchParams.set('local_currency', searchCurrency); else url.searchParams.delete('local_currency'); - url.searchParams.set('page', '1'); - goto(url, { keepFocus: true, noScroll: true }); + history.replaceState(history.state, '', url); }, 500); } + async function loadMore() { + if (loading || !hasMore || !companyStore.activeCompany) return; + loading = true; + error = null; + try { + const response = await getExchangeRates(companyStore.activeCompany.id, { + local_currency: searchCurrency || undefined, + page: currentPage + 1, + page_size: pageSize + }); + if (response.data?.items) { + allItems = [...allItems, ...response.data.items]; + currentPage += 1; + totalItems = response.data.total || 0; + } + } catch (err) { + error = 'Error cargando mas datos'; + console.error('Error loading more exchange rates:', err); + } finally { + loading = false; + } + } + + async function reloadData() { + if (!companyStore.activeCompany) return; + loading = true; + error = null; + try { + const response = await getExchangeRates(companyStore.activeCompany.id, { + local_currency: searchCurrency || undefined, + page: 1, + page_size: pageSize + }); + if (response.data) { + allItems = response.data.items; + currentPage = response.data.page || 1; + totalItems = response.data.total || 0; + } + } catch (err) { + error = 'Error al recargar datos'; + console.error('Error reloading exchange rates:', err); + } finally { + loading = false; + } + } + function handleSuccess() { - const url = new URL($page.url); - goto(url, { invalidateAll: true }); + reloadData(); } -
+

Tipos de Cambio

Catálogo de tipos de cambio

- +
-
-
- + {#if error} +
+ {error}
-
+ {/if} -
- -
+ +
Listado de Tipos de Cambio
+
+
+ +
Mostrando {allItems.length} de {totalItems} registros
diff --git a/frontend/src/routes/dashboard/general_catalogs/identifiers/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/identifiers/+page.svelte index 31be43a1..d986d669 100644 --- a/frontend/src/routes/dashboard/general_catalogs/identifiers/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/identifiers/+page.svelte @@ -4,17 +4,21 @@ import { browser } from '$app/environment'; import { createColumns } from '$lib/components/dashboard/general_catalogs/identifiers/columns'; import CreateEditDialog from '$lib/components/dashboard/general_catalogs/identifiers/create-edit-dialog.svelte'; - import DataTable from '$lib/components/dashboard/general_catalogs/identifiers/data-table.svelte'; + import InfiniteDataTable from '$lib/components/dashboard/common/infinite-data-table.svelte'; + import * as Card from '$lib/components/ui/card'; import { Button } from '$lib/components/ui/button'; import { Input } from '$lib/components/ui/input'; - import { Plus } from 'lucide-svelte'; + import { Plus, RefreshCw } from 'lucide-svelte'; import type { PageData } from './$types'; import { useShortcuts } from '$lib/hooks/use-shortcuts'; import { obtenerAtajosListaIdentificadores } from '$lib/config/shortcuts/dashboard/general_catalogs/identifiers/list'; + import { getIdentifiers } from '$lib/api/dashboard/a76/general_catalogs/identifiers'; + import { companyStore } from '$lib/stores/company.svelte'; let { data }: { data: PageData } = $props(); let createDialogOpen = $state(false); + let error = $state(data.error || null); // Atajos useShortcuts( @@ -30,10 +34,47 @@ let searchDesc = $state($page.url.searchParams.get('description') || ''); let timeout: ReturnType; - function handleSearch() { + let allItems = $state(data.identifiers?.items || []); + let currentPage = $state(data.identifiers?.page || 1); + let pageSize = $state(data.identifiers?.page_size || 50); + let totalItems = $state(data.identifiers?.total || 0); + let loading = $state(false); + let hasMore = $derived(allItems.length < totalItems); + + $effect(() => { + if (data.identifiers) { + allItems = data.identifiers.items || []; + currentPage = data.identifiers.page || 1; + totalItems = data.identifiers.total || 0; + pageSize = data.identifiers.page_size || pageSize; + } + }); + + async function handleSearch() { if (!browser) return; clearTimeout(timeout); - timeout = setTimeout(() => { + timeout = setTimeout(async () => { + if (!companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchCode) filters.code = searchCode; + if (searchDesc) filters.description = searchDesc; + + const response = await getIdentifiers(1, pageSize, companyStore.activeCompany.id, filters); + if (response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (err) { + error = 'Error aplicando filtros'; + console.error('Error applying filters:', err); + } finally { + loading = false; + } + const url = new URL($page.url); if (searchCode) url.searchParams.set('code', searchCode); else url.searchParams.delete('code'); @@ -41,49 +82,125 @@ if (searchDesc) url.searchParams.set('description', searchDesc); else url.searchParams.delete('description'); - url.searchParams.set('page', '1'); - goto(url, { keepFocus: true, noScroll: true }); + history.replaceState(history.state, '', url); }, 500); } + async function loadMore() { + if (loading || !hasMore || !companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchCode) filters.code = searchCode; + if (searchDesc) filters.description = searchDesc; + + const response = await getIdentifiers( + currentPage + 1, + pageSize, + companyStore.activeCompany.id, + filters + ); + if (response.data?.items) { + allItems = [...allItems, ...response.data.items]; + currentPage += 1; + totalItems = response.data.total; + } + } catch (err) { + error = 'Error cargando mas datos'; + console.error('Error loading more identifiers:', err); + } finally { + loading = false; + } + } + + async function reloadData() { + if (!companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchCode) filters.code = searchCode; + if (searchDesc) filters.description = searchDesc; + + const response = await getIdentifiers(1, pageSize, companyStore.activeCompany.id, filters); + if (response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (err) { + error = 'Error al recargar datos'; + console.error('Error reloading identifiers:', err); + } finally { + loading = false; + } + } + function handleSuccess() { - const url = new URL($page.url); - goto(url, { invalidateAll: true }); + reloadData(); } -
+

Identificadores

Catálogo de identificadores

- -
- -
-
- -
-
- +
+ +
-
- + {#if error} +
+ {error} +
+ {/if} + + + +
+ Listado de Identificadores +
+ + +
+
+
+ +
+ +
+
+
+ +
+ Mostrando {allItems.length} de {totalItems} registros
diff --git a/frontend/src/routes/dashboard/general_catalogs/inpc/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/inpc/+page.svelte index bc626c29..92990890 100644 --- a/frontend/src/routes/dashboard/general_catalogs/inpc/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/inpc/+page.svelte @@ -4,17 +4,21 @@ import { browser } from '$app/environment'; import { createColumns } from '$lib/components/dashboard/general_catalogs/inpc/columns'; import CreateEditDialog from '$lib/components/dashboard/general_catalogs/inpc/create-edit-dialog.svelte'; - import DataTable from '$lib/components/dashboard/general_catalogs/inpc/data-table.svelte'; + import InfiniteDataTable from '$lib/components/dashboard/common/infinite-data-table.svelte'; + import * as Card from '$lib/components/ui/card'; import { Button } from '$lib/components/ui/button'; import { Input } from '$lib/components/ui/input'; - import { Plus } from 'lucide-svelte'; + import { Plus, RefreshCw } from 'lucide-svelte'; import type { PageData } from './$types'; import { useShortcuts } from '$lib/hooks/use-shortcuts'; import { obtenerAtajosListaInpc } from '$lib/config/shortcuts/dashboard/general_catalogs/inpc/list'; + import { getINPCs } from '$lib/api/dashboard/a76/general_catalogs/inpc'; + import { companyStore } from '$lib/stores/company.svelte'; let { data }: { data: PageData } = $props(); let createDialogOpen = $state(false); + let error = $state(data.error || null); // Atajos useShortcuts( @@ -30,10 +34,48 @@ let searchMonth = $state($page.url.searchParams.get('month') || ''); let timeout: ReturnType; - function handleSearch() { + // Infinite scroll + let allItems = $state(data.inpc?.items || []); + let currentPage = $state(data.inpc?.page || 1); + let pageSize = $state(data.inpc?.page_size || 50); + let totalItems = $state(data.inpc?.total || 0); + let loading = $state(false); + let hasMore = $derived(allItems.length < totalItems); + + $effect(() => { + if (data.inpc) { + allItems = data.inpc.items || []; + currentPage = data.inpc.page || 1; + totalItems = data.inpc.total || 0; + pageSize = data.inpc.page_size || pageSize; + } + }); + + async function handleSearch() { if (!browser) return; clearTimeout(timeout); - timeout = setTimeout(() => { + timeout = setTimeout(async () => { + if (!companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchYear) filters.year = searchYear; + if (searchMonth) filters.month = searchMonth; + + const response = await getINPCs(1, pageSize, companyStore.activeCompany.id, filters); + if (response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (err) { + error = 'Error aplicando filtros'; + console.error('Error applying filters:', err); + } finally { + loading = false; + } + const url = new URL($page.url); if (searchYear) url.searchParams.set('year', searchYear); else url.searchParams.delete('year'); @@ -41,45 +83,125 @@ if (searchMonth) url.searchParams.set('month', searchMonth); else url.searchParams.delete('month'); - url.searchParams.set('page', '1'); - goto(url, { keepFocus: true, noScroll: true }); + history.replaceState(history.state, '', url); }, 500); } + async function loadMore() { + if (loading || !hasMore || !companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchYear) filters.year = searchYear; + if (searchMonth) filters.month = searchMonth; + + const response = await getINPCs( + currentPage + 1, + pageSize, + companyStore.activeCompany.id, + filters + ); + if (response.data?.items) { + allItems = [...allItems, ...response.data.items]; + currentPage += 1; + totalItems = response.data.total; + } + } catch (err) { + error = 'Error cargando mas datos'; + console.error('Error loading more INPC:', err); + } finally { + loading = false; + } + } + + async function reloadData() { + if (!companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchYear) filters.year = searchYear; + if (searchMonth) filters.month = searchMonth; + + const response = await getINPCs(1, pageSize, companyStore.activeCompany.id, filters); + if (response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (err) { + error = 'Error al recargar datos'; + console.error('Error reloading INPC:', err); + } finally { + loading = false; + } + } + function handleSuccess() { - const url = new URL($page.url); - goto(url, { invalidateAll: true }); + reloadData(); } -
-
+
+

INPC

Índice Nacional de Precios al Consumidor

- -
- -
-
- -
-
- +
+ +
-
- + {#if error} +
+ {error} +
+ {/if} + + + +
+ Listado de INPC +
+ + +
+
+
+ +
+ +
+
+
+ +
+ Mostrando {allItems.length} de {totalItems} registros
diff --git a/frontend/src/routes/dashboard/general_catalogs/legends/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/legends/+page.svelte index 2c9ecc30..9632ba7c 100644 --- a/frontend/src/routes/dashboard/general_catalogs/legends/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/legends/+page.svelte @@ -1,18 +1,22 @@ -
-
+
+

Leyendas Fijas

Gestión del catálogo de leyendas fijas

- -
- -
-
- -
-
- +
+ +
-
- + {#if error} +
+ {error} +
+ {/if} + + + +
+ Listado de Leyendas +
+ + +
+
+
+ +
+ +
+
+
+ +
+ Mostrando {allItems.length} de {totalItems} registros
diff --git a/frontend/src/routes/dashboard/general_catalogs/multi_currency_types/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/multi_currency_types/+page.svelte index 1dbfa9d1..004b399a 100644 --- a/frontend/src/routes/dashboard/general_catalogs/multi_currency_types/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/multi_currency_types/+page.svelte @@ -1,17 +1,25 @@ -
+

Tipos de Moneda Múltiple

Gestión del catálogo de tipos de moneda múltiple

- +
-
-
- + {#if error} +
+ {error}
-
- -
-
+ {/if} -
- -
+ +
Listado de Monedas
+
+
+ +
Mostrando {allItems.length} de {totalItems} registros
diff --git a/frontend/src/routes/dashboard/general_catalogs/packages/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/packages/+page.svelte index 12777b93..659451d8 100644 --- a/frontend/src/routes/dashboard/general_catalogs/packages/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/packages/+page.svelte @@ -1,21 +1,25 @@ -
+

Bultos y Embalajes

Gestión del catálogo de bultos y embalajes

- -
- -
-
- -
-
- +
+ +
-
- + {#if error} +
+ {error} +
+ {/if} + + + +
+ Listado de Bultos +
+ + +
+
+
+ +
+ +
+
+
+ +
+ Mostrando {allItems.length} de {totalItems} registros
diff --git a/frontend/src/routes/dashboard/general_catalogs/ports/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/ports/+page.svelte index 88c42d3c..2ad73e0c 100644 --- a/frontend/src/routes/dashboard/general_catalogs/ports/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/ports/+page.svelte @@ -4,17 +4,21 @@ import { browser } from '$app/environment'; import { createColumns } from '$lib/components/dashboard/ports/columns'; import CreateEditDialog from '$lib/components/dashboard/ports/create-edit-dialog.svelte'; - import DataTable from '$lib/components/dashboard/general_catalogs/units_of_measure/ace/data-table.svelte'; + import InfiniteDataTable from '$lib/components/dashboard/common/infinite-data-table.svelte'; + import * as Card from '$lib/components/ui/card'; import { Button } from '$lib/components/ui/button'; import { Input } from '$lib/components/ui/input'; - import { Plus } from 'lucide-svelte'; + import { Plus, RefreshCw } from 'lucide-svelte'; import type { PageData } from './$types'; import { useShortcuts } from '$lib/hooks/use-shortcuts'; import { obtenerAtajosListaPuertos } from '$lib/config/shortcuts/dashboard/general_catalogs/ports/list'; + import { portsApi } from '$lib/api/dashboard/a76/general_catalogs/ports'; + import { companyStore } from '$lib/stores/company.svelte'; let { data }: { data: PageData } = $props(); let createDialogOpen = $state(false); + let error = $state(data.items?.error || null); // Atajos useShortcuts( @@ -30,10 +34,50 @@ let searchDesc = $state($page.url.searchParams.get('description') || ''); let timeout: ReturnType; - function handleSearch() { + let allItems = $state(data.items?.items || data.items || []); + let currentPage = $state(data.items?.page || 1); + let pageSize = $state(data.items?.pageSize || data.items?.page_size || 50); + let totalItems = $state(data.items?.total || 0); + let loading = $state(false); + let hasMore = $derived(allItems.length < totalItems); + + $effect(() => { + if (data.items?.items) { + allItems = data.items.items || []; + currentPage = data.items.page || 1; + totalItems = data.items.total || 0; + pageSize = data.items.pageSize || data.items.page_size || pageSize; + } + }); + + async function handleSearch() { if (!browser) return; clearTimeout(timeout); - timeout = setTimeout(() => { + timeout = setTimeout(async () => { + if (!companyStore.activeCompany) return; + loading = true; + error = null; + try { + const params: Record = { + page: '1', + page_size: pageSize.toString() + }; + if (searchCode) params.port_code = searchCode; + if (searchDesc) params.description = searchDesc; + + const response = await portsApi.list(companyStore.activeCompany.id, params); + if (response.data?.items) { + allItems = response.data.items; + currentPage = response.data.page || 1; + totalItems = response.data.total || 0; + } + } catch (err) { + error = 'Error aplicando filtros'; + console.error('Error applying filters:', err); + } finally { + loading = false; + } + const url = new URL($page.url); if (searchCode) url.searchParams.set('port_code', searchCode); else url.searchParams.delete('port_code'); @@ -41,58 +85,117 @@ if (searchDesc) url.searchParams.set('description', searchDesc); else url.searchParams.delete('description'); - url.searchParams.set('page', '1'); - goto(url, { keepFocus: true, noScroll: true }); + history.replaceState(history.state, '', url); }, 500); } + async function loadMore() { + if (loading || !hasMore || !companyStore.activeCompany) return; + loading = true; + error = null; + try { + const params: Record = { + page: (currentPage + 1).toString(), + page_size: pageSize.toString() + }; + if (searchCode) params.port_code = searchCode; + if (searchDesc) params.description = searchDesc; + + const response = await portsApi.list(companyStore.activeCompany.id, params); + if (response.data?.items) { + allItems = [...allItems, ...response.data.items]; + currentPage += 1; + totalItems = response.data.total || 0; + } + } catch (err) { + error = 'Error cargando mas datos'; + console.error('Error loading more ports:', err); + } finally { + loading = false; + } + } + + async function reloadData() { + if (!companyStore.activeCompany) return; + loading = true; + error = null; + try { + const params: Record = { + page: '1', + page_size: pageSize.toString() + }; + if (searchCode) params.port_code = searchCode; + if (searchDesc) params.description = searchDesc; + + const response = await portsApi.list(companyStore.activeCompany.id, params); + if (response.data?.items) { + allItems = response.data.items; + currentPage = response.data.page || 1; + totalItems = response.data.total || 0; + } + } catch (err) { + error = 'Error al recargar datos'; + console.error('Error reloading ports:', err); + } finally { + loading = false; + } + } + function handleSuccess() { - const url = new URL($page.url); - goto(url, { invalidateAll: true }); + reloadData(); } -
+

Puertos

Catálogo de puertos

- +
+ + +
- {#if data.items?.error} + {#if error}
- {data.items.error} + {error}
{/if} -
-
- -
-
- -
-
+ + +
+ Listado de Puertos +
+ + +
+
+
+ +
+ +
+
+
-
- -
+
Mostrando {allItems.length} de {totalItems} registros
diff --git a/frontend/src/routes/dashboard/general_catalogs/prevalidators/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/prevalidators/+page.svelte index 81899bfd..fd4ed81e 100644 --- a/frontend/src/routes/dashboard/general_catalogs/prevalidators/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/prevalidators/+page.svelte @@ -2,17 +2,21 @@ import { goto } from '$app/navigation'; import { page } from '$app/stores'; import { browser } from '$app/environment'; + import * as Card from '$lib/components/ui/card'; import { Button } from '$lib/components/ui/button'; import { Input } from '$lib/components/ui/input'; - import { Plus } from 'lucide-svelte'; - import DataTable from '$lib/components/dashboard/general_catalogs/prevalidators/data-table.svelte'; + import { Plus, RefreshCw } from 'lucide-svelte'; + import InfiniteDataTable from '$lib/components/dashboard/common/infinite-data-table.svelte'; import { createColumns } from '$lib/components/dashboard/general_catalogs/prevalidators/columns'; import CreateEditDialog from '$lib/components/dashboard/general_catalogs/prevalidators/create-edit-dialog.svelte'; import { useShortcuts } from '$lib/hooks/use-shortcuts'; import { obtenerAtajosListaPrevalidadores } from '$lib/config/shortcuts/dashboard/general_catalogs/prevalidators/list'; + import { getPrevalidators } from '$lib/api/dashboard/a76/general_catalogs/prevalidators'; + import { companyStore } from '$lib/stores/company.svelte'; let { data } = $props(); let dialogOpen = $state(false); + let error = $state(data.error || null); // Atajos useShortcuts( @@ -27,15 +31,47 @@ let searchDesc = $state($page.url.searchParams.get('description') || ''); let timeout: ReturnType; - function handleSuccess() { - const url = new URL($page.url); - goto(url, { invalidateAll: true }); - } + let allItems = $state(data.prevalidators?.items || []); + let currentPage = $state(data.prevalidators?.page || 1); + let pageSize = $state(data.prevalidators?.page_size || 50); + let totalItems = $state(data.prevalidators?.total || 0); + let loading = $state(false); + let hasMore = $derived(allItems.length < totalItems); - function handleSearch() { + $effect(() => { + if (data.prevalidators) { + allItems = data.prevalidators.items || []; + currentPage = data.prevalidators.page || 1; + totalItems = data.prevalidators.total || 0; + pageSize = data.prevalidators.page_size || pageSize; + } + }); + + async function handleSearch() { if (!browser) return; clearTimeout(timeout); - timeout = setTimeout(() => { + timeout = setTimeout(async () => { + if (!companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchCode) filters.code = searchCode; + if (searchDesc) filters.description = searchDesc; + + const response = await getPrevalidators(1, pageSize, filters, companyStore.activeCompany.id); + if (response?.items) { + allItems = response.items; + currentPage = 1; + totalItems = response.total; + } + } catch (err) { + error = 'Error aplicando filtros'; + console.error('Error applying filters:', err); + } finally { + loading = false; + } + const url = new URL($page.url); if (searchCode) url.searchParams.set('code', searchCode); else url.searchParams.delete('code'); @@ -43,45 +79,98 @@ if (searchDesc) url.searchParams.set('description', searchDesc); else url.searchParams.delete('description'); - url.searchParams.set('page', '1'); - goto(url, { keepFocus: true, noScroll: true }); + history.replaceState(history.state, '', url); }, 500); } + + async function loadMore() { + if (loading || !hasMore || !companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchCode) filters.code = searchCode; + if (searchDesc) filters.description = searchDesc; + + const response = await getPrevalidators( + currentPage + 1, + pageSize, + filters, + companyStore.activeCompany.id + ); + if (response?.items) { + allItems = [...allItems, ...response.items]; + currentPage += 1; + totalItems = response.total; + } + } catch (err) { + error = 'Error cargando mas datos'; + console.error('Error loading more prevalidators:', err); + } finally { + loading = false; + } + } + + async function reloadData() { + if (!companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchCode) filters.code = searchCode; + if (searchDesc) filters.description = searchDesc; + + const response = await getPrevalidators(1, pageSize, filters, companyStore.activeCompany.id); + if (response?.items) { + allItems = response.items; + currentPage = 1; + totalItems = response.total; + } + } catch (err) { + error = 'Error al recargar datos'; + console.error('Error reloading prevalidators:', err); + } finally { + loading = false; + } + } + + function handleSuccess() { + reloadData(); + } -
+

Prevalidadores

Catálogo de prevalidadores

- -
- -
-
- -
-
- +
+ +
-
- -
+ {#if error} +
+ {error} +
+ {/if} + + + +
+ Listado de Prevalidadores +
+ + +
+
+
+
+
+ +
Mostrando {allItems.length} de {totalItems} registros
diff --git a/frontend/src/routes/dashboard/general_catalogs/seal/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/seal/+page.svelte index 562bb586..fac039f8 100644 --- a/frontend/src/routes/dashboard/general_catalogs/seal/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/seal/+page.svelte @@ -1,8 +1,9 @@ -
-
+
+

Sellos

Gestiona los sellos de tu empresa

- +
+ + +
{#if error} -
+

{error}

{/if} -
-
- -
-
+ + +
+ Listado de Sellos +
+ +
+
+
+ +
+ +
+
+
-
- +
+ Mostrando {allItems.length} de {totalItems || allItems.length} registros
diff --git a/frontend/src/routes/dashboard/general_catalogs/signatures/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/signatures/+page.svelte index 34af6e59..a0e46d78 100644 --- a/frontend/src/routes/dashboard/general_catalogs/signatures/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/signatures/+page.svelte @@ -4,15 +4,19 @@ import { browser } from '$app/environment'; import { Button } from '$lib/components/ui/button'; import { Input } from '$lib/components/ui/input'; - import { Plus } from 'lucide-svelte'; - import DataTable from '$lib/components/dashboard/general_catalogs/signatures/data-table.svelte'; + import * as Card from '$lib/components/ui/card'; + import { Plus, RefreshCw } from 'lucide-svelte'; + import InfiniteDataTable from '$lib/components/dashboard/common/infinite-data-table.svelte'; import { createColumns } from '$lib/components/dashboard/general_catalogs/signatures/columns'; import CreateEditDialog from '$lib/components/dashboard/general_catalogs/signatures/create-edit-dialog.svelte'; import { useShortcuts } from '$lib/hooks/use-shortcuts'; import { obtenerAtajosListaFirmas } from '$lib/config/shortcuts/dashboard/general_catalogs/signatures/list'; + import { getSignatures } from '$lib/api/dashboard/a76/general_catalogs/signatures'; + import { companyStore } from '$lib/stores/company.svelte'; let { data } = $props(); let dialogOpen = $state(false); + let error = $state(data.error || null); // Atajos useShortcuts( @@ -26,50 +30,138 @@ let searchCode = $state($page.url.searchParams.get('code') || ''); let timeout: ReturnType; - function handleSuccess() { - const url = new URL($page.url); - goto(url, { invalidateAll: true }); - } + let allItems = $state(data.signatures?.items || []); + let currentPage = $state(data.signatures?.page || 1); + let pageSize = $state(data.signatures?.page_size || 50); + let totalItems = $state(data.signatures?.total || 0); + let loading = $state(false); + let hasMore = $derived(allItems.length < totalItems); - function handleSearch() { + $effect(() => { + if (data.signatures) { + allItems = data.signatures.items || []; + currentPage = data.signatures.page || 1; + totalItems = data.signatures.total || 0; + pageSize = data.signatures.page_size || pageSize; + } + }); + + async function handleSearch() { if (!browser) return; clearTimeout(timeout); - timeout = setTimeout(() => { + timeout = setTimeout(async () => { + if (!companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchCode) filters.code = searchCode; + + const response = await getSignatures( + 1, + pageSize, + companyStore.activeCompany.id, + filters + ); + if (response?.items) { + allItems = response.items; + currentPage = 1; + totalItems = response.total; + } + } catch (err) { + error = 'Error aplicando filtros'; + console.error('Error applying filters:', err); + } finally { + loading = false; + } + const url = new URL($page.url); if (searchCode) url.searchParams.set('code', searchCode); else url.searchParams.delete('code'); - url.searchParams.set('page', '1'); - goto(url, { keepFocus: true, noScroll: true }); + history.replaceState(history.state, '', url); }, 500); } + + async function loadMore() { + if (loading || !hasMore || !companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchCode) filters.code = searchCode; + + const response = await getSignatures( + currentPage + 1, + pageSize, + companyStore.activeCompany.id, + filters + ); + if (response?.items) { + allItems = [...allItems, ...response.items]; + currentPage += 1; + totalItems = response.total; + } + } catch (err) { + error = 'Error cargando mas datos'; + console.error('Error loading more signatures:', err); + } finally { + loading = false; + } + } + + async function reloadData() { + if (!companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchCode) filters.code = searchCode; + + const response = await getSignatures( + 1, + pageSize, + companyStore.activeCompany.id, + filters + ); + if (response?.items) { + allItems = response.items; + currentPage = 1; + totalItems = response.total; + } + } catch (err) { + error = 'Error al recargar datos'; + console.error('Error reloading signatures:', err); + } finally { + loading = false; + } + } + + function handleSuccess() { + reloadData(); + } -
+

Firmas Electrónicas

Gestión del catálogo de firmas electrónicas

- +
-
-
- + {#if error} +
+ {error}
-
+ {/if} -
- -
+ +
Listado de Firmas
+
+
+ +
Mostrando {allItems.length} de {totalItems} registros
diff --git a/frontend/src/routes/dashboard/general_catalogs/tariff-fractions/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/tariff-fractions/+page.svelte index 9ad3119a..8fc9313b 100644 --- a/frontend/src/routes/dashboard/general_catalogs/tariff-fractions/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/tariff-fractions/+page.svelte @@ -89,145 +89,100 @@ } -
- - - - Catálogo de Fracciones SITAR - SCAII - -

Nomenclatura arancelaria mexicana completa

+
+
+
+

Catálogo de Fracciones SITAR - SCAII

+

Nomenclatura arancelaria mexicana completa

+
+ +
+ + + +
+ Listado de Fracciones +
+ + +
+
- - -
- -
-
- - -
- -
- - -
-
- {#if isLoading} -
- - Cargando... -
- {:else} - Mostrando {tariffFractions.length} de {totalRecords} fracciones arancelarias - {#if searchQuery} - (filtrado) - {/if} - {/if} -
- {#if totalPages > 1} -
- Página {currentPage} de {totalPages} -
- {/if} -
- - -
- - + +
+ + + + Código + Fracción + Descripción + NICO + UMT + Adv. Impo + Adv. Expo + + + + {#if tariffFractions.length === 0} - Código - Fracción - Descripción - NICO - UMT - Adv. Impo - Adv. Expo + + {#if isLoading} + Cargando fracciones arancelarias... + {:else if searchQuery} + No se encontraron fracciones que coincidan con la búsqueda + {:else} + No hay fracciones arancelarias disponibles + {/if} + - - - {#if tariffFractions.length === 0} - - - {#if isLoading} - Cargando fracciones arancelarias... - {:else if searchQuery} - No se encontraron fracciones que coincidan con la búsqueda - {:else} - No hay fracciones arancelarias disponibles - {/if} - + {:else} + {#each tariffFractions as fraction (fraction.id)} + + {fraction.code} + {fraction.fraction} + {fraction.description || '-'} + {fraction.nico || '-'} + {fraction.umt || '-'} + {fraction.adv_impo || '-'} + {fraction.adv_expo || '-'} - {:else} - {#each tariffFractions as fraction (fraction.id)} - - {fraction.code} - {fraction.fraction} - - {fraction.description || '-'} - - {fraction.nico || '-'} - {fraction.umt || '-'} - {fraction.adv_impo || '-'} - {fraction.adv_expo || '-'} - - {/each} - {/if} - - -
- - - {#if totalPages > 1} -
- - - - Página {currentPage} de {totalPages} - - - -
- {/if} + {/each} + {/if} + +
+ +
+ Mostrando {tariffFractions.length} de {totalRecords} fracciones arancelarias + {#if searchQuery} + + Filtrado + {/if} +
+ + {#if totalPages > 1} +
+ + + + +
+ {/if}
diff --git a/frontend/src/routes/dashboard/general_catalogs/tariff-fractions/canadian/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/tariff-fractions/canadian/+page.svelte index 5a67d55e..63fab84b 100644 --- a/frontend/src/routes/dashboard/general_catalogs/tariff-fractions/canadian/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/tariff-fractions/canadian/+page.svelte @@ -3,9 +3,15 @@ import * as m from '$lib/paraglide/messages.js'; -
-
-

{m['sidebar.fractions.canadian']()}

+
+
+
+

{m['sidebar.fractions.canadian']()}

+

Catálogo de fracciones arancelarias canadienses

+
+
+ +
+
-
diff --git a/frontend/src/routes/dashboard/general_catalogs/trailers/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/trailers/+page.svelte index 596c3d13..0331dc38 100644 --- a/frontend/src/routes/dashboard/general_catalogs/trailers/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/trailers/+page.svelte @@ -1,12 +1,13 @@ -
+
-

Trailers

+

Trailers

Gestión del catálogo de trailers de la compañía

- +
-
- - -
+ +
Listado de Trailers
+ {#if loading && data.length === 0}
Cargando trailers...
{:else}
{/if}
+
- {#if loading && data.length === 0} -
- Cargando trailers... -
- {:else} - - {/if} +
Mostrando {data.length} de {totalItems} registros
diff --git a/frontend/src/routes/dashboard/general_catalogs/transporters/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/transporters/+page.svelte index 150e006b..f14bf171 100644 --- a/frontend/src/routes/dashboard/general_catalogs/transporters/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/transporters/+page.svelte @@ -1,12 +1,13 @@ -
+
-

Transportistas

+

Transportistas

Gestión del catálogo de líneas transportistas

- +
-
- - -
+ +
Listado de Transportistas
+ {#if loading && data.length === 0}
Cargando transportistas...
{:else}
{/if}
+
- {#if loading && data.length === 0} -
- Cargando transportistas... -
- {:else} - - {/if} +
Mostrando {data.length} de {totalItems} registros
diff --git a/frontend/src/routes/dashboard/general_catalogs/unit_conversions/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/unit_conversions/+page.svelte index bc274ff2..ea00c786 100644 --- a/frontend/src/routes/dashboard/general_catalogs/unit_conversions/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/unit_conversions/+page.svelte @@ -4,17 +4,21 @@ import { browser } from '$app/environment'; import { createColumns } from '$lib/components/dashboard/general_catalogs/unit_conversions/columns'; import CreateEditDialog from '$lib/components/dashboard/general_catalogs/unit_conversions/create-edit-dialog.svelte'; - import DataTable from '$lib/components/dashboard/general_catalogs/unit_conversions/data-table.svelte'; + import InfiniteDataTable from '$lib/components/dashboard/common/infinite-data-table.svelte'; + import * as Card from '$lib/components/ui/card'; import { Button } from '$lib/components/ui/button'; import { Input } from '$lib/components/ui/input'; - import { Plus } from 'lucide-svelte'; + import { Plus, RefreshCw } from 'lucide-svelte'; import type { PageData } from './$types'; import { useShortcuts } from '$lib/hooks/use-shortcuts'; import { obtenerAtajosListaConversiones } from '$lib/config/shortcuts/dashboard/general_catalogs/unit_conversions/list'; + import { getUnitConversions } from '$lib/api/dashboard/a76/general_catalogs/unit-conversions'; + import { companyStore } from '$lib/stores/company.svelte'; let { data }: { data: PageData } = $props(); let createDialogOpen = $state(false); + let error = $state(data.error || null); // Atajos useShortcuts( @@ -30,10 +34,52 @@ let searchTo = $state($page.url.searchParams.get('to_unit_code') || ''); let timeout: ReturnType; - function handleSearch() { + let allItems = $state(data.conversions?.items || []); + let currentPage = $state(data.conversions?.page || 1); + let pageSize = $state(data.conversions?.page_size || 50); + let totalItems = $state(data.conversions?.total || 0); + let loading = $state(false); + let hasMore = $derived(allItems.length < totalItems); + + $effect(() => { + if (data.conversions) { + allItems = data.conversions.items || []; + currentPage = data.conversions.page || 1; + totalItems = data.conversions.total || 0; + pageSize = data.conversions.page_size || pageSize; + } + }); + + async function handleSearch() { if (!browser) return; clearTimeout(timeout); - timeout = setTimeout(() => { + timeout = setTimeout(async () => { + if (!companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchFrom) filters.from_unit_code = searchFrom; + if (searchTo) filters.to_unit_code = searchTo; + + const response = await getUnitConversions( + 1, + pageSize, + companyStore.activeCompany.id, + filters + ); + if (response?.items) { + allItems = response.items; + currentPage = 1; + totalItems = response.total; + } + } catch (err) { + error = 'Error aplicando filtros'; + console.error('Error applying filters:', err); + } finally { + loading = false; + } + const url = new URL($page.url); if (searchFrom) url.searchParams.set('from_unit_code', searchFrom); else url.searchParams.delete('from_unit_code'); @@ -41,46 +87,92 @@ if (searchTo) url.searchParams.set('to_unit_code', searchTo); else url.searchParams.delete('to_unit_code'); - url.searchParams.set('page', '1'); - goto(url, { keepFocus: true, noScroll: true }); + history.replaceState(history.state, '', url); }, 500); } + async function loadMore() { + if (loading || !hasMore || !companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchFrom) filters.from_unit_code = searchFrom; + if (searchTo) filters.to_unit_code = searchTo; + + const response = await getUnitConversions( + currentPage + 1, + pageSize, + companyStore.activeCompany.id, + filters + ); + if (response?.items) { + allItems = [...allItems, ...response.items]; + currentPage += 1; + totalItems = response.total; + } + } catch (err) { + error = 'Error cargando mas datos'; + console.error('Error loading more unit conversions:', err); + } finally { + loading = false; + } + } + + async function reloadData() { + if (!companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchFrom) filters.from_unit_code = searchFrom; + if (searchTo) filters.to_unit_code = searchTo; + + const response = await getUnitConversions( + 1, + pageSize, + companyStore.activeCompany.id, + filters + ); + if (response?.items) { + allItems = response.items; + currentPage = 1; + totalItems = response.total; + } + } catch (err) { + error = 'Error al recargar datos'; + console.error('Error reloading unit conversions:', err); + } finally { + loading = false; + } + } + function handleSuccess() { - const url = new URL($page.url); - goto(url, { invalidateAll: true }); + reloadData(); } -
+

Conversiones de Unidades

Catálogo de conversiones de unidades de medida

- +
-
-
- + {#if error} +
+ {error}
-
- -
-
+ {/if} -
- -
+ +
Listado de Conversiones
+
+
+ +
Mostrando {allItems.length} de {totalItems} registros
diff --git a/frontend/src/routes/dashboard/general_catalogs/units_of_measure/ace/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/units_of_measure/ace/+page.svelte index 664840ef..a4bc68fb 100644 --- a/frontend/src/routes/dashboard/general_catalogs/units_of_measure/ace/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/units_of_measure/ace/+page.svelte @@ -4,17 +4,21 @@ import { browser } from '$app/environment'; import { createColumns } from '$lib/components/dashboard/general_catalogs/units_of_measure/ace/columns'; import CreateEditDialog from '$lib/components/dashboard/general_catalogs/units_of_measure/ace/create-edit-dialog.svelte'; - import DataTable from '$lib/components/dashboard/general_catalogs/units_of_measure/ace/data-table.svelte'; + import InfiniteDataTable from '$lib/components/dashboard/common/infinite-data-table.svelte'; + import * as Card from '$lib/components/ui/card'; import { Button } from '$lib/components/ui/button'; import { Input } from '$lib/components/ui/input'; - import { Plus } from 'lucide-svelte'; + import { Plus, RefreshCw } from 'lucide-svelte'; import type { PageData } from './$types'; import { useShortcuts } from '$lib/hooks/use-shortcuts'; import { obtenerAtajosListaUnidadesACE } from '$lib/config/shortcuts/dashboard/general_catalogs/units_of_measure/ace/list'; + import { getUnitsOfMeasureACE } from '$lib/api/dashboard/a76/general_catalogs/units-of-measure'; + import { companyStore } from '$lib/stores/company.svelte'; let { data }: { data: PageData } = $props(); let createDialogOpen = $state(false); + let error = $state(data.error || null); // Atajos useShortcuts( @@ -30,10 +34,52 @@ let searchDesc = $state($page.url.searchParams.get('description') || ''); let timeout: ReturnType; - function handleSearch() { + let allItems = $state(data.ace_units?.items || []); + let currentPage = $state(data.ace_units?.page || 1); + let pageSize = $state(data.ace_units?.page_size || 50); + let totalItems = $state(data.ace_units?.total || 0); + let loading = $state(false); + let hasMore = $derived(allItems.length < totalItems); + + $effect(() => { + if (data.ace_units) { + allItems = data.ace_units.items || []; + currentPage = data.ace_units.page || 1; + totalItems = data.ace_units.total || 0; + pageSize = data.ace_units.page_size || pageSize; + } + }); + + async function handleSearch() { if (!browser) return; clearTimeout(timeout); - timeout = setTimeout(() => { + timeout = setTimeout(async () => { + if (!companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchCode) filters.code = searchCode; + if (searchDesc) filters.description = searchDesc; + + const response = await getUnitsOfMeasureACE( + 1, + pageSize, + companyStore.activeCompany.id, + filters + ); + if (response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (err) { + error = 'Error aplicando filtros'; + console.error('Error applying filters:', err); + } finally { + loading = false; + } + const url = new URL($page.url); if (searchCode) url.searchParams.set('code', searchCode); else url.searchParams.delete('code'); @@ -41,50 +87,92 @@ if (searchDesc) url.searchParams.set('description', searchDesc); else url.searchParams.delete('description'); - url.searchParams.set('page', '1'); - goto(url, { keepFocus: true, noScroll: true }); + history.replaceState(history.state, '', url); }, 500); } + async function loadMore() { + if (loading || !hasMore || !companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchCode) filters.code = searchCode; + if (searchDesc) filters.description = searchDesc; + + const response = await getUnitsOfMeasureACE( + currentPage + 1, + pageSize, + companyStore.activeCompany.id, + filters + ); + if (response.data?.items) { + allItems = [...allItems, ...response.data.items]; + currentPage += 1; + totalItems = response.data.total; + } + } catch (err) { + error = 'Error cargando mas datos'; + console.error('Error loading more ACE units:', err); + } finally { + loading = false; + } + } + + async function reloadData() { + if (!companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchCode) filters.code = searchCode; + if (searchDesc) filters.description = searchDesc; + + const response = await getUnitsOfMeasureACE( + 1, + pageSize, + companyStore.activeCompany.id, + filters + ); + if (response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (err) { + error = 'Error al recargar datos'; + console.error('Error reloading ACE units:', err); + } finally { + loading = false; + } + } + function handleSuccess() { - const url = new URL($page.url); - goto(url, { invalidateAll: true }); + reloadData(); } -
+

Unidades de Medida ACE

Catálogo de unidades de medida ACE

- +
-
-
- + {#if error} +
+ {error}
-
- -
-
+ {/if} -
- -
+ +
Listado de Unidades ACE
+
+
+ +
Mostrando {allItems.length} de {totalItems} registros
diff --git a/frontend/src/routes/dashboard/general_catalogs/units_of_measure/american/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/units_of_measure/american/+page.svelte index 41f27a3f..38bfedf3 100644 --- a/frontend/src/routes/dashboard/general_catalogs/units_of_measure/american/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/units_of_measure/american/+page.svelte @@ -3,18 +3,22 @@ import { goto } from '$app/navigation'; import { browser } from '$app/environment'; import { createColumns } from '$lib/components/dashboard/general_catalogs/units_of_measure/american/columns'; - import DataTable from '$lib/components/dashboard/general_catalogs/units_of_measure/american/data-table.svelte'; + import InfiniteDataTable from '$lib/components/dashboard/common/infinite-data-table.svelte'; import CreateEditDialog from '$lib/components/dashboard/general_catalogs/units_of_measure/american/create-edit-dialog.svelte'; + import * as Card from '$lib/components/ui/card'; import { Button } from '$lib/components/ui/button'; import { Input } from '$lib/components/ui/input'; - import { Plus } from 'lucide-svelte'; + import { Plus, RefreshCw } from 'lucide-svelte'; import type { PageData } from './$types'; import { useShortcuts } from '$lib/hooks/use-shortcuts'; import { obtenerAtajosListaUnidadesAmericanas } from '$lib/config/shortcuts/dashboard/general_catalogs/units_of_measure/american/list'; + import { getUnitsOfMeasureAmerican } from '$lib/api/dashboard/a76/general_catalogs/units-of-measure'; + import { companyStore } from '$lib/stores/company.svelte'; let { data }: { data: PageData } = $props(); let createDialogOpen = $state(false); + let error = $state(data.error || null); // Atajos useShortcuts( @@ -30,10 +34,52 @@ let searchDesc = $state($page.url.searchParams.get('description') || ''); let timeout: ReturnType; - function handleSearch() { + let allItems = $state(data.american_units?.items || []); + let currentPage = $state(data.american_units?.page || 1); + let pageSize = $state(data.american_units?.page_size || 50); + let totalItems = $state(data.american_units?.total || 0); + let loading = $state(false); + let hasMore = $derived(allItems.length < totalItems); + + $effect(() => { + if (data.american_units) { + allItems = data.american_units.items || []; + currentPage = data.american_units.page || 1; + totalItems = data.american_units.total || 0; + pageSize = data.american_units.page_size || pageSize; + } + }); + + async function handleSearch() { if (!browser) return; clearTimeout(timeout); - timeout = setTimeout(() => { + timeout = setTimeout(async () => { + if (!companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchCode) filters.code = searchCode; + if (searchDesc) filters.description = searchDesc; + + const response = await getUnitsOfMeasureAmerican( + 1, + pageSize, + companyStore.activeCompany.id, + filters + ); + if (response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (err) { + error = 'Error aplicando filtros'; + console.error('Error applying filters:', err); + } finally { + loading = false; + } + const url = new URL($page.url); if (searchCode) url.searchParams.set('code', searchCode); else url.searchParams.delete('code'); @@ -41,50 +87,92 @@ if (searchDesc) url.searchParams.set('description', searchDesc); else url.searchParams.delete('description'); - url.searchParams.set('page', '1'); - goto(url, { keepFocus: true, noScroll: true }); + history.replaceState(history.state, '', url); }, 500); } + async function loadMore() { + if (loading || !hasMore || !companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchCode) filters.code = searchCode; + if (searchDesc) filters.description = searchDesc; + + const response = await getUnitsOfMeasureAmerican( + currentPage + 1, + pageSize, + companyStore.activeCompany.id, + filters + ); + if (response.data?.items) { + allItems = [...allItems, ...response.data.items]; + currentPage += 1; + totalItems = response.data.total; + } + } catch (err) { + error = 'Error cargando mas datos'; + console.error('Error loading more American units:', err); + } finally { + loading = false; + } + } + + async function reloadData() { + if (!companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchCode) filters.code = searchCode; + if (searchDesc) filters.description = searchDesc; + + const response = await getUnitsOfMeasureAmerican( + 1, + pageSize, + companyStore.activeCompany.id, + filters + ); + if (response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (err) { + error = 'Error al recargar datos'; + console.error('Error reloading American units:', err); + } finally { + loading = false; + } + } + function handleSuccess() { - const url = new URL($page.url); - goto(url, { invalidateAll: true }); + reloadData(); } -
+

Unidades de Medida Americanas

Catálogo de unidades de medida Americanas

- +
-
-
- + {#if error} +
+ {error}
-
- -
-
+ {/if} -
- -
+ +
Listado de Unidades Americanas
+
+
+ +
Mostrando {allItems.length} de {totalItems} registros
diff --git a/frontend/src/routes/dashboard/general_catalogs/units_of_measure/customs/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/units_of_measure/customs/+page.svelte index 671625b1..e8e8fe79 100644 --- a/frontend/src/routes/dashboard/general_catalogs/units_of_measure/customs/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/units_of_measure/customs/+page.svelte @@ -3,18 +3,22 @@ import { goto } from '$app/navigation'; import { browser } from '$app/environment'; import { createColumns } from '$lib/components/dashboard/general_catalogs/units_of_measure/customs/columns'; - import DataTable from '$lib/components/dashboard/general_catalogs/units_of_measure/customs/data-table.svelte'; + import InfiniteDataTable from '$lib/components/dashboard/common/infinite-data-table.svelte'; import CreateEditDialog from '$lib/components/dashboard/general_catalogs/units_of_measure/customs/create-edit-dialog.svelte'; + import * as Card from '$lib/components/ui/card'; import { Button } from '$lib/components/ui/button'; import { Input } from '$lib/components/ui/input'; - import { Plus } from 'lucide-svelte'; + import { Plus, RefreshCw } from 'lucide-svelte'; import type { PageData } from './$types'; import { useShortcuts } from '$lib/hooks/use-shortcuts'; import { obtenerAtajosListaUnidadesAduanas } from '$lib/config/shortcuts/dashboard/general_catalogs/units_of_measure/customs/list'; + import { getUnitsOfMeasureCustoms } from '$lib/api/dashboard/a76/general_catalogs/units-of-measure'; + import { companyStore } from '$lib/stores/company.svelte'; let { data }: { data: PageData } = $props(); let createDialogOpen = $state(false); + let error = $state(data.error || null); // Atajos useShortcuts( @@ -30,10 +34,52 @@ let searchDesc = $state($page.url.searchParams.get('description') || ''); let timeout: ReturnType; - function handleSearch() { + let allItems = $state(data.customs_units?.items || []); + let currentPage = $state(data.customs_units?.page || 1); + let pageSize = $state(data.customs_units?.page_size || 50); + let totalItems = $state(data.customs_units?.total || 0); + let loading = $state(false); + let hasMore = $derived(allItems.length < totalItems); + + $effect(() => { + if (data.customs_units) { + allItems = data.customs_units.items || []; + currentPage = data.customs_units.page || 1; + totalItems = data.customs_units.total || 0; + pageSize = data.customs_units.page_size || pageSize; + } + }); + + async function handleSearch() { if (!browser) return; clearTimeout(timeout); - timeout = setTimeout(() => { + timeout = setTimeout(async () => { + if (!companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchCode) filters.code = searchCode; + if (searchDesc) filters.description = searchDesc; + + const response = await getUnitsOfMeasureCustoms( + 1, + pageSize, + companyStore.activeCompany.id, + filters + ); + if (response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (err) { + error = 'Error aplicando filtros'; + console.error('Error applying filters:', err); + } finally { + loading = false; + } + const url = new URL($page.url); if (searchCode) url.searchParams.set('code', searchCode); else url.searchParams.delete('code'); @@ -41,50 +87,92 @@ if (searchDesc) url.searchParams.set('description', searchDesc); else url.searchParams.delete('description'); - url.searchParams.set('page', '1'); - goto(url, { keepFocus: true, noScroll: true }); + history.replaceState(history.state, '', url); }, 500); } + async function loadMore() { + if (loading || !hasMore || !companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchCode) filters.code = searchCode; + if (searchDesc) filters.description = searchDesc; + + const response = await getUnitsOfMeasureCustoms( + currentPage + 1, + pageSize, + companyStore.activeCompany.id, + filters + ); + if (response.data?.items) { + allItems = [...allItems, ...response.data.items]; + currentPage += 1; + totalItems = response.data.total; + } + } catch (err) { + error = 'Error cargando mas datos'; + console.error('Error loading more customs units:', err); + } finally { + loading = false; + } + } + + async function reloadData() { + if (!companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchCode) filters.code = searchCode; + if (searchDesc) filters.description = searchDesc; + + const response = await getUnitsOfMeasureCustoms( + 1, + pageSize, + companyStore.activeCompany.id, + filters + ); + if (response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (err) { + error = 'Error al recargar datos'; + console.error('Error reloading customs units:', err); + } finally { + loading = false; + } + } + function handleSuccess() { - const url = new URL($page.url); - goto(url, { invalidateAll: true }); + reloadData(); } -
+

Unidades de Medida Aduanas MEX

Catálogo de unidades de medida para aduanas mexicanas

- +
-
-
- + {#if error} +
+ {error}
-
- -
-
+ {/if} -
- -
+ +
Listado de Unidades Aduanas MX
+
+
+ +
Mostrando {allItems.length} de {totalItems} registros
diff --git a/frontend/src/routes/dashboard/general_catalogs/units_of_measure/general/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/units_of_measure/general/+page.svelte index 92a5cdd1..00f06498 100644 --- a/frontend/src/routes/dashboard/general_catalogs/units_of_measure/general/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/units_of_measure/general/+page.svelte @@ -3,18 +3,22 @@ import { goto } from '$app/navigation'; import { browser } from '$app/environment'; import { createColumns } from '$lib/components/dashboard/general_catalogs/units_of_measure/general/columns'; - import DataTable from '$lib/components/dashboard/general_catalogs/units_of_measure/general/data-table.svelte'; + import InfiniteDataTable from '$lib/components/dashboard/common/infinite-data-table.svelte'; import CreateEditDialog from '$lib/components/dashboard/general_catalogs/units_of_measure/general/create-edit-dialog.svelte'; + import * as Card from '$lib/components/ui/card'; import { Button } from '$lib/components/ui/button'; import { Input } from '$lib/components/ui/input'; - import { Plus } from 'lucide-svelte'; + import { Plus, RefreshCw } from 'lucide-svelte'; import type { PageData } from './$types'; import { useShortcuts } from '$lib/hooks/use-shortcuts'; import { obtenerAtajosListaUnidadesGeneral } from '$lib/config/shortcuts/dashboard/general_catalogs/units_of_measure/general/list'; + import { getUnitsOfMeasureGeneral } from '$lib/api/dashboard/a76/general_catalogs/units-of-measure'; + import { companyStore } from '$lib/stores/company.svelte'; let { data }: { data: PageData } = $props(); let createDialogOpen = $state(false); + let error = $state(data.error || null); // Atajos useShortcuts( @@ -30,10 +34,52 @@ let searchDesc = $state($page.url.searchParams.get('description') || ''); let timeout: ReturnType; - function handleSearch() { + let allItems = $state(data.general_units?.items || []); + let currentPage = $state(data.general_units?.page || 1); + let pageSize = $state(data.general_units?.page_size || 50); + let totalItems = $state(data.general_units?.total || 0); + let loading = $state(false); + let hasMore = $derived(allItems.length < totalItems); + + $effect(() => { + if (data.general_units) { + allItems = data.general_units.items || []; + currentPage = data.general_units.page || 1; + totalItems = data.general_units.total || 0; + pageSize = data.general_units.page_size || pageSize; + } + }); + + async function handleSearch() { if (!browser) return; clearTimeout(timeout); - timeout = setTimeout(() => { + timeout = setTimeout(async () => { + if (!companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchCode) filters.code = searchCode; + if (searchDesc) filters.description = searchDesc; + + const response = await getUnitsOfMeasureGeneral( + 1, + pageSize, + companyStore.activeCompany.id, + filters + ); + if (response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (err) { + error = 'Error aplicando filtros'; + console.error('Error applying filters:', err); + } finally { + loading = false; + } + const url = new URL($page.url); if (searchCode) url.searchParams.set('code', searchCode); else url.searchParams.delete('code'); @@ -41,50 +87,92 @@ if (searchDesc) url.searchParams.set('description', searchDesc); else url.searchParams.delete('description'); - url.searchParams.set('page', '1'); - goto(url, { keepFocus: true, noScroll: true }); + history.replaceState(history.state, '', url); }, 500); } + async function loadMore() { + if (loading || !hasMore || !companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchCode) filters.code = searchCode; + if (searchDesc) filters.description = searchDesc; + + const response = await getUnitsOfMeasureGeneral( + currentPage + 1, + pageSize, + companyStore.activeCompany.id, + filters + ); + if (response.data?.items) { + allItems = [...allItems, ...response.data.items]; + currentPage += 1; + totalItems = response.data.total; + } + } catch (err) { + error = 'Error cargando mas datos'; + console.error('Error loading more general units:', err); + } finally { + loading = false; + } + } + + async function reloadData() { + if (!companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchCode) filters.code = searchCode; + if (searchDesc) filters.description = searchDesc; + + const response = await getUnitsOfMeasureGeneral( + 1, + pageSize, + companyStore.activeCompany.id, + filters + ); + if (response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (err) { + error = 'Error al recargar datos'; + console.error('Error reloading general units:', err); + } finally { + loading = false; + } + } + function handleSuccess() { - const url = new URL($page.url); - goto(url, { invalidateAll: true }); + reloadData(); } -
+

Unidades de Medida

Catálogo general de unidades de medida

- +
-
-
- + {#if error} +
+ {error}
-
- -
-
+ {/if} -
- -
+ +
Listado de Unidades
+
+
+ +
Mostrando {allItems.length} de {totalItems} registros
diff --git a/frontend/src/routes/dashboard/general_catalogs/units_of_measure/oma/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/units_of_measure/oma/+page.svelte index eab0d9a6..da28b5ba 100644 --- a/frontend/src/routes/dashboard/general_catalogs/units_of_measure/oma/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/units_of_measure/oma/+page.svelte @@ -3,18 +3,22 @@ import { goto } from '$app/navigation'; import { browser } from '$app/environment'; import { createColumns } from '$lib/components/dashboard/general_catalogs/units_of_measure/oma/columns'; - import DataTable from '$lib/components/dashboard/general_catalogs/units_of_measure/oma/data-table.svelte'; + import InfiniteDataTable from '$lib/components/dashboard/common/infinite-data-table.svelte'; import CreateEditDialog from '$lib/components/dashboard/general_catalogs/units_of_measure/oma/create-edit-dialog.svelte'; + import * as Card from '$lib/components/ui/card'; import { Button } from '$lib/components/ui/button'; import { Input } from '$lib/components/ui/input'; - import { Plus } from 'lucide-svelte'; + import { Plus, RefreshCw } from 'lucide-svelte'; import type { PageData } from './$types'; import { useShortcuts } from '$lib/hooks/use-shortcuts'; import { obtenerAtajosListaUnidadesOMA } from '$lib/config/shortcuts/dashboard/general_catalogs/units_of_measure/oma/list'; + import { getUnitsOfMeasureOMA } from '$lib/api/dashboard/a76/general_catalogs/units-of-measure'; + import { companyStore } from '$lib/stores/company.svelte'; let { data }: { data: PageData } = $props(); let createDialogOpen = $state(false); + let error = $state(data.error || null); // Atajos useShortcuts( @@ -30,10 +34,52 @@ let searchDesc = $state($page.url.searchParams.get('description') || ''); let timeout: ReturnType; - function handleSearch() { + let allItems = $state(data.oma_units?.items || []); + let currentPage = $state(data.oma_units?.page || 1); + let pageSize = $state(data.oma_units?.page_size || 50); + let totalItems = $state(data.oma_units?.total || 0); + let loading = $state(false); + let hasMore = $derived(allItems.length < totalItems); + + $effect(() => { + if (data.oma_units) { + allItems = data.oma_units.items || []; + currentPage = data.oma_units.page || 1; + totalItems = data.oma_units.total || 0; + pageSize = data.oma_units.page_size || pageSize; + } + }); + + async function handleSearch() { if (!browser) return; clearTimeout(timeout); - timeout = setTimeout(() => { + timeout = setTimeout(async () => { + if (!companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchCode) filters.code = searchCode; + if (searchDesc) filters.description = searchDesc; + + const response = await getUnitsOfMeasureOMA( + 1, + pageSize, + companyStore.activeCompany.id, + filters + ); + if (response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (err) { + error = 'Error aplicando filtros'; + console.error('Error applying filters:', err); + } finally { + loading = false; + } + const url = new URL($page.url); if (searchCode) url.searchParams.set('code', searchCode); else url.searchParams.delete('code'); @@ -41,50 +87,92 @@ if (searchDesc) url.searchParams.set('description', searchDesc); else url.searchParams.delete('description'); - url.searchParams.set('page', '1'); - goto(url, { keepFocus: true, noScroll: true }); + history.replaceState(history.state, '', url); }, 500); } + async function loadMore() { + if (loading || !hasMore || !companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchCode) filters.code = searchCode; + if (searchDesc) filters.description = searchDesc; + + const response = await getUnitsOfMeasureOMA( + currentPage + 1, + pageSize, + companyStore.activeCompany.id, + filters + ); + if (response.data?.items) { + allItems = [...allItems, ...response.data.items]; + currentPage += 1; + totalItems = response.data.total; + } + } catch (err) { + error = 'Error cargando mas datos'; + console.error('Error loading more OMA units:', err); + } finally { + loading = false; + } + } + + async function reloadData() { + if (!companyStore.activeCompany) return; + loading = true; + error = null; + try { + const filters: Record = {}; + if (searchCode) filters.code = searchCode; + if (searchDesc) filters.description = searchDesc; + + const response = await getUnitsOfMeasureOMA( + 1, + pageSize, + companyStore.activeCompany.id, + filters + ); + if (response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (err) { + error = 'Error al recargar datos'; + console.error('Error reloading OMA units:', err); + } finally { + loading = false; + } + } + function handleSuccess() { - const url = new URL($page.url); - goto(url, { invalidateAll: true }); + reloadData(); } -
+

Unidades de Medida OMA

Catálogo de unidades de medida OMA

- +
-
-
- + {#if error} +
+ {error}
-
- -
-
+ {/if} -
- -
+ +
Listado de Unidades OMA
+
+
+ +
Mostrando {allItems.length} de {totalItems} registros
diff --git a/frontend/src/routes/dashboard/general_catalogs/vehicles/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/vehicles/+page.svelte index 1bcc8916..39ee3719 100644 --- a/frontend/src/routes/dashboard/general_catalogs/vehicles/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/vehicles/+page.svelte @@ -1,12 +1,13 @@ -
+
-

Vehículos (Transporte)

+

Vehículos (Transporte)

Gestión del catálogo de camiones y vehículos de transporte

- +
-
- - -
+ +
Listado de Vehículos
+ {#if loading && data.length === 0}
Cargando vehículos...
{:else}
{/if}
+
- {#if loading && data.length === 0} -
- Cargando vehículos... -
- {:else} - - {/if} +
Mostrando {data.length} de {totalItems} registros
diff --git a/frontend/src/routes/dashboard/goods/fixed-asset-classes/+page.svelte b/frontend/src/routes/dashboard/goods/fixed-asset-classes/+page.svelte index 3b9bf873..7f46bab4 100644 --- a/frontend/src/routes/dashboard/goods/fixed-asset-classes/+page.svelte +++ b/frontend/src/routes/dashboard/goods/fixed-asset-classes/+page.svelte @@ -233,19 +233,30 @@ ]); -
- -
-

CATALOGO DE CLASES DE ACTIVO FIJO

-

Gestiona y consulta las clases de activo fijo

+
+
+
+

Clases de Activo Fijo

+

Gestiona y consulta las clases de activo fijo

+
+
+ + +
-
+
-
+
-
+

Filtros

@@ -256,37 +267,37 @@
- +
- +
- +
-
-
+
+

Listado de Clases

Mostrando de {filteredClasses.length} registros - @@ -309,9 +320,7 @@
-
+

Código de Clase @@ -382,6 +391,8 @@

+
+
-
- -
-

CATÁLOGO DE PARTES

-

- Gestiona y consulta las partes de inventario y activo fijo -

+
+
+
+

Catálogo de Partes

+

+ Gestiona y consulta las partes de inventario y activo fijo +

+
+
+ + +
-
+
-
+
-
+

Filtros

@@ -215,23 +226,23 @@
- +
- +
- +
@@ -267,14 +278,14 @@
-
-
+
+

Listado de Partes

Mostrando {filteredParts.length} registros - @@ -298,9 +309,7 @@
-
+

Número de Parte @@ -414,6 +423,8 @@

+
+
([]); @@ -81,15 +81,15 @@ const urlOperationType = searchParams.get('operation_type'); const urlInvoiceType = searchParams.get('invoice_type'); const urlInvoiceNumber = searchParams.get('invoice_number'); - const urlProjectNumber = searchParams.get('project_number'); - const urlYear = searchParams.get('year'); + const urlYearFrom = searchParams.get('year_from'); + const urlYearTo = searchParams.get('year_to'); // Actualizar filtros si hay cambios en la URL filters.operation_type = (urlOperationType || '') as '' | OperationType; filters.invoice_type = urlInvoiceType || ''; filters.invoice_number = urlInvoiceNumber || ''; - filters.project_number = urlProjectNumber || ''; - filters.year = urlYear || ''; + filters.year_from = urlYearFrom || ''; + filters.year_to = urlYearTo || ''; } }); @@ -118,8 +118,8 @@ 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); + if (filters.year_from) params.set('year_from', filters.year_from); + if (filters.year_to) params.set('year_to', filters.year_to); const queryString = params.toString(); const newUrl = queryString ? `?${queryString}` : window.location.pathname; @@ -140,8 +140,8 @@ operation_type: filters.operation_type, invoice_type: filters.invoice_type, invoice_number: filters.invoice_number, - project_number: filters.project_number, - year: filters.year + year_from: filters.year_from, + year_to: filters.year_to }; const currentFiltersKey = JSON.stringify(currentFilters); @@ -268,8 +268,8 @@ operation_type: filters.operation_type || undefined, invoice_type: filters.invoice_type || undefined, invoice_number: filters.invoice_number || undefined, - project_number: filters.project_number || undefined, - year: filters.year || undefined, + year_from: filters.year_from || undefined, + year_to: filters.year_to || undefined, sort_by: sorting.length > 0 ? sorting[0].id : undefined, sort_order: sorting.length > 0 ? (sorting[0].desc ? 'desc' : 'asc') : undefined }; @@ -327,8 +327,8 @@ operation_type: filters.operation_type || undefined, invoice_type: filters.invoice_type || undefined, invoice_number: filters.invoice_number || undefined, - project_number: filters.project_number || undefined, - year: filters.year || undefined, + year_from: filters.year_from || undefined, + year_to: filters.year_to || undefined, sort_by: sorting.length > 0 ? sorting[0].id : undefined, sort_order: sorting.length > 0 ? (sorting[0].desc ? 'desc' : 'asc') : undefined }; @@ -367,8 +367,8 @@ operation_type: '', invoice_type: '', invoice_number: '', - project_number: '', - year: '' + year_from: '', + year_to: '' }; applyFilters(); } @@ -387,8 +387,8 @@ operation_type: filters.operation_type || undefined, invoice_type: filters.invoice_type || undefined, invoice_number: filters.invoice_number || undefined, - project_number: filters.project_number || undefined, - year: filters.year || undefined, + year_from: filters.year_from || undefined, + year_to: filters.year_to || undefined, sort_by: sorting.length > 0 ? sorting[0].id : undefined, sort_order: sorting.length > 0 ? (sorting[0].desc ? 'desc' : 'asc') : undefined }; @@ -957,84 +957,47 @@ } -
+
-

Facturas

+

Facturas

Gestiona las facturas del sistema

-
- -
- - - Filtros - Filtra las facturas por diferentes criterios (los filtros se aplican automáticamente) - - -
-
- - -
-
- - -
- -
- - -
- -
- - -
- -
- - -
-
-
-
{#if error} @@ -1045,38 +1008,63 @@ {/if} - +
Listado de Facturas - - Mostrando {allItems.length} de {totalItems} registros -
-
-
- - (sorting = newSorting)} - /> + +
+ (sorting = newSorting)} + /> +
+
+ Mostrando {allItems.length} de {totalItems} registros + + Filtros activos: {Object.values(filters).filter((value) => value !== '').length} +
+ +
+ ([{ id: 'id', desc: true }]); @@ -256,7 +256,7 @@ const filterParams = { status: filters.status || undefined, - client_id: filters.client_id ? parseInt(filters.client_id) : undefined, + pedimento: filters.pedimento || undefined, year: filters.year || undefined, sort_by: sorting.length > 0 ? sorting[0].id : undefined, sort_order: sorting.length > 0 ? (sorting[0].desc ? 'desc' : 'asc') : undefined @@ -309,7 +309,7 @@ const filterParams = { status: filters.status || undefined, - client_id: filters.client_id ? parseInt(filters.client_id) : undefined, + pedimento: filters.pedimento || undefined, year: filters.year || undefined, sort_by: sorting.length > 0 ? sorting[0].id : undefined, sort_order: sorting.length > 0 ? (sorting[0].desc ? 'desc' : 'asc') : undefined @@ -347,7 +347,7 @@ function clearFilters() { filters = { status: '', - client_id: '', + pedimento: '', year: '' }; applyFilters(); @@ -370,7 +370,7 @@ const filterParams = { status: filters.status || undefined, - client_id: filters.client_id ? parseInt(filters.client_id) : undefined, + pedimento: filters.pedimento || undefined, year: filters.year || undefined, sort_by: sorting.length > 0 ? sorting[0].id : undefined, sort_order: sorting.length > 0 ? (sorting[0].desc ? 'desc' : 'asc') : undefined @@ -439,69 +439,37 @@ const columns = createColumns(handleSuccess); -
+
-

Pedimentos

+

Pedimentos

Gestiona los pedimentos del sistema

- +
+ + +
- - - -
-
- - -
- -
- - -
- -
- - -
-
-
-
- {#if error} - + Error {error} @@ -510,42 +478,64 @@ {/if} - +
Listado de Pedimentos - - Mostrando {allItems.length} de {totalItems} registros -
- +
+ + + +
- + - (sorting = newSorting)} - /> +
+ (sorting = newSorting)} + /> +
+
+ Mostrando {allItems.length} de {totalItems} registros + + Filtros activos: {Object.values(filters).filter((value) => value !== '').length} +
+ +
+
diff --git a/frontend/src/routes/dashboard/reference_data/code_pedimento_regimens/+page.svelte b/frontend/src/routes/dashboard/reference_data/code_pedimento_regimens/+page.svelte index 5f0781a8..0ecf1a06 100644 --- a/frontend/src/routes/dashboard/reference_data/code_pedimento_regimens/+page.svelte +++ b/frontend/src/routes/dashboard/reference_data/code_pedimento_regimens/+page.svelte @@ -3,56 +3,39 @@ import { codePedimentoRegimensApi, type CodePedimentoRegimen } from '$lib/api/dashboard/reference_data/code_pedimento_regimens'; import DataTable from '$lib/components/dashboard/reference_data/code_pedimento_regimens/data-table.svelte'; import { createColumns } from '$lib/components/dashboard/reference_data/code_pedimento_regimens/columns.js'; - import CreateEditDialog from '$lib/components/dashboard/reference_data/code_pedimento_regimens/create-edit-dialog.svelte'; import * as Card from '$lib/components/ui/card'; import { Button } from '$lib/components/ui/button'; - import type { PageData } from './$types'; + import { Input } from '$lib/components/ui/input'; + import { page } from '$app/stores'; + import { browser } from '$app/environment'; + import { RefreshCw } from 'lucide-svelte'; import { useShortcuts } from '$lib/hooks/use-shortcuts'; import { obtenerAtajosLista } from '$lib/config/shortcuts/dashboard/reference_data/code_pedimento_regimens/list'; - import { browser } from '$app/environment'; - import { Plus, RefreshCw } from 'lucide-svelte'; + import type { PageData } from './$types'; // Los datos iniciales vienen del servidor let { data }: { data: PageData } = $props(); - // Estado para el diálogo de crear - let showCreateDialog = $state(false); - // Atajos useShortcuts( 'Lista Códigos', obtenerAtajosLista({ - manejarNuevo: () => (showCreateDialog = true), manejarActualizar: reloadData }) ); - // Sincronizar token de cookies a localStorage al montar el componente + // Sincronizar token de cookies onMount(() => { if (browser) { - // Función para obtener el valor de una cookie const getCookie = (name: string): string | null => { const value = `; ${document.cookie}`; const parts = value.split(`; ${name}=`); if (parts.length === 2) return parts.pop()?.split(';').shift() || null; return null; }; - - // Verificar si hay token en las cookies const cookieToken = getCookie('access_token'); const localToken = localStorage.getItem('access_token'); - - if (cookieToken && cookieToken !== localToken) { - localStorage.setItem('access_token', cookieToken); - } - - // También sincronizar refresh_token si existe - const cookieRefreshToken = getCookie('refresh_token'); - const localRefreshToken = localStorage.getItem('refresh_token'); - - if (cookieRefreshToken && cookieRefreshToken !== localRefreshToken) { - localStorage.setItem('refresh_token', cookieRefreshToken); - } + if (cookieToken && cookieToken !== localToken) localStorage.setItem('access_token', cookieToken); } }); @@ -65,116 +48,101 @@ let hasMore = $derived(allItems.length < totalItems); let error = $state(data.error || null); + // Filtros + let searchQuery = $state($page.url.searchParams.get('search') || ''); + let timeout: ReturnType; + + function handleSearch() { + if (!browser) return; + clearTimeout(timeout); + timeout = setTimeout(async () => { + loading = true; + try { + const response = await codePedimentoRegimensApi.list(1, pageSize, searchQuery); + if (!response.error && response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (e) { + console.error('Error aplicando filtros:', e); + } finally { + loading = false; + } + const url = new URL($page.url); + if (searchQuery) url.searchParams.set('search', searchQuery); + else url.searchParams.delete('search'); + history.replaceState(history.state, '', url); + }, 500); + } + async function loadMore() { if (loading || !hasMore) return; - loading = true; error = null; - - try { - const response = await codePedimentoRegimensApi.list(currentPage + 1, pageSize); - + try { + const response = await codePedimentoRegimensApi.list(currentPage + 1, pageSize, searchQuery); if (response.error) { - console.error('📊 [Page] Error en loadMore:', response.error, 'Status:', response.status); - - // Si es un error de autenticación (401 o 403) y no se pudo refrescar, mostrar mensaje específico if (response.status === 401 || response.status === 403) { error = 'Sesión expirada. Recargando página...'; - // Recargar automáticamente después de 2 segundos - setTimeout(() => { - window.location.reload(); - }, 2000); + setTimeout(() => window.location.reload(), 2000); } else { error = response.error; } return; } - - if (response.data?.items) { - // Agregar los nuevos items al array existente + if (response.data?.items) { allItems = [...allItems, ...response.data.items]; currentPage++; totalItems = response.data.total; } } catch (e) { error = 'Error cargando más datos'; - console.error('📊 [Page] Error loading more:', e); } finally { loading = false; } } function reloadData() { - // Reset y recargar desde el principio window.location.reload(); } - function handleCreateClick() { - showCreateDialog = true; - } - function handleSuccess() { - // Recargar datos después de crear/editar/eliminar reloadData(); } - // Crear columnas con el callback onSuccess const columns = createColumns(handleSuccess); -
- -
-
-

Código Pedimento - Regímenes

+
+ +
+
+

+ Pedimento - Regímenes +

- Gestiona las relaciones entre códigos de pedimento y regímenes + Relación entre códigos de pedimento y regímenes aduaneros

- +
+ +
- {#if error} - - - Error - {error} - - +
+ {error} +
{/if} - - - -
-
- Listado de Relaciones - - Mostrando {allItems.length} de {totalItems} registros - -
- -
-
- - - - + +
Listado de Pedimento - Regímenes
+
-
- - +
Mostrando {allItems.length} de {totalItems} registros
+
diff --git a/frontend/src/routes/dashboard/reference_data/containers/+page.svelte b/frontend/src/routes/dashboard/reference_data/containers/+page.svelte index fdb94c31..f25afd54 100644 --- a/frontend/src/routes/dashboard/reference_data/containers/+page.svelte +++ b/frontend/src/routes/dashboard/reference_data/containers/+page.svelte @@ -3,56 +3,30 @@ import { containersApi, type Container } from '$lib/api/dashboard/reference_data/containers'; import DataTable from '$lib/components/dashboard/reference_data/containers/data-table.svelte'; import { createColumns } from '$lib/components/dashboard/reference_data/containers/columns.js'; - import CreateEditDialog from '$lib/components/dashboard/reference_data/containers/create-edit-dialog.svelte'; import * as Card from '$lib/components/ui/card'; import { Button } from '$lib/components/ui/button'; - import type { PageData } from './$types'; - import { useShortcuts } from '$lib/hooks/use-shortcuts'; - import { obtenerAtajosLista } from '$lib/config/shortcuts/dashboard/reference_data/containers/list'; + import { Input } from '$lib/components/ui/input'; + import { page } from '$app/stores'; import { browser } from '$app/environment'; - import { Plus, RefreshCw } from 'lucide-svelte'; + import { RefreshCw } from 'lucide-svelte'; + import { useShortcuts } from '$lib/hooks/use-shortcuts'; + import type { PageData } from './$types'; // Los datos iniciales vienen del servidor let { data }: { data: PageData } = $props(); - - // Estado para el diálogo de crear - let showCreateDialog = $state(false); - // Atajos - useShortcuts( - 'Lista Contenedores', - obtenerAtajosLista({ - manejarNuevo: () => (showCreateDialog = true), - manejarActualizar: reloadData - }) - ); - - // Sincronizar token de cookies a localStorage al montar el componente + // Sincronizar token de cookies onMount(() => { if (browser) { - // Función para obtener el valor de una cookie const getCookie = (name: string): string | null => { const value = `; ${document.cookie}`; const parts = value.split(`; ${name}=`); if (parts.length === 2) return parts.pop()?.split(';').shift() || null; return null; }; - - // Verificar si hay token en las cookies const cookieToken = getCookie('access_token'); const localToken = localStorage.getItem('access_token'); - - if (cookieToken && cookieToken !== localToken) { - localStorage.setItem('access_token', cookieToken); - } - - // También sincronizar refresh_token si existe - const cookieRefreshToken = getCookie('refresh_token'); - const localRefreshToken = localStorage.getItem('refresh_token'); - - if (cookieRefreshToken && cookieRefreshToken !== localRefreshToken) { - localStorage.setItem('refresh_token', cookieRefreshToken); - } + if (cookieToken && cookieToken !== localToken) localStorage.setItem('access_token', cookieToken); } }); @@ -65,116 +39,112 @@ let hasMore = $derived(allItems.length < totalItems); let error = $state(data.error || null); + // Filtros + let searchQuery = $state($page.url.searchParams.get('search') || ''); + let timeout: ReturnType; + + function handleSearch() { + if (!browser) return; + clearTimeout(timeout); + timeout = setTimeout(async () => { + loading = true; + try { + const response = await containersApi.list(1, pageSize, searchQuery); + if (!response.error && response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (e) { + console.error('Error aplicando filtros:', e); + } finally { + loading = false; + } + const url = new URL($page.url); + if (searchQuery) url.searchParams.set('search', searchQuery); + else url.searchParams.delete('search'); + history.replaceState(history.state, '', url); + }, 500); + } + async function loadMore() { if (loading || !hasMore) return; - loading = true; error = null; - - try { - const response = await containersApi.list(currentPage + 1, pageSize); - + try { + const response = await containersApi.list(currentPage + 1, pageSize, searchQuery); if (response.error) { - console.error('📊 [Page] Error en loadMore:', response.error, 'Status:', response.status); - - // Si es un error de autenticación (401 o 403) y no se pudo refrescar, mostrar mensaje específico if (response.status === 401 || response.status === 403) { error = 'Sesión expirada. Recargando página...'; - // Recargar automáticamente después de 2 segundos - setTimeout(() => { - window.location.reload(); - }, 2000); + setTimeout(() => window.location.reload(), 2000); } else { error = response.error; } return; } - - if (response.data?.items) { - // Agregar los nuevos items al array existente + if (response.data?.items) { allItems = [...allItems, ...response.data.items]; currentPage++; totalItems = response.data.total; } } catch (e) { error = 'Error cargando más datos'; - console.error('📊 [Page] Error loading more:', e); } finally { loading = false; } } function reloadData() { - // Reset y recargar desde el principio window.location.reload(); } - function handleCreateClick() { - showCreateDialog = true; - } - function handleSuccess() { - // Recargar datos después de crear/editar/eliminar reloadData(); } - // Crear columnas con el callback onSuccess + useShortcuts('Contenedores', [ + { key: 'Alt+Shift+R', description: 'Actualizar Lista', action: reloadData } + ]); + const columns = createColumns(handleSuccess); -
- -
-
-

Contenedores

+
+ +
+
+

+ Contenedores +

- Gestiona los tipos de contenedores disponibles + Gestiona los tipos de contenedores disponibles en el sistema

- +
+ +
- {#if error} - - - Error - {error} - - +
+ {error} +
{/if} - - + -
-
- Listado de Contenedores - - Mostrando {allItems.length} de {totalItems} registros - +
+ Listado de Contenedores +
+
-
- - - - +
-
- - +
Mostrando {allItems.length} de {totalItems} registros
+
diff --git a/frontend/src/routes/dashboard/reference_data/countries/+page.svelte b/frontend/src/routes/dashboard/reference_data/countries/+page.svelte index 6a66336f..378f0264 100644 --- a/frontend/src/routes/dashboard/reference_data/countries/+page.svelte +++ b/frontend/src/routes/dashboard/reference_data/countries/+page.svelte @@ -3,9 +3,11 @@ import { countriesApi, type Country } from '$lib/api/dashboard/reference_data/countries'; import DataTable from '$lib/components/dashboard/reference_data/countries/data-table.svelte'; import { createColumns } from '$lib/components/dashboard/reference_data/countries/columns.js'; - 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 { Input } from '$lib/components/ui/input'; + import { RefreshCw } from 'lucide-svelte'; + import { page } from '$app/stores'; import type { PageData } from './$types'; import { useShortcuts } from '$lib/hooks/use-shortcuts'; import { obtenerAtajosLista } from '$lib/config/shortcuts/dashboard/reference_data/countries/list'; @@ -14,14 +16,10 @@ // Los datos iniciales vienen del servidor let { data }: { data: PageData } = $props(); - // Estado para el diálogo de crear - let showCreateDialog = $state(false); - // Atajos useShortcuts( 'Lista Países', obtenerAtajosLista({ - manejarNuevo: () => (showCreateDialog = true), manejarActualizar: reloadData }) ); @@ -64,6 +62,37 @@ let hasMore = $derived(allItems.length < totalItems); let error = $state(data.error || null); + // Filtros + let searchQuery = $state($page.url.searchParams.get('search') || ''); + let timeout: ReturnType; + + function handleSearch() { + if (!browser) return; + clearTimeout(timeout); + timeout = setTimeout(async () => { + loading = true; + try { + const response = await countriesApi.list(1, pageSize, searchQuery); + if (!response.error && response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (e) { + console.error('Error aplicando filtros:', e); + } finally { + loading = false; + } + + // Actualizar URL silenciosamente para mantener estado + const url = new URL($page.url); + if (searchQuery) url.searchParams.set('search', searchQuery); + else url.searchParams.delete('search'); + + history.replaceState(history.state, '', url); + }, 500); + } + async function loadMore() { if (loading || !hasMore) return; @@ -71,7 +100,7 @@ error = null; try { - const response = await countriesApi.list(currentPage + 1, pageSize); + const response = await countriesApi.list(currentPage + 1, pageSize, searchQuery); if (response.error) { console.error('📊 [Page] Error en loadMore:', response.error, 'Status:', response.status); @@ -108,10 +137,6 @@ window.location.reload(); } - function handleCreateClick() { - showCreateDialog = true; - } - function handleSuccess() { // Recargar datos después de crear/editar/eliminar reloadData(); @@ -121,41 +146,35 @@ const columns = createColumns(handleSuccess); -
-
-
-

Países

+
+ +
+
+

+ Países +

Gestiona los países disponibles en el sistema

-
- -
{#if error} -
+
{error}
{/if} -
- -
-
+ +
Listado de Países
+
+
- +
Mostrando {allItems.length} de {totalItems} registros
+
diff --git a/frontend/src/routes/dashboard/reference_data/currency_types/+page.svelte b/frontend/src/routes/dashboard/reference_data/currency_types/+page.svelte index b546fb2a..50b1085f 100644 --- a/frontend/src/routes/dashboard/reference_data/currency_types/+page.svelte +++ b/frontend/src/routes/dashboard/reference_data/currency_types/+page.svelte @@ -3,55 +3,30 @@ import { currencyTypesApi, type CurrencyType } from '$lib/api/dashboard/reference_data/currency_types'; import DataTable from '$lib/components/dashboard/reference_data/currency_types/data-table.svelte'; import { createColumns } from '$lib/components/dashboard/reference_data/currency_types/columns.js'; - 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 { useShortcuts } from '$lib/hooks/use-shortcuts'; - import { obtenerAtajosLista } from '$lib/config/shortcuts/dashboard/reference_data/currency_types/list'; + import { Input } from '$lib/components/ui/input'; + import { page } from '$app/stores'; import { browser } from '$app/environment'; + import { RefreshCw } from 'lucide-svelte'; + import { useShortcuts } from '$lib/hooks/use-shortcuts'; + import type { PageData } from './$types'; // Los datos iniciales vienen del servidor let { data }: { data: PageData } = $props(); - - // Estado para el diálogo de crear - let showCreateDialog = $state(false); - // Atajos - useShortcuts( - 'Lista Tipos de Moneda', - obtenerAtajosLista({ - manejarNuevo: () => (showCreateDialog = true), - manejarActualizar: reloadData - }) - ); - - // Sincronizar token de cookies a localStorage al montar el componente + // Sincronizar token de cookies onMount(() => { if (browser) { - // Función para obtener el valor de una cookie const getCookie = (name: string): string | null => { const value = `; ${document.cookie}`; const parts = value.split(`; ${name}=`); if (parts.length === 2) return parts.pop()?.split(';').shift() || null; return null; }; - - // Verificar si hay token en las cookies const cookieToken = getCookie('access_token'); const localToken = localStorage.getItem('access_token'); - - if (cookieToken && cookieToken !== localToken) { - localStorage.setItem('access_token', cookieToken); - } - - // También sincronizar refresh_token si existe - const cookieRefreshToken = getCookie('refresh_token'); - const localRefreshToken = localStorage.getItem('refresh_token'); - - if (cookieRefreshToken && cookieRefreshToken !== localRefreshToken) { - localStorage.setItem('refresh_token', cookieRefreshToken); - } + if (cookieToken && cookieToken !== localToken) localStorage.setItem('access_token', cookieToken); } }); @@ -64,98 +39,105 @@ let hasMore = $derived(allItems.length < totalItems); let error = $state(data.error || null); + // Filtros + let searchQuery = $state($page.url.searchParams.get('search') || ''); + let timeout: ReturnType; + + function handleSearch() { + if (!browser) return; + clearTimeout(timeout); + timeout = setTimeout(async () => { + loading = true; + try { + const response = await currencyTypesApi.list(1, pageSize, searchQuery); + if (!response.error && response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (e) { + console.error('Error aplicando filtros:', e); + } finally { + loading = false; + } + const url = new URL($page.url); + if (searchQuery) url.searchParams.set('search', searchQuery); + else url.searchParams.delete('search'); + history.replaceState(history.state, '', url); + }, 500); + } + async function loadMore() { if (loading || !hasMore) return; - loading = true; error = null; - - try { - const response = await currencyTypesApi.list(currentPage + 1, pageSize); - + try { + const response = await currencyTypesApi.list(currentPage + 1, pageSize, searchQuery); if (response.error) { - console.error('📊 [Page] Error en loadMore:', response.error, 'Status:', response.status); - - // Si es un error de autenticación (401 o 403) y no se pudo refrescar, mostrar mensaje específico if (response.status === 401 || response.status === 403) { error = 'Sesión expirada. Recargando página...'; - // Recargar automáticamente después de 2 segundos - setTimeout(() => { - window.location.reload(); - }, 2000); + setTimeout(() => window.location.reload(), 2000); } else { error = response.error; } return; } - - if (response.data?.items) { - // Agregar los nuevos items al array existente + if (response.data?.items) { allItems = [...allItems, ...response.data.items]; currentPage++; totalItems = response.data.total; } } catch (e) { error = 'Error cargando más datos'; - console.error('📊 [Page] Error loading more:', e); } finally { loading = false; } } function reloadData() { - // Reset y recargar desde el principio window.location.reload(); } - function handleCreateClick() { - showCreateDialog = true; - } - function handleSuccess() { - // Recargar datos después de crear/editar/eliminar reloadData(); } - // Crear columnas con el callback onSuccess + useShortcuts('Tipos de Moneda', [ + { key: 'Alt+Shift+R', description: 'Actualizar Lista', action: reloadData } + ]); + const columns = createColumns(handleSuccess); -
-
-
-

Tipos de Moneda

+
+ +
+
+

+ Tipos de Moneda +

Gestiona los tipos de moneda disponibles en el sistema

-
- -
{#if error} -
+
{error}
{/if} -
- -
-
+ +
Listado de Tipos de Moneda
+
+
- +
Mostrando {allItems.length} de {totalItems} registros
+
diff --git a/frontend/src/routes/dashboard/reference_data/customs_sections/+page.svelte b/frontend/src/routes/dashboard/reference_data/customs_sections/+page.svelte index 4c59e6a0..2a6da5e7 100644 --- a/frontend/src/routes/dashboard/reference_data/customs_sections/+page.svelte +++ b/frontend/src/routes/dashboard/reference_data/customs_sections/+page.svelte @@ -3,46 +3,30 @@ import { customsSectionsApi, type CustomsSection } from '$lib/api/dashboard/reference_data/customs_sections'; import DataTable from '$lib/components/dashboard/reference_data/customs_sections/data-table.svelte'; import { createColumns } from '$lib/components/dashboard/reference_data/customs_sections/columns.js'; - import CreateEditDialog from '$lib/components/dashboard/reference_data/customs_sections/create-edit-dialog.svelte'; import * as Card from '$lib/components/ui/card'; import { Button } from '$lib/components/ui/button'; - import type { PageData } from './$types'; + import { Input } from '$lib/components/ui/input'; + import { page } from '$app/stores'; import { browser } from '$app/environment'; - import { Plus, RefreshCw } from 'lucide-svelte'; + import { RefreshCw } from 'lucide-svelte'; import { useShortcuts } from '$lib/hooks/use-shortcuts'; + import type { PageData } from './$types'; // Los datos iniciales vienen del servidor let { data }: { data: PageData } = $props(); - // Estado para el diálogo de crear - let showCreateDialog = $state(false); - - // Sincronizar token de cookies a localStorage al montar el componente + // Sincronizar token de cookies onMount(() => { if (browser) { - // Función para obtener el valor de una cookie const getCookie = (name: string): string | null => { const value = `; ${document.cookie}`; const parts = value.split(`; ${name}=`); if (parts.length === 2) return parts.pop()?.split(';').shift() || null; return null; }; - - // Verificar si hay token en las cookies const cookieToken = getCookie('access_token'); const localToken = localStorage.getItem('access_token'); - - if (cookieToken && cookieToken !== localToken) { - localStorage.setItem('access_token', cookieToken); - } - - // También sincronizar refresh_token si existe - const cookieRefreshToken = getCookie('refresh_token'); - const localRefreshToken = localStorage.getItem('refresh_token'); - - if (cookieRefreshToken && cookieRefreshToken !== localRefreshToken) { - localStorage.setItem('refresh_token', cookieRefreshToken); - } + if (cookieToken && cookieToken !== localToken) localStorage.setItem('access_token', cookieToken); } }); @@ -55,122 +39,105 @@ let hasMore = $derived(allItems.length < totalItems); let error = $state(data.error || null); + // Filtros + let searchQuery = $state($page.url.searchParams.get('search') || ''); + let timeout: ReturnType; + + function handleSearch() { + if (!browser) return; + clearTimeout(timeout); + timeout = setTimeout(async () => { + loading = true; + try { + const response = await customsSectionsApi.list(1, pageSize, searchQuery); + if (!response.error && response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (e) { + console.error('Error aplicando filtros:', e); + } finally { + loading = false; + } + const url = new URL($page.url); + if (searchQuery) url.searchParams.set('search', searchQuery); + else url.searchParams.delete('search'); + history.replaceState(history.state, '', url); + }, 500); + } + async function loadMore() { if (loading || !hasMore) return; - loading = true; error = null; - try { - const response = await customsSectionsApi.list(currentPage + 1, pageSize); - + const response = await customsSectionsApi.list(currentPage + 1, pageSize, searchQuery); if (response.error) { - console.error('📊 [Page] Error en loadMore:', response.error, 'Status:', response.status); - - // Si es un error de autenticación (401 o 403) y no se pudo refrescar, mostrar mensaje específico if (response.status === 401 || response.status === 403) { error = 'Sesión expirada. Recargando página...'; - // Recargar automáticamente después de 2 segundos - setTimeout(() => { - window.location.reload(); - }, 2000); + setTimeout(() => window.location.reload(), 2000); } else { error = response.error; } return; } - if (response.data?.items) { - // Agregar los nuevos items al array existente allItems = [...allItems, ...response.data.items]; currentPage++; totalItems = response.data.total; } } catch (e) { error = 'Error cargando más datos'; - console.error('📊 [Page] Error loading more:', e); } finally { loading = false; } } function reloadData() { - // Reset y recargar desde el principio window.location.reload(); } - function handleCreateClick() { - showCreateDialog = true; - } - function handleSuccess() { - // Recargar datos después de crear/editar/eliminar reloadData(); } - // Keyboard Shortcuts useShortcuts('Secciones Aduanales', [ - { - key: 'Alt+Shift+N', - description: 'Nueva Sección', - action: handleCreateClick - }, - { - key: 'Alt+Shift+R', - description: 'Actualizar Lista', - action: reloadData - } + { key: 'Alt+Shift+R', description: 'Actualizar Lista', action: reloadData } ]); - // Crear columnas con el callback onSuccess const columns = createColumns(handleSuccess); -
- -
-
-

Secciones Aduanales

-

Gestiona las secciones aduanales del sistema

+
+ +
+
+

+ Secciones Aduanales +

+

+ Gestiona las secciones aduanales del sistema +

+
+
+
-
- {#if error} - - - Error - {error} - - +
+ {error} +
{/if} - - - -
-
- Listado de Secciones Aduanales - - Mostrando {allItems.length} de {totalItems} registros - -
- -
-
- - - - + +
Listado de Secciones Aduanales
+
-
- - +
Mostrando {allItems.length} de {totalItems} registros
+
diff --git a/frontend/src/routes/dashboard/reference_data/customs_warehouses/+page.svelte b/frontend/src/routes/dashboard/reference_data/customs_warehouses/+page.svelte index 7055ef57..649546c2 100644 --- a/frontend/src/routes/dashboard/reference_data/customs_warehouses/+page.svelte +++ b/frontend/src/routes/dashboard/reference_data/customs_warehouses/+page.svelte @@ -3,55 +3,30 @@ import { customsWarehousesApi, type CustomsWarehouse } from '$lib/api/dashboard/reference_data/customs_warehouses'; import DataTable from '$lib/components/dashboard/reference_data/customs_warehouses/data-table.svelte'; import { createColumns } from '$lib/components/dashboard/reference_data/customs_warehouses/columns.js'; - import CreateEditDialog from '$lib/components/dashboard/reference_data/customs_warehouses/create-edit-dialog.svelte'; + import * as Card from '$lib/components/ui/card'; import { Button } from '$lib/components/ui/button'; - import type { PageData } from './$types'; - import { useShortcuts } from '$lib/hooks/use-shortcuts'; - import { obtenerAtajosLista } from '$lib/config/shortcuts/dashboard/reference_data/customs_warehouses/list'; + import { Input } from '$lib/components/ui/input'; + import { page } from '$app/stores'; import { browser } from '$app/environment'; - import { Plus, RefreshCw } from 'lucide-svelte'; + import { RefreshCw } from 'lucide-svelte'; + import { useShortcuts } from '$lib/hooks/use-shortcuts'; + import type { PageData } from './$types'; // Los datos iniciales vienen del servidor let { data }: { data: PageData } = $props(); - - // Estado para el diálogo de crear - let showCreateDialog = $state(false); - // Atajos - useShortcuts( - 'Lista Almacenes Aduanales', - obtenerAtajosLista({ - manejarNuevo: () => (showCreateDialog = true), - manejarActualizar: reloadData - }) - ); - - // Sincronizar token de cookies a localStorage al montar el componente + // Sincronizar token de cookies onMount(() => { if (browser) { - // Función para obtener el valor de una cookie const getCookie = (name: string): string | null => { const value = `; ${document.cookie}`; const parts = value.split(`; ${name}=`); if (parts.length === 2) return parts.pop()?.split(';').shift() || null; return null; }; - - // Verificar si hay token en las cookies const cookieToken = getCookie('access_token'); const localToken = localStorage.getItem('access_token'); - - if (cookieToken && cookieToken !== localToken) { - localStorage.setItem('access_token', cookieToken); - } - - // También sincronizar refresh_token si existe - const cookieRefreshToken = getCookie('refresh_token'); - const localRefreshToken = localStorage.getItem('refresh_token'); - - if (cookieRefreshToken && cookieRefreshToken !== localRefreshToken) { - localStorage.setItem('refresh_token', cookieRefreshToken); - } + if (cookieToken && cookieToken !== localToken) localStorage.setItem('access_token', cookieToken); } }); @@ -64,98 +39,105 @@ let hasMore = $derived(allItems.length < totalItems); let error = $state(data.error || null); + // Filtros + let searchQuery = $state($page.url.searchParams.get('search') || ''); + let timeout: ReturnType; + + function handleSearch() { + if (!browser) return; + clearTimeout(timeout); + timeout = setTimeout(async () => { + loading = true; + try { + const response = await customsWarehousesApi.list(1, pageSize, searchQuery); + if (!response.error && response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (e) { + console.error('Error aplicando filtros:', e); + } finally { + loading = false; + } + const url = new URL($page.url); + if (searchQuery) url.searchParams.set('search', searchQuery); + else url.searchParams.delete('search'); + history.replaceState(history.state, '', url); + }, 500); + } + async function loadMore() { if (loading || !hasMore) return; - loading = true; error = null; - - try { - const response = await customsWarehousesApi.list(currentPage + 1, pageSize); - + try { + const response = await customsWarehousesApi.list(currentPage + 1, pageSize, searchQuery); if (response.error) { - console.error('📊 [Page] Error en loadMore:', response.error, 'Status:', response.status); - - // Si es un error de autenticación (401 o 403) y no se pudo refrescar, mostrar mensaje específico if (response.status === 401 || response.status === 403) { error = 'Sesión expirada. Recargando página...'; - // Recargar automáticamente después de 2 segundos - setTimeout(() => { - window.location.reload(); - }, 2000); + setTimeout(() => window.location.reload(), 2000); } else { error = response.error; } return; } - - if (response.data?.items) { - // Agregar los nuevos items al array existente + if (response.data?.items) { allItems = [...allItems, ...response.data.items]; currentPage++; totalItems = response.data.total; } } catch (e) { error = 'Error cargando más datos'; - console.error('📊 [Page] Error loading more:', e); } finally { loading = false; } } function reloadData() { - // Reset y recargar desde el principio window.location.reload(); } - function handleCreateClick() { - showCreateDialog = true; - } - function handleSuccess() { - // Recargar datos después de crear/editar/eliminar reloadData(); } - // Crear columnas con el callback onSuccess + useShortcuts('Almacenes Aduanales', [ + { key: 'Alt+Shift+R', description: 'Actualizar Lista', action: reloadData } + ]); + const columns = createColumns(handleSuccess); -
-
-
-

Recintos Fiscalizados

+
+ +
+
+

+ Recintos Fiscalizados +

Gestiona los recintos fiscalizados del sistema aduanal

-
- -
{#if error} -
+
{error}
{/if} -
- -
-
+ +
Listado de Recintos Fiscalizados
+
+
- +
Mostrando {allItems.length} de {totalItems} registros
+
diff --git a/frontend/src/routes/dashboard/reference_data/incoterms/+page.server.ts b/frontend/src/routes/dashboard/reference_data/incoterms/+page.server.ts index 776fe196..0527ad0a 100644 --- a/frontend/src/routes/dashboard/reference_data/incoterms/+page.server.ts +++ b/frontend/src/routes/dashboard/reference_data/incoterms/+page.server.ts @@ -18,13 +18,20 @@ export const load: PageServerLoad = async ({ cookies, fetch, url, parent }) => { } try { - // Obtener parámetros de paginación de la URL + // Obtener parámetros de paginación y filtros de la URL const page = parseInt(url.searchParams.get('page') || '1'); const pageSize = parseInt(url.searchParams.get('page_size') || '50'); + const code = url.searchParams.get('code') || ''; + const description = url.searchParams.get('description') || ''; + + // Construir URL con filtros + let endpoint = `v1/public/reference_data/incoterms/?page=${page}&page_size=${pageSize}`; + if (code) endpoint += `&code=${encodeURIComponent(code)}`; + if (description) endpoint += `&description=${encodeURIComponent(description)}`; // Usar authenticatedFetch para manejar automáticamente el refresh de tokens const response = await authenticatedFetch( - `v1/public/reference_data/incoterms/?page=${page}&page_size=${pageSize}`, + endpoint, {}, cookies, fetch diff --git a/frontend/src/routes/dashboard/reference_data/incoterms/+page.svelte b/frontend/src/routes/dashboard/reference_data/incoterms/+page.svelte index 9a1b417c..5288a8a8 100644 --- a/frontend/src/routes/dashboard/reference_data/incoterms/+page.svelte +++ b/frontend/src/routes/dashboard/reference_data/incoterms/+page.svelte @@ -2,29 +2,76 @@ import { page } from '$app/stores'; import { goto } from '$app/navigation'; import { browser } from '$app/environment'; + import { incotermsApi, type Incoterm } from '$lib/api/dashboard/reference_data/incoterms'; import { createColumns } from '$lib/components/dashboard/reference_data/incoterms/columns'; import DataTable from '$lib/components/dashboard/reference_data/incoterms/data-table.svelte'; - 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 { Input } from '$lib/components/ui/input'; - import { Plus } from 'lucide-svelte'; + import { RefreshCw, Plus } from 'lucide-svelte'; import { useShortcuts } from '$lib/hooks/use-shortcuts'; import { obtenerAtajosLista } from '$lib/config/shortcuts/dashboard/reference_data/incoterms/list'; import type { PageData } from './$types'; let { data }: { data: PageData } = $props(); - let createDialogOpen = $state(false); - // Atajos useShortcuts( 'Lista Incoterms', obtenerAtajosLista({ - manejarNuevo: () => (createDialogOpen = true), - manejarActualizar: handleSuccess + manejarActualizar: reloadData }) ); + // Estado para infinite scroll + let allItems = $state(data.items || []); + let currentPage = $state(data.page || 1); + let pageSize = $state(50); + let totalItems = $state(data.total || 0); + let loading = $state(false); + let hasMore = $derived(allItems.length < totalItems); + let error = $state(data.error || null); + + async function loadMore() { + if (loading || !hasMore) return; + + loading = true; + error = null; + + try { + const response = await incotermsApi.list(currentPage + 1, pageSize, searchCode, searchDesc); + + if (response.error) { + console.error('📊 [Page] Error en loadMore:', response.error, 'Status:', response.status); + + if (response.status === 401 || response.status === 403) { + error = 'Sesión expirada. Recargando página...'; + setTimeout(() => { + window.location.reload(); + }, 2000); + } else { + error = response.error; + } + return; + } + + if (response.data?.items) { + allItems = [...allItems, ...response.data.items]; + currentPage++; + totalItems = response.data.total; + } + } catch (e) { + error = 'Error cargando más datos'; + console.error('📊 [Page] Error loading more:', e); + } finally { + loading = false; + } + } + + function reloadData() { + window.location.reload(); + } + // Filtros let searchCode = $state($page.url.searchParams.get('code') || ''); let searchDesc = $state($page.url.searchParams.get('description') || ''); @@ -33,7 +80,22 @@ function handleSearch() { if (!browser) return; clearTimeout(timeout); - timeout = setTimeout(() => { + timeout = setTimeout(async () => { + loading = true; + try { + const response = await incotermsApi.list(1, pageSize, searchCode, searchDesc); + if (!response.error && response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (e) { + console.error('Error aplicando filtros:', e); + } finally { + loading = false; + } + + // Actualizar URL silenciosamente para mantener estado const url = new URL($page.url); if (searchCode) url.searchParams.set('code', searchCode); else url.searchParams.delete('code'); @@ -41,8 +103,7 @@ if (searchDesc) url.searchParams.set('description', searchDesc); else url.searchParams.delete('description'); - url.searchParams.set('page', '1'); - goto(url, { keepFocus: true, noScroll: true }); + history.replaceState(history.state, '', url); }, 500); } @@ -52,44 +113,43 @@ } -
-
-
-

Incoterms

+
+ +
+
+

+ Incoterms +

- Catálogo de Incoterms + Catálogo de términos internacionales de comercio

-
-
- -
-
-
-
- +
+
-
- -
+ {#if error} +
+ {error} +
+ {/if} - + + +
+ Listado de Incoterms +
+ + +
+
+
+
+
+ +
Mostrando {allItems.length} de {totalItems} registros
diff --git a/frontend/src/routes/dashboard/reference_data/invoice_types/+page.svelte b/frontend/src/routes/dashboard/reference_data/invoice_types/+page.svelte index f615c7b3..9467a74a 100644 --- a/frontend/src/routes/dashboard/reference_data/invoice_types/+page.svelte +++ b/frontend/src/routes/dashboard/reference_data/invoice_types/+page.svelte @@ -3,55 +3,30 @@ import { invoiceTypesApi, type InvoiceType } from '$lib/api/dashboard/reference_data/invoice_types'; import DataTable from '$lib/components/dashboard/reference_data/invoice_types/data-table.svelte'; import { createColumns } from '$lib/components/dashboard/reference_data/invoice_types/columns.js'; - 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 { useShortcuts } from '$lib/hooks/use-shortcuts'; - import { obtenerAtajosLista } from '$lib/config/shortcuts/dashboard/reference_data/invoice_types/list'; + import { Input } from '$lib/components/ui/input'; + import { page } from '$app/stores'; import { browser } from '$app/environment'; + import { RefreshCw } from 'lucide-svelte'; + import { useShortcuts } from '$lib/hooks/use-shortcuts'; + import type { PageData } from './$types'; // Los datos iniciales vienen del servidor let { data }: { data: PageData } = $props(); - - // Estado para el diálogo de crear - let showCreateDialog = $state(false); - // Atajos - useShortcuts( - 'Lista Tipos de Factura', - obtenerAtajosLista({ - manejarNuevo: () => (showCreateDialog = true), - manejarActualizar: reloadData - }) - ); - - // Sincronizar token de cookies a localStorage al montar el componente + // Sincronizar token de cookies onMount(() => { if (browser) { - // Función para obtener el valor de una cookie const getCookie = (name: string): string | null => { const value = `; ${document.cookie}`; const parts = value.split(`; ${name}=`); if (parts.length === 2) return parts.pop()?.split(';').shift() || null; return null; }; - - // Verificar si hay token en las cookies const cookieToken = getCookie('access_token'); const localToken = localStorage.getItem('access_token'); - - if (cookieToken && cookieToken !== localToken) { - localStorage.setItem('access_token', cookieToken); - } - - // También sincronizar refresh_token si existe - const cookieRefreshToken = getCookie('refresh_token'); - const localRefreshToken = localStorage.getItem('refresh_token'); - - if (cookieRefreshToken && cookieRefreshToken !== localRefreshToken) { - localStorage.setItem('refresh_token', cookieRefreshToken); - } + if (cookieToken && cookieToken !== localToken) localStorage.setItem('access_token', cookieToken); } }); @@ -64,98 +39,105 @@ let hasMore = $derived(allItems.length < totalItems); let error = $state(data.error || null); + // Filtros + let searchQuery = $state($page.url.searchParams.get('search') || ''); + let timeout: ReturnType; + + function handleSearch() { + if (!browser) return; + clearTimeout(timeout); + timeout = setTimeout(async () => { + loading = true; + try { + const response = await invoiceTypesApi.list(1, pageSize, undefined, searchQuery); + if (!response.error && response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (e) { + console.error('Error aplicando filtros:', e); + } finally { + loading = false; + } + const url = new URL($page.url); + if (searchQuery) url.searchParams.set('search', searchQuery); + else url.searchParams.delete('search'); + history.replaceState(history.state, '', url); + }, 500); + } + async function loadMore() { if (loading || !hasMore) return; - loading = true; error = null; - - try { - const response = await invoiceTypesApi.list(currentPage + 1, pageSize); - + try { + const response = await invoiceTypesApi.list(currentPage + 1, pageSize, undefined, searchQuery); if (response.error) { - console.error('📊 [Page] Error en loadMore:', response.error, 'Status:', response.status); - - // Si es un error de autenticación (401 o 403) y no se pudo refrescar, mostrar mensaje específico if (response.status === 401 || response.status === 403) { error = 'Sesión expirada. Recargando página...'; - // Recargar automáticamente después de 2 segundos - setTimeout(() => { - window.location.reload(); - }, 2000); + setTimeout(() => window.location.reload(), 2000); } else { error = response.error; } return; } - - if (response.data?.items) { - // Agregar los nuevos items al array existente + if (response.data?.items) { allItems = [...allItems, ...response.data.items]; currentPage++; totalItems = response.data.total; } } catch (e) { error = 'Error cargando más datos'; - console.error('📊 [Page] Error loading more:', e); } finally { loading = false; } } function reloadData() { - // Reset y recargar desde el principio window.location.reload(); } - function handleCreateClick() { - showCreateDialog = true; - } - function handleSuccess() { - // Recargar datos después de crear/editar/eliminar reloadData(); } - // Crear columnas con el callback onSuccess + useShortcuts('Tipos de Factura', [ + { key: 'Alt+Shift+R', description: 'Actualizar Lista', action: reloadData } + ]); + const columns = createColumns(handleSuccess); -
-
-
-

Tipos de Factura

+
+ +
+
+

+ Tipos de Factura +

- Gestiona los tipos de facturas del sistema + Gestiona los tipos de facturas disponibles en el sistema

-
- -
{#if error} -
+
{error}
{/if} -
- -
-
+ +
Listado de Tipos de Factura
+
+
- +
Mostrando {allItems.length} de {totalItems} registros
+
diff --git a/frontend/src/routes/dashboard/reference_data/material_types/+page.svelte b/frontend/src/routes/dashboard/reference_data/material_types/+page.svelte index 1847f6e2..b77a5332 100644 --- a/frontend/src/routes/dashboard/reference_data/material_types/+page.svelte +++ b/frontend/src/routes/dashboard/reference_data/material_types/+page.svelte @@ -3,56 +3,30 @@ import { materialTypesApi, type MaterialType } from '$lib/api/dashboard/reference_data/material_types'; import DataTable from '$lib/components/dashboard/reference_data/material_types/data-table.svelte'; import { createColumns } from '$lib/components/dashboard/reference_data/material_types/columns.js'; - import CreateEditDialog from '$lib/components/dashboard/reference_data/material_types/create-edit-dialog.svelte'; import * as Card from '$lib/components/ui/card'; import { Button } from '$lib/components/ui/button'; - import type { PageData } from './$types'; - import { useShortcuts } from '$lib/hooks/use-shortcuts'; - import { obtenerAtajosLista } from '$lib/config/shortcuts/dashboard/reference_data/material_types/list'; + import { Input } from '$lib/components/ui/input'; + import { page } from '$app/stores'; import { browser } from '$app/environment'; - import { Plus, RefreshCw } from 'lucide-svelte'; + import { RefreshCw } from 'lucide-svelte'; + import { useShortcuts } from '$lib/hooks/use-shortcuts'; + import type { PageData } from './$types'; // Los datos iniciales vienen del servidor let { data }: { data: PageData } = $props(); - - // Estado para el diálogo de crear - let showCreateDialog = $state(false); - // Atajos - useShortcuts( - 'Lista Tipos de Material', - obtenerAtajosLista({ - manejarNuevo: () => (showCreateDialog = true), - manejarActualizar: reloadData - }) - ); - - // Sincronizar token de cookies a localStorage al montar el componente + // Sincronizar token de cookies onMount(() => { if (browser) { - // Función para obtener el valor de una cookie const getCookie = (name: string): string | null => { const value = `; ${document.cookie}`; const parts = value.split(`; ${name}=`); if (parts.length === 2) return parts.pop()?.split(';').shift() || null; return null; }; - - // Verificar si hay token en las cookies const cookieToken = getCookie('access_token'); const localToken = localStorage.getItem('access_token'); - - if (cookieToken && cookieToken !== localToken) { - localStorage.setItem('access_token', cookieToken); - } - - // También sincronizar refresh_token si existe - const cookieRefreshToken = getCookie('refresh_token'); - const localRefreshToken = localStorage.getItem('refresh_token'); - - if (cookieRefreshToken && cookieRefreshToken !== localRefreshToken) { - localStorage.setItem('refresh_token', cookieRefreshToken); - } + if (cookieToken && cookieToken !== localToken) localStorage.setItem('access_token', cookieToken); } }); @@ -65,116 +39,105 @@ let hasMore = $derived(allItems.length < totalItems); let error = $state(data.error || null); + // Filtros + let searchQuery = $state($page.url.searchParams.get('search') || ''); + let timeout: ReturnType; + + function handleSearch() { + if (!browser) return; + clearTimeout(timeout); + timeout = setTimeout(async () => { + loading = true; + try { + const response = await materialTypesApi.list(1, pageSize, undefined, searchQuery); + if (!response.error && response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (e) { + console.error('Error aplicando filtros:', e); + } finally { + loading = false; + } + const url = new URL($page.url); + if (searchQuery) url.searchParams.set('search', searchQuery); + else url.searchParams.delete('search'); + history.replaceState(history.state, '', url); + }, 500); + } + async function loadMore() { if (loading || !hasMore) return; - loading = true; error = null; - - try { - const response = await materialTypesApi.list(currentPage + 1, pageSize); - + try { + const response = await materialTypesApi.list(currentPage + 1, pageSize, undefined, searchQuery); if (response.error) { - console.error('📊 [Page] Error en loadMore:', response.error, 'Status:', response.status); - - // Si es un error de autenticación (401 o 403) y no se pudo refrescar, mostrar mensaje específico if (response.status === 401 || response.status === 403) { error = 'Sesión expirada. Recargando página...'; - // Recargar automáticamente después de 2 segundos - setTimeout(() => { - window.location.reload(); - }, 2000); + setTimeout(() => window.location.reload(), 2000); } else { error = response.error; } return; } - - if (response.data?.items) { - // Agregar los nuevos items al array existente + if (response.data?.items) { allItems = [...allItems, ...response.data.items]; currentPage++; totalItems = response.data.total; } } catch (e) { error = 'Error cargando más datos'; - console.error('📊 [Page] Error loading more:', e); } finally { loading = false; } } function reloadData() { - // Reset y recargar desde el principio window.location.reload(); } - function handleCreateClick() { - showCreateDialog = true; - } - function handleSuccess() { - // Recargar datos después de crear/editar/eliminar reloadData(); } - // Crear columnas con el callback onSuccess + useShortcuts('Tipos de Material', [ + { key: 'Alt+Shift+R', description: 'Actualizar Lista', action: reloadData } + ]); + const columns = createColumns(handleSuccess); -
- -
-
-

Tipos de Material

+
+ +
+
+

+ Tipos de Material +

- Gestiona los tipos de materiales del sistema + Gestiona los tipos de materiales disponibles en el sistema

- +
+ +
- {#if error} - - - Error - {error} - - +
+ {error} +
{/if} - - - -
-
- Listado de Tipos de Material - - Mostrando {allItems.length} de {totalItems} registros - -
- -
-
- - - - + +
Listado de Tipos de Material
+
-
- - +
Mostrando {allItems.length} de {totalItems} registros
+
diff --git a/frontend/src/routes/dashboard/reference_data/payment_methods/+page.svelte b/frontend/src/routes/dashboard/reference_data/payment_methods/+page.svelte index 53623210..54553e47 100644 --- a/frontend/src/routes/dashboard/reference_data/payment_methods/+page.svelte +++ b/frontend/src/routes/dashboard/reference_data/payment_methods/+page.svelte @@ -3,46 +3,30 @@ import { paymentMethodsApi, type PaymentMethod } from '$lib/api/dashboard/reference_data/payment_methods'; import DataTable from '$lib/components/dashboard/reference_data/payment_methods/data-table.svelte'; import { createColumns } from '$lib/components/dashboard/reference_data/payment_methods/columns.js'; - import CreateEditDialog from '$lib/components/dashboard/reference_data/payment_methods/create-edit-dialog.svelte'; import * as Card from '$lib/components/ui/card'; import { Button } from '$lib/components/ui/button'; - import type { PageData } from './$types'; + import { Input } from '$lib/components/ui/input'; + import { page } from '$app/stores'; import { browser } from '$app/environment'; - import { Plus, RefreshCw } from 'lucide-svelte'; + import { RefreshCw } from 'lucide-svelte'; import { useShortcuts } from '$lib/hooks/use-shortcuts'; + import type { PageData } from './$types'; // Los datos iniciales vienen del servidor let { data }: { data: PageData } = $props(); - // Estado para el diálogo de crear - let showCreateDialog = $state(false); - - // Sincronizar token de cookies a localStorage al montar el componente + // Sincronizar token de cookies onMount(() => { if (browser) { - // Función para obtener el valor de una cookie const getCookie = (name: string): string | null => { const value = `; ${document.cookie}`; const parts = value.split(`; ${name}=`); if (parts.length === 2) return parts.pop()?.split(';').shift() || null; return null; }; - - // Verificar si hay token en las cookies const cookieToken = getCookie('access_token'); const localToken = localStorage.getItem('access_token'); - - if (cookieToken && cookieToken !== localToken) { - localStorage.setItem('access_token', cookieToken); - } - - // También sincronizar refresh_token si existe - const cookieRefreshToken = getCookie('refresh_token'); - const localRefreshToken = localStorage.getItem('refresh_token'); - - if (cookieRefreshToken && cookieRefreshToken !== localRefreshToken) { - localStorage.setItem('refresh_token', cookieRefreshToken); - } + if (cookieToken && cookieToken !== localToken) localStorage.setItem('access_token', cookieToken); } }); @@ -55,122 +39,105 @@ let hasMore = $derived(allItems.length < totalItems); let error = $state(data.error || null); + // Filtros + let searchQuery = $state($page.url.searchParams.get('search') || ''); + let timeout: ReturnType; + + function handleSearch() { + if (!browser) return; + clearTimeout(timeout); + timeout = setTimeout(async () => { + loading = true; + try { + const response = await paymentMethodsApi.list(1, pageSize, searchQuery); + if (!response.error && response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (e) { + console.error('Error aplicando filtros:', e); + } finally { + loading = false; + } + const url = new URL($page.url); + if (searchQuery) url.searchParams.set('search', searchQuery); + else url.searchParams.delete('search'); + history.replaceState(history.state, '', url); + }, 500); + } + async function loadMore() { if (loading || !hasMore) return; - loading = true; error = null; - try { - const response = await paymentMethodsApi.list(currentPage + 1, pageSize); - + const response = await paymentMethodsApi.list(currentPage + 1, pageSize, searchQuery); if (response.error) { - console.error('📊 [Page] Error en loadMore:', response.error, 'Status:', response.status); - - // Si es un error de autenticación (401 o 403) y no se pudo refrescar, mostrar mensaje específico if (response.status === 401 || response.status === 403) { error = 'Sesión expirada. Recargando página...'; - // Recargar automáticamente después de 2 segundos - setTimeout(() => { - window.location.reload(); - }, 2000); + setTimeout(() => window.location.reload(), 2000); } else { error = response.error; } return; } - if (response.data?.items) { - // Agregar los nuevos items al array existente allItems = [...allItems, ...response.data.items]; currentPage++; totalItems = response.data.total; } } catch (e) { error = 'Error cargando más datos'; - console.error('📊 [Page] Error loading more:', e); } finally { loading = false; } } function reloadData() { - // Reset y recargar desde el principio window.location.reload(); } - function handleCreateClick() { - showCreateDialog = true; - } - function handleSuccess() { - // Recargar datos después de crear/editar/eliminar reloadData(); } - // Keyboard Shortcuts useShortcuts('Métodos de Pago', [ - { - key: 'Alt+Shift+N', - description: 'Nuevo Método', - action: handleCreateClick - }, - { - key: 'Alt+Shift+R', - description: 'Actualizar Lista', - action: reloadData - } + { key: 'Alt+Shift+R', description: 'Actualizar Lista', action: reloadData } ]); - // Crear columnas con el callback onSuccess const columns = createColumns(handleSuccess); -
- -
-
-

Métodos de Pago

-

Gestiona las formas de pago disponibles en el sistema

+
+ +
+
+

+ Métodos de Pago +

+

+ Gestiona las formas de pago disponibles en el sistema +

+
+
+
-
- {#if error} - - - Error - {error} - - +
+ {error} +
{/if} - - - -
-
- Listado de Métodos de Pago - - Mostrando {allItems.length} de {totalItems} registros - -
- -
-
- - - - + +
Listado de Métodos de Pago
+
-
- - +
Mostrando {allItems.length} de {totalItems} registros
+
diff --git a/frontend/src/routes/dashboard/reference_data/pedimento_codes/+page.svelte b/frontend/src/routes/dashboard/reference_data/pedimento_codes/+page.svelte index 15db3620..4b763276 100644 --- a/frontend/src/routes/dashboard/reference_data/pedimento_codes/+page.svelte +++ b/frontend/src/routes/dashboard/reference_data/pedimento_codes/+page.svelte @@ -3,46 +3,30 @@ import { pedimentoCodesApi, type PedimentoCode } from '$lib/api/dashboard/reference_data/pedimento_codes'; import DataTable from '$lib/components/dashboard/reference_data/pedimento_codes/data-table.svelte'; import { createColumns } from '$lib/components/dashboard/reference_data/pedimento_codes/columns.js'; - 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 { Input } from '$lib/components/ui/input'; + import { page } from '$app/stores'; + import { browser } from '$app/environment'; + import { RefreshCw } from 'lucide-svelte'; import { useShortcuts } from '$lib/hooks/use-shortcuts'; import type { PageData } from './$types'; - import { browser } from '$app/environment'; // Los datos iniciales vienen del servidor let { data }: { data: PageData } = $props(); - // Estado para el diálogo de crear - let showCreateDialog = $state(false); - - // Sincronizar token de cookies a localStorage al montar el componente + // Sincronizar token de cookies onMount(() => { if (browser) { - // Función para obtener el valor de una cookie const getCookie = (name: string): string | null => { const value = `; ${document.cookie}`; const parts = value.split(`; ${name}=`); if (parts.length === 2) return parts.pop()?.split(';').shift() || null; return null; }; - - // Verificar si hay token en las cookies const cookieToken = getCookie('access_token'); const localToken = localStorage.getItem('access_token'); - - if (cookieToken && cookieToken !== localToken) { - localStorage.setItem('access_token', cookieToken); - } - - // También sincronizar refresh_token si existe - const cookieRefreshToken = getCookie('refresh_token'); - const localRefreshToken = localStorage.getItem('refresh_token'); - - if (cookieRefreshToken && cookieRefreshToken !== localRefreshToken) { - localStorage.setItem('refresh_token', cookieRefreshToken); - } + if (cookieToken && cookieToken !== localToken) localStorage.setItem('access_token', cookieToken); } }); @@ -55,122 +39,105 @@ let hasMore = $derived(allItems.length < totalItems); let error = $state(data.error || null); + // Filtros + let searchQuery = $state($page.url.searchParams.get('search') || ''); + let timeout: ReturnType; + + function handleSearch() { + if (!browser) return; + clearTimeout(timeout); + timeout = setTimeout(async () => { + loading = true; + try { + const response = await pedimentoCodesApi.list(1, pageSize, searchQuery); + if (!response.error && response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (e) { + console.error('Error aplicando filtros:', e); + } finally { + loading = false; + } + const url = new URL($page.url); + if (searchQuery) url.searchParams.set('search', searchQuery); + else url.searchParams.delete('search'); + history.replaceState(history.state, '', url); + }, 500); + } + async function loadMore() { if (loading || !hasMore) return; - loading = true; error = null; - try { - const response = await pedimentoCodesApi.list(currentPage + 1, pageSize); - + const response = await pedimentoCodesApi.list(currentPage + 1, pageSize, searchQuery); if (response.error) { - console.error('📊 [Page] Error en loadMore:', response.error, 'Status:', response.status); - - // Si es un error de autenticación (401 o 403) y no se pudo refrescar, mostrar mensaje específico if (response.status === 401 || response.status === 403) { error = 'Sesión expirada. Recargando página...'; - // Recargar automáticamente después de 2 segundos - setTimeout(() => { - window.location.reload(); - }, 2000); + setTimeout(() => window.location.reload(), 2000); } else { error = response.error; } return; } - if (response.data?.items) { - // Agregar los nuevos items al array existente allItems = [...allItems, ...response.data.items]; currentPage++; totalItems = response.data.total; } } catch (e) { error = 'Error cargando más datos'; - console.error('📊 [Page] Error loading more:', e); } finally { loading = false; } } function reloadData() { - // Reset y recargar desde el principio window.location.reload(); } - function handleCreateClick() { - showCreateDialog = true; - } - function handleSuccess() { - // Recargar datos después de crear/editar/eliminar reloadData(); } - // Keyboard Shortcuts useShortcuts('Claves de Pedimento', [ - { - key: 'Alt+Shift+N', - description: 'Nueva Clave', - action: handleCreateClick - }, - { - key: 'Alt+Shift+R', - description: 'Actualizar Lista', - action: reloadData - } + { key: 'Alt+Shift+R', description: 'Actualizar Lista', action: reloadData } ]); - // Crear columnas con el callback onSuccess const columns = createColumns(handleSuccess); -
- -
-
-

Claves de Pedimento

-

Gestiona las claves de pedimento del sistema aduanero

+
+ +
+
+

+ Claves de Pedimento +

+

+ Gestiona las claves de pedimento del sistema aduanero +

+
+
+
-
- {#if error} - - - Error - {error} - - +
+ {error} +
{/if} - - - -
-
- Listado de Claves de Pedimento - - Mostrando {allItems.length} de {totalItems} registros - -
- -
-
- - - - + +
Listado de Claves de Pedimento
+
-
- - +
Mostrando {allItems.length} de {totalItems} registros
+
diff --git a/frontend/src/routes/dashboard/reference_data/pedimento_regimens/+page.svelte b/frontend/src/routes/dashboard/reference_data/pedimento_regimens/+page.svelte index e2222c2f..10256756 100644 --- a/frontend/src/routes/dashboard/reference_data/pedimento_regimens/+page.svelte +++ b/frontend/src/routes/dashboard/reference_data/pedimento_regimens/+page.svelte @@ -3,46 +3,30 @@ import { pedimentoRegimensApi, type PedimentoRegimen } from '$lib/api/dashboard/reference_data/pedimento_regimens'; import DataTable from '$lib/components/dashboard/reference_data/pedimento_regimens/data-table.svelte'; import { createColumns } from '$lib/components/dashboard/reference_data/pedimento_regimens/columns.js'; - import CreateEditDialog from '$lib/components/dashboard/reference_data/pedimento_regimens/create-edit-dialog.svelte'; import * as Card from '$lib/components/ui/card'; import { Button } from '$lib/components/ui/button'; - import type { PageData } from './$types'; + import { Input } from '$lib/components/ui/input'; + import { page } from '$app/stores'; import { browser } from '$app/environment'; - import { Plus, RefreshCw } from 'lucide-svelte'; + import { RefreshCw } from 'lucide-svelte'; import { useShortcuts } from '$lib/hooks/use-shortcuts'; + import type { PageData } from './$types'; // Los datos iniciales vienen del servidor let { data }: { data: PageData } = $props(); - // Estado para el diálogo de crear - let showCreateDialog = $state(false); - - // Sincronizar token de cookies a localStorage al montar el componente + // Sincronizar token de cookies onMount(() => { if (browser) { - // Función para obtener el valor de una cookie const getCookie = (name: string): string | null => { const value = `; ${document.cookie}`; const parts = value.split(`; ${name}=`); if (parts.length === 2) return parts.pop()?.split(';').shift() || null; return null; }; - - // Verificar si hay token en las cookies const cookieToken = getCookie('access_token'); const localToken = localStorage.getItem('access_token'); - - if (cookieToken && cookieToken !== localToken) { - localStorage.setItem('access_token', cookieToken); - } - - // También sincronizar refresh_token si existe - const cookieRefreshToken = getCookie('refresh_token'); - const localRefreshToken = localStorage.getItem('refresh_token'); - - if (cookieRefreshToken && cookieRefreshToken !== localRefreshToken) { - localStorage.setItem('refresh_token', cookieRefreshToken); - } + if (cookieToken && cookieToken !== localToken) localStorage.setItem('access_token', cookieToken); } }); @@ -55,122 +39,105 @@ let hasMore = $derived(allItems.length < totalItems); let error = $state(data.error || null); + // Filtros + let searchQuery = $state($page.url.searchParams.get('search') || ''); + let timeout: ReturnType; + + function handleSearch() { + if (!browser) return; + clearTimeout(timeout); + timeout = setTimeout(async () => { + loading = true; + try { + const response = await pedimentoRegimensApi.list(1, pageSize, searchQuery); + if (!response.error && response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (e) { + console.error('Error aplicando filtros:', e); + } finally { + loading = false; + } + const url = new URL($page.url); + if (searchQuery) url.searchParams.set('search', searchQuery); + else url.searchParams.delete('search'); + history.replaceState(history.state, '', url); + }, 500); + } + async function loadMore() { if (loading || !hasMore) return; - loading = true; error = null; - try { - const response = await pedimentoRegimensApi.list(currentPage + 1, pageSize); - + const response = await pedimentoRegimensApi.list(currentPage + 1, pageSize, searchQuery); if (response.error) { - console.error('📊 [Page] Error en loadMore:', response.error, 'Status:', response.status); - - // Si es un error de autenticación (401 o 403) y no se pudo refrescar, mostrar mensaje específico if (response.status === 401 || response.status === 403) { error = 'Sesión expirada. Recargando página...'; - // Recargar automáticamente después de 2 segundos - setTimeout(() => { - window.location.reload(); - }, 2000); + setTimeout(() => window.location.reload(), 2000); } else { error = response.error; } return; } - if (response.data?.items) { - // Agregar los nuevos items al array existente allItems = [...allItems, ...response.data.items]; currentPage++; totalItems = response.data.total; } } catch (e) { error = 'Error cargando más datos'; - console.error('📊 [Page] Error loading more:', e); } finally { loading = false; } } function reloadData() { - // Reset y recargar desde el principio window.location.reload(); } - function handleCreateClick() { - showCreateDialog = true; - } - function handleSuccess() { - // Recargar datos después de crear/editar/eliminar reloadData(); } - // Keyboard Shortcuts useShortcuts('Regímenes', [ - { - key: 'Alt+Shift+N', - description: 'Nuevo Régimen', - action: handleCreateClick - }, - { - key: 'Alt+Shift+R', - description: 'Actualizar Lista', - action: reloadData - } + { key: 'Alt+Shift+R', description: 'Actualizar Lista', action: reloadData } ]); - // Crear columnas con el callback onSuccess const columns = createColumns(handleSuccess); -
- -
-
-

Regímenes de Pedimento

-

Gestiona los regímenes aduaneros de pedimento

+
+ +
+
+

+ Regímenes +

+

+ Gestiona los regímenes aduaneros de pedimento +

+
+
+
-
- {#if error} - - - Error - {error} - - +
+ {error} +
{/if} - - - -
-
- Listado de Regímenes de Pedimento - - Mostrando {allItems.length} de {totalItems} registros - -
- -
-
- - - - + +
Listado de Regímenes
+
-
- - +
Mostrando {allItems.length} de {totalItems} registros
+
diff --git a/frontend/src/routes/dashboard/reference_data/sectors/+page.svelte b/frontend/src/routes/dashboard/reference_data/sectors/+page.svelte index f944f18f..863da60e 100644 --- a/frontend/src/routes/dashboard/reference_data/sectors/+page.svelte +++ b/frontend/src/routes/dashboard/reference_data/sectors/+page.svelte @@ -4,56 +4,30 @@ import { companyStore } from '$lib/stores/company.svelte'; import DataTable from '$lib/components/dashboard/reference_data/sectors/data-table.svelte'; import { createColumns } from '$lib/components/dashboard/reference_data/sectors/columns.js'; - 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 { useShortcuts } from '$lib/hooks/use-shortcuts'; - import { obtenerAtajosLista } from '$lib/config/shortcuts/dashboard/reference_data/sectors/list'; + import { Input } from '$lib/components/ui/input'; + import { page } from '$app/stores'; import { browser } from '$app/environment'; + import { RefreshCw } from 'lucide-svelte'; + import { useShortcuts } from '$lib/hooks/use-shortcuts'; + import type { PageData } from './$types'; // Los datos iniciales vienen del servidor let { data }: { data: PageData } = $props(); - - // Estado para el diálogo de crear - let showCreateDialog = $state(false); - // Atajos - useShortcuts( - 'Lista Sectores', - obtenerAtajosLista({ - manejarNuevo: () => (showCreateDialog = true), - manejarActualizar: reloadData - }) - ); - - // Sincronizar token de cookies a localStorage al montar el componente + // Sincronizar token de cookies onMount(() => { if (browser) { - // Función para obtener el valor de una cookie const getCookie = (name: string): string | null => { const value = `; ${document.cookie}`; const parts = value.split(`; ${name}=`); if (parts.length === 2) return parts.pop()?.split(';').shift() || null; return null; }; - - // Verificar si hay token en las cookies const cookieToken = getCookie('access_token'); const localToken = localStorage.getItem('access_token'); - - if (cookieToken && cookieToken !== localToken) { - localStorage.setItem('access_token', cookieToken); - } - - // También sincronizar refresh_token si existe - const cookieRefreshToken = getCookie('refresh_token'); - const localRefreshToken = localStorage.getItem('refresh_token'); - - if (cookieRefreshToken && cookieRefreshToken !== localRefreshToken) { - localStorage.setItem('refresh_token', cookieRefreshToken); - } + if (cookieToken && cookieToken !== localToken) localStorage.setItem('access_token', cookieToken); } }); @@ -66,121 +40,128 @@ let hasMore = $derived(allItems.length < totalItems); let error = $state(data.error || null); + // Filtros + let searchQuery = $state($page.url.searchParams.get('search') || ''); + let timeout: ReturnType; + + function getActiveCompanyId(): number | null { + const fromStore = companyStore.activeCompany?.id; + if (fromStore) return fromStore; + if (!browser) return null; + const cookie = document.cookie + .split('; ') + .find((row) => row.startsWith('active_company_id=')) + ?.split('=')[1]; + if (!cookie) return null; + const parsed = Number(cookie); + return Number.isFinite(parsed) ? parsed : null; + } + + function handleSearch() { + if (!browser) return; + clearTimeout(timeout); + timeout = setTimeout(async () => { + loading = true; + try { + const companyId = getActiveCompanyId(); + if (!companyId) { + error = 'No hay empresa activa seleccionada'; + return; + } + const response = await sectorsApi.list(1, pageSize, companyId, searchQuery); + if (!response.error && response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (e) { + console.error('Error aplicando filtros:', e); + } finally { + loading = false; + } + const url = new URL($page.url); + if (searchQuery) url.searchParams.set('search', searchQuery); + else url.searchParams.delete('search'); + history.replaceState(history.state, '', url); + }, 500); + } + async function loadMore() { if (loading || !hasMore) return; - loading = true; error = null; - - try { - const companyId = companyStore.activeCompany?.id; - if (!companyId) { - error = 'No hay empresa activa seleccionada'; - return; - } - const response = await sectorsApi.list(currentPage + 1, pageSize, companyId); - + try { + const companyId = getActiveCompanyId(); + if (!companyId) { + error = 'No hay empresa activa seleccionada'; + return; + } + const response = await sectorsApi.list(currentPage + 1, pageSize, companyId, searchQuery); if (response.error) { - console.error('📊 [Page] Error en loadMore:', response.error, 'Status:', response.status); - - // Si es un error de autenticación (401 o 403) y no se pudo refrescar, mostrar mensaje específico if (response.status === 401 || response.status === 403) { error = 'Sesión expirada. Recargando página...'; - // Recargar automáticamente después de 2 segundos - setTimeout(() => { - window.location.reload(); - }, 2000); + setTimeout(() => window.location.reload(), 2000); } else { error = response.error; } return; } - - if (response.data?.items) { - // Agregar los nuevos items al array existente + if (response.data?.items) { allItems = [...allItems, ...response.data.items]; currentPage++; totalItems = response.data.total; } } catch (e) { error = 'Error cargando más datos'; - console.error('📊 [Page] Error loading more:', e); } finally { loading = false; } } function reloadData() { - // Reset y recargar desde el principio window.location.reload(); } - function handleCreateClick() { - showCreateDialog = true; - } - function handleSuccess() { - // Recargar datos después de crear/editar/eliminar reloadData(); } - // Crear columnas con el callback onSuccess + useShortcuts('Sectores', [ + { key: 'Alt+Shift+R', description: 'Actualizar Lista', action: reloadData } + ]); + const columns = createColumns(handleSuccess); -
- -
-
-

Sectores

+
+ +
+
+

+ Sectores +

- Gestiona los sectores económicos + Gestiona los sectores económicos del sistema

- +
+ +
- {#if error} - - - Error - {error} - - +
+ {error} +
{/if} - - - -
-
- Listado de Sectores - - Mostrando {allItems.length} de {totalItems} registros - -
- -
-
- - - - + +
Listado de Sectores
+
-
- - +
Mostrando {allItems.length} de {totalItems} registros
+
diff --git a/frontend/src/routes/dashboard/reference_data/states/+page.svelte b/frontend/src/routes/dashboard/reference_data/states/+page.svelte index bae3c744..9153e117 100644 --- a/frontend/src/routes/dashboard/reference_data/states/+page.svelte +++ b/frontend/src/routes/dashboard/reference_data/states/+page.svelte @@ -3,29 +3,26 @@ import { statesApi, type State } from '$lib/api/dashboard/reference_data/states'; import DataTable from '$lib/components/dashboard/reference_data/states/data-table.svelte'; import { createColumns } from '$lib/components/dashboard/reference_data/states/columns.js'; - import CreateEditDialog from '$lib/components/dashboard/reference_data/states/create-edit-dialog.svelte'; import * as Card from '$lib/components/ui/card'; import { Button } from '$lib/components/ui/button'; + import { Input } from '$lib/components/ui/input'; import type { PageData } from './$types'; import { useShortcuts } from '$lib/hooks/use-shortcuts'; - import { obtenerAtajosLista } from '$lib/config/shortcuts/dashboard/reference_data/states/list'; import { browser } from '$app/environment'; - import { Plus, RefreshCw } from 'lucide-svelte'; + import { page } from '$app/stores'; + import { RefreshCw } from 'lucide-svelte'; // Los datos iniciales vienen del servidor let { data }: { data: PageData } = $props(); - - // Estado para el diálogo de crear - let showCreateDialog = $state(false); - // Atajos - useShortcuts( - 'Lista Estados', - obtenerAtajosLista({ - manejarNuevo: () => (showCreateDialog = true), - manejarActualizar: reloadData - }) - ); + // Keyboard Shortcuts + useShortcuts('Estados', [ + { + key: 'Alt+Shift+R', + description: 'Actualizar Lista', + action: reloadData + } + ]); // Sincronizar token de cookies a localStorage al montar el componente onMount(() => { @@ -65,6 +62,34 @@ let hasMore = $derived(allItems.length < totalItems); let error = $state(data.error || null); + // Filtros + let searchQuery = $state($page.url.searchParams.get('search') || ''); + let timeout: ReturnType; + + function handleSearch() { + if (!browser) return; + clearTimeout(timeout); + timeout = setTimeout(async () => { + loading = true; + try { + const response = await statesApi.list(1, pageSize, searchQuery); + if (!response.error && response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (e) { + console.error('Error aplicando filtros:', e); + } finally { + loading = false; + } + const url = new URL($page.url); + if (searchQuery) url.searchParams.set('search', searchQuery); + else url.searchParams.delete('search'); + history.replaceState(history.state, '', url); + }, 500); + } + async function loadMore() { if (loading || !hasMore) return; @@ -72,7 +97,7 @@ error = null; try { - const response = await statesApi.list(currentPage + 1, pageSize); + const response = await statesApi.list(currentPage + 1, pageSize, searchQuery); if (response.error) { console.error('📊 [Page] Error en loadMore:', response.error, 'Status:', response.status); @@ -109,10 +134,6 @@ window.location.reload(); } - function handleCreateClick() { - showCreateDialog = true; - } - function handleSuccess() { // Recargar datos después de crear/editar/eliminar reloadData(); @@ -122,59 +143,35 @@ const columns = createColumns(handleSuccess); -
- -
-
-

Estados

+
+ +
+
+

+ Estados +

Gestiona los estados y sus claves de identificación

- +
+ +
- {#if error} - - - Error - {error} - - +
+ {error} +
{/if} - - - -
-
- Listado de Estados - - Mostrando {allItems.length} de {totalItems} registros - -
- -
-
- - - - + +
Listado de Estados
+
-
- - +
Mostrando {allItems.length} de {totalItems} registros
+
diff --git a/frontend/src/routes/dashboard/reference_data/transport_modes/+page.svelte b/frontend/src/routes/dashboard/reference_data/transport_modes/+page.svelte index 511ac0e4..15541683 100644 --- a/frontend/src/routes/dashboard/reference_data/transport_modes/+page.svelte +++ b/frontend/src/routes/dashboard/reference_data/transport_modes/+page.svelte @@ -3,56 +3,30 @@ import { transportModesApi, type TransportMode } from '$lib/api/dashboard/reference_data/transport_modes'; import DataTable from '$lib/components/dashboard/reference_data/transport_modes/data-table.svelte'; import { createColumns } from '$lib/components/dashboard/reference_data/transport_modes/columns.js'; - import CreateEditDialog from '$lib/components/dashboard/reference_data/transport_modes/create-edit-dialog.svelte'; import * as Card from '$lib/components/ui/card'; import { Button } from '$lib/components/ui/button'; - import type { PageData } from './$types'; - import { useShortcuts } from '$lib/hooks/use-shortcuts'; - import { obtenerAtajosLista } from '$lib/config/shortcuts/dashboard/reference_data/transport_modes/list'; + import { Input } from '$lib/components/ui/input'; + import { page } from '$app/stores'; import { browser } from '$app/environment'; - import { Plus, RefreshCw } from 'lucide-svelte'; + import { RefreshCw } from 'lucide-svelte'; + import { useShortcuts } from '$lib/hooks/use-shortcuts'; + import type { PageData } from './$types'; // Los datos iniciales vienen del servidor let { data }: { data: PageData } = $props(); - - // Estado para el diálogo de crear - let showCreateDialog = $state(false); - // Atajos - useShortcuts( - 'Lista Modos de Transporte', - obtenerAtajosLista({ - manejarNuevo: () => (showCreateDialog = true), - manejarActualizar: reloadData - }) - ); - - // Sincronizar token de cookies a localStorage al montar el componente + // Sincronizar token de cookies onMount(() => { if (browser) { - // Función para obtener el valor de una cookie const getCookie = (name: string): string | null => { const value = `; ${document.cookie}`; const parts = value.split(`; ${name}=`); if (parts.length === 2) return parts.pop()?.split(';').shift() || null; return null; }; - - // Verificar si hay token en las cookies const cookieToken = getCookie('access_token'); const localToken = localStorage.getItem('access_token'); - - if (cookieToken && cookieToken !== localToken) { - localStorage.setItem('access_token', cookieToken); - } - - // También sincronizar refresh_token si existe - const cookieRefreshToken = getCookie('refresh_token'); - const localRefreshToken = localStorage.getItem('refresh_token'); - - if (cookieRefreshToken && cookieRefreshToken !== localRefreshToken) { - localStorage.setItem('refresh_token', cookieRefreshToken); - } + if (cookieToken && cookieToken !== localToken) localStorage.setItem('access_token', cookieToken); } }); @@ -65,116 +39,105 @@ let hasMore = $derived(allItems.length < totalItems); let error = $state(data.error || null); + // Filtros + let searchQuery = $state($page.url.searchParams.get('search') || ''); + let timeout: ReturnType; + + function handleSearch() { + if (!browser) return; + clearTimeout(timeout); + timeout = setTimeout(async () => { + loading = true; + try { + const response = await transportModesApi.list(1, pageSize, searchQuery); + if (!response.error && response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (e) { + console.error('Error aplicando filtros:', e); + } finally { + loading = false; + } + const url = new URL($page.url); + if (searchQuery) url.searchParams.set('search', searchQuery); + else url.searchParams.delete('search'); + history.replaceState(history.state, '', url); + }, 500); + } + async function loadMore() { if (loading || !hasMore) return; - loading = true; error = null; - - try { - const response = await transportModesApi.list(currentPage + 1, pageSize); - + try { + const response = await transportModesApi.list(currentPage + 1, pageSize, searchQuery); if (response.error) { - console.error('📊 [Page] Error en loadMore:', response.error, 'Status:', response.status); - - // Si es un error de autenticación (401 o 403) y no se pudo refrescar, mostrar mensaje específico if (response.status === 401 || response.status === 403) { error = 'Sesión expirada. Recargando página...'; - // Recargar automáticamente después de 2 segundos - setTimeout(() => { - window.location.reload(); - }, 2000); + setTimeout(() => window.location.reload(), 2000); } else { error = response.error; } return; } - - if (response.data?.items) { - // Agregar los nuevos items al array existente + if (response.data?.items) { allItems = [...allItems, ...response.data.items]; currentPage++; totalItems = response.data.total; } } catch (e) { error = 'Error cargando más datos'; - console.error('📊 [Page] Error loading more:', e); } finally { loading = false; } } function reloadData() { - // Reset y recargar desde el principio window.location.reload(); } - function handleCreateClick() { - showCreateDialog = true; - } - function handleSuccess() { - // Recargar datos después de crear/editar/eliminar reloadData(); } - // Crear columnas con el callback onSuccess + useShortcuts('Modos de Transporte', [ + { key: 'Alt+Shift+R', description: 'Actualizar Lista', action: reloadData } + ]); + const columns = createColumns(handleSuccess); -
- -
-
-

Modos de Transporte

+
+ +
+
+

+ Modos de Transporte +

- Gestiona los modos de transporte disponibles + Gestiona los modos de transporte disponibles en el sistema

- +
+ +
- {#if error} - - - Error - {error} - - +
+ {error} +
{/if} - - - -
-
- Listado de Modos de Transporte - - Mostrando {allItems.length} de {totalItems} registros - -
- -
-
- - - - + +
Listado de Modos de Transporte
+
-
- - +
Mostrando {allItems.length} de {totalItems} registros
+
diff --git a/frontend/src/routes/dashboard/reference_data/transport_types/+page.svelte b/frontend/src/routes/dashboard/reference_data/transport_types/+page.svelte index 6506fd52..dd9fcc29 100644 --- a/frontend/src/routes/dashboard/reference_data/transport_types/+page.svelte +++ b/frontend/src/routes/dashboard/reference_data/transport_types/+page.svelte @@ -3,56 +3,30 @@ import { transportTypesApi, type TransportType } from '$lib/api/dashboard/reference_data/transport_types'; import DataTable from '$lib/components/dashboard/reference_data/transport_types/data-table.svelte'; import { createColumns } from '$lib/components/dashboard/reference_data/transport_types/columns.js'; - 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 { useShortcuts } from '$lib/hooks/use-shortcuts'; - import { obtenerAtajosLista } from '$lib/config/shortcuts/dashboard/reference_data/transport_types/list'; + import { Input } from '$lib/components/ui/input'; + import { page } from '$app/stores'; import { browser } from '$app/environment'; + import { RefreshCw } from 'lucide-svelte'; + import { useShortcuts } from '$lib/hooks/use-shortcuts'; + import type { PageData } from './$types'; // Los datos iniciales vienen del servidor let { data }: { data: PageData } = $props(); - - // Estado para el diálogo de crear - let showCreateDialog = $state(false); - // Atajos - useShortcuts( - 'Lista Tipos de Transporte', - obtenerAtajosLista({ - manejarNuevo: () => (showCreateDialog = true), - manejarActualizar: reloadData - }) - ); - - // Sincronizar token de cookies a localStorage al montar el componente + // Sincronizar token de cookies onMount(() => { if (browser) { - // Función para obtener el valor de una cookie const getCookie = (name: string): string | null => { const value = `; ${document.cookie}`; const parts = value.split(`; ${name}=`); if (parts.length === 2) return parts.pop()?.split(';').shift() || null; return null; }; - - // Verificar si hay token en las cookies const cookieToken = getCookie('access_token'); const localToken = localStorage.getItem('access_token'); - - if (cookieToken && cookieToken !== localToken) { - localStorage.setItem('access_token', cookieToken); - } - - // También sincronizar refresh_token si existe - const cookieRefreshToken = getCookie('refresh_token'); - const localRefreshToken = localStorage.getItem('refresh_token'); - - if (cookieRefreshToken && cookieRefreshToken !== localRefreshToken) { - localStorage.setItem('refresh_token', cookieRefreshToken); - } + if (cookieToken && cookieToken !== localToken) localStorage.setItem('access_token', cookieToken); } }); @@ -65,116 +39,105 @@ let hasMore = $derived(allItems.length < totalItems); let error = $state(data.error || null); + // Filtros + let searchQuery = $state($page.url.searchParams.get('search') || ''); + let timeout: ReturnType; + + function handleSearch() { + if (!browser) return; + clearTimeout(timeout); + timeout = setTimeout(async () => { + loading = true; + try { + const response = await transportTypesApi.list(1, pageSize, searchQuery); + if (!response.error && response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (e) { + console.error('Error aplicando filtros:', e); + } finally { + loading = false; + } + const url = new URL($page.url); + if (searchQuery) url.searchParams.set('search', searchQuery); + else url.searchParams.delete('search'); + history.replaceState(history.state, '', url); + }, 500); + } + async function loadMore() { if (loading || !hasMore) return; - loading = true; error = null; - - try { - const response = await transportTypesApi.list(currentPage + 1, pageSize); - + try { + const response = await transportTypesApi.list(currentPage + 1, pageSize, searchQuery); if (response.error) { - console.error('📊 [Page] Error en loadMore:', response.error, 'Status:', response.status); - - // Si es un error de autenticación (401 o 403) y no se pudo refrescar, mostrar mensaje específico if (response.status === 401 || response.status === 403) { error = 'Sesión expirada. Recargando página...'; - // Recargar automáticamente después de 2 segundos - setTimeout(() => { - window.location.reload(); - }, 2000); + setTimeout(() => window.location.reload(), 2000); } else { error = response.error; } return; } - - if (response.data?.items) { - // Agregar los nuevos items al array existente + if (response.data?.items) { allItems = [...allItems, ...response.data.items]; currentPage++; totalItems = response.data.total; } } catch (e) { error = 'Error cargando más datos'; - console.error('📊 [Page] Error loading more:', e); } finally { loading = false; } } function reloadData() { - // Reset y recargar desde el principio window.location.reload(); } - function handleCreateClick() { - showCreateDialog = true; - } - function handleSuccess() { - // Recargar datos después de crear/editar/eliminar reloadData(); } - // Crear columnas con el callback onSuccess + useShortcuts('Tipos de Transporte', [ + { key: 'Alt+Shift+R', description: 'Actualizar Lista', action: reloadData } + ]); + const columns = createColumns(handleSuccess); -
- -
-
-

Tipos de Transporte

+
+ +
+
+

+ Tipos de Transporte +

Gestiona los tipos de transporte según código SAT

- +
+ +
- {#if error} - - - Error - {error} - - +
+ {error} +
{/if} - - - -
-
- Listado de Tipos de Transporte - - Mostrando {allItems.length} de {totalItems} registros - -
- -
-
- - - - + +
Listado de Tipos de Transporte
+
-
- - +
Mostrando {allItems.length} de {totalItems} registros
+
diff --git a/frontend/src/routes/dashboard/reference_data/valuation_methods/+page.svelte b/frontend/src/routes/dashboard/reference_data/valuation_methods/+page.svelte index 59c8a0fc..03389645 100644 --- a/frontend/src/routes/dashboard/reference_data/valuation_methods/+page.svelte +++ b/frontend/src/routes/dashboard/reference_data/valuation_methods/+page.svelte @@ -3,55 +3,30 @@ import { valuationMethodsApi, type ValuationMethod } from '$lib/api/dashboard/reference_data/valuation_methods'; import DataTable from '$lib/components/dashboard/reference_data/valuation_methods/data-table.svelte'; import { createColumns } from '$lib/components/dashboard/reference_data/valuation_methods/columns.js'; - 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 { useShortcuts } from '$lib/hooks/use-shortcuts'; - import { obtenerAtajosLista } from '$lib/config/shortcuts/dashboard/reference_data/valuation_methods/list'; - import type { PageData } from './$types'; + import { Input } from '$lib/components/ui/input'; + import { page } from '$app/stores'; import { browser } from '$app/environment'; + import { RefreshCw } from 'lucide-svelte'; + import { useShortcuts } from '$lib/hooks/use-shortcuts'; + import type { PageData } from './$types'; // Los datos iniciales vienen del servidor let { data }: { data: PageData } = $props(); - - // Estado para el diálogo de crear - let showCreateDialog = $state(false); - // Atajos - useShortcuts( - 'Lista Métodos de Valoración', - obtenerAtajosLista({ - manejarNuevo: () => (showCreateDialog = true), - manejarActualizar: reloadData - }) - ); - - // Sincronizar token de cookies a localStorage al montar el componente + // Sincronizar token de cookies onMount(() => { if (browser) { - // Función para obtener el valor de una cookie const getCookie = (name: string): string | null => { const value = `; ${document.cookie}`; const parts = value.split(`; ${name}=`); if (parts.length === 2) return parts.pop()?.split(';').shift() || null; return null; }; - - // Verificar si hay token en las cookies const cookieToken = getCookie('access_token'); const localToken = localStorage.getItem('access_token'); - - if (cookieToken && cookieToken !== localToken) { - localStorage.setItem('access_token', cookieToken); - } - - // También sincronizar refresh_token si existe - const cookieRefreshToken = getCookie('refresh_token'); - const localRefreshToken = localStorage.getItem('refresh_token'); - - if (cookieRefreshToken && cookieRefreshToken !== localRefreshToken) { - localStorage.setItem('refresh_token', cookieRefreshToken); - } + if (cookieToken && cookieToken !== localToken) localStorage.setItem('access_token', cookieToken); } }); @@ -64,98 +39,105 @@ let hasMore = $derived(allItems.length < totalItems); let error = $state(data.error || null); + // Filtros + let searchQuery = $state($page.url.searchParams.get('search') || ''); + let timeout: ReturnType; + + function handleSearch() { + if (!browser) return; + clearTimeout(timeout); + timeout = setTimeout(async () => { + loading = true; + try { + const response = await valuationMethodsApi.list(1, pageSize, searchQuery); + if (!response.error && response.data) { + allItems = response.data.items; + currentPage = 1; + totalItems = response.data.total; + } + } catch (e) { + console.error('Error aplicando filtros:', e); + } finally { + loading = false; + } + const url = new URL($page.url); + if (searchQuery) url.searchParams.set('search', searchQuery); + else url.searchParams.delete('search'); + history.replaceState(history.state, '', url); + }, 500); + } + async function loadMore() { if (loading || !hasMore) return; - loading = true; error = null; - - try { - const response = await valuationMethodsApi.list(currentPage + 1, pageSize); - + try { + const response = await valuationMethodsApi.list(currentPage + 1, pageSize, searchQuery); if (response.error) { - console.error('📊 [Page] Error en loadMore:', response.error, 'Status:', response.status); - - // Si es un error de autenticación (401 o 403) y no se pudo refrescar, mostrar mensaje específico if (response.status === 401 || response.status === 403) { error = 'Sesión expirada. Recargando página...'; - // Recargar automáticamente después de 2 segundos - setTimeout(() => { - window.location.reload(); - }, 2000); + setTimeout(() => window.location.reload(), 2000); } else { error = response.error; } return; } - - if (response.data?.items) { - // Agregar los nuevos items al array existente + if (response.data?.items) { allItems = [...allItems, ...response.data.items]; currentPage++; totalItems = response.data.total; } } catch (e) { error = 'Error cargando más datos'; - console.error('📊 [Page] Error loading more:', e); } finally { loading = false; } } function reloadData() { - // Reset y recargar desde el principio window.location.reload(); } - function handleCreateClick() { - showCreateDialog = true; - } - function handleSuccess() { - // Recargar datos después de crear/editar/eliminar reloadData(); } - // Crear columnas con el callback onSuccess + useShortcuts('Métodos de Valoración', [ + { key: 'Alt+Shift+R', description: 'Actualizar Lista', action: reloadData } + ]); + const columns = createColumns(handleSuccess); -
-
-
-

Métodos de Valoración

+
+ +
+
+

+ Métodos de Valoración +

- Gestiona los métodos de valoración aduanera + Gestiona los métodos de valoración aduanera autorizados

-
- -
{#if error} -
+
{error}
{/if} -
- -
-
+ +
Listado de Métodos de Valoración
+
+
- +
Mostrando {allItems.length} de {totalItems} registros
+