diff --git a/frontend/src/lib/api/dashboard/refrence_data/countries.ts b/frontend/src/lib/api/dashboard/refrence_data/countries.ts new file mode 100644 index 00000000..66fba25e --- /dev/null +++ b/frontend/src/lib/api/dashboard/refrence_data/countries.ts @@ -0,0 +1,78 @@ +/** + * API Client para Countries + * Gestiona las operaciones CRUD para los países + */ +import { api } from '$lib/api'; + +export interface Country { + m3_key: string; + mex_key: string; + ame_key: string; + description_es: string; + description_en: string; +} + +export interface CountryListResponse { + items: Country[]; + total: number; + page: number; + page_size: number; +} + +export interface CreateCountryData { + m3_key: string; + mex_key: string; + ame_key: string; + description_es: string; + description_en: string; +} + +export interface UpdateCountryData { + m3_key?: string; + mex_key?: string; + ame_key?: string; + description_es?: string; + description_en?: string; +} + +/** + * API para Countries + */ +export const countriesApi = { + /** + * Lista todos los países con paginación + * @param page - Número de página (por defecto 1) + * @param pageSize - Tamaño de página (por defecto 50) + */ + list: (page = 1, pageSize = 50) => + api.get( + `/v1/countries?page=${page}&page_size=${pageSize}` + ), + + /** + * Obtiene un país por su clave M3 + * @param m3_key - Clave M3 del país + */ + get: (m3_key: string) => api.get(`/v1/countries/${m3_key}`), + + /** + * Crea un nuevo país + * @param data - Datos del país a crear + */ + create: (data: CreateCountryData) => + api.post('/v1/countries', data), + + /** + * Actualiza un país existente + * @param m3_key - Clave M3 del país a actualizar + * @param data - Datos a actualizar + */ + update: (m3_key: string, data: UpdateCountryData) => + api.put(`/v1/countries/${m3_key}`, data), + + /** + * Elimina un país + * @param m3_key - Clave M3 del país a eliminar + */ + delete: (m3_key: string) => api.delete(`/v1/countries/${m3_key}`) +}; diff --git a/frontend/src/lib/components/dashboard/reference_data/countries/columns.ts b/frontend/src/lib/components/dashboard/reference_data/countries/columns.ts new file mode 100644 index 00000000..2b24e5e3 --- /dev/null +++ b/frontend/src/lib/components/dashboard/reference_data/countries/columns.ts @@ -0,0 +1,94 @@ +import type { ColumnDef } from "@tanstack/table-core"; +import { renderComponent, renderSnippet } from "$lib/components/ui/data-table/index.js"; +import { createRawSnippet } from "svelte"; +import DataTableActions from "./data-table-actions.svelte"; + +export type Country = { + m3_key: string; + mex_key: string; + ame_key: string; + description_es: string; + description_en: string; +}; + +export function createColumns(onSuccess?: () => void): ColumnDef[] { + return [ + { + accessorKey: "m3_key", + header: "Clave M3", + cell: ({ row }) => { + const codeSnippet = createRawSnippet<[{ code: string }]>((getCode) => { + const { code } = getCode(); + return { + render: () => + `${code}` + }; + }); + return renderSnippet(codeSnippet, { code: row.original.m3_key }); + } + }, + { + accessorKey: "mex_key", + header: "Clave MX", + cell: ({ row }) => { + const codeSnippet = createRawSnippet<[{ code: string }]>((getCode) => { + const { code } = getCode(); + return { + render: () => + `${code}` + }; + }); + return renderSnippet(codeSnippet, { code: row.original.mex_key }); + } + }, + { + accessorKey: "ame_key", + header: "Clave AME", + cell: ({ row }) => { + const codeSnippet = createRawSnippet<[{ code: string }]>((getCode) => { + const { code } = getCode(); + return { + render: () => + `${code}` + }; + }); + return renderSnippet(codeSnippet, { code: row.original.ame_key }); + } + }, + { + accessorKey: "description_es", + header: "Descripción (ES)", + cell: ({ row }) => { + const descSnippet = createRawSnippet<[{ description: string }]>((getDesc) => { + const { description } = getDesc(); + return { + render: () => `
${description}
` + }; + }); + return renderSnippet(descSnippet, { description: row.original.description_es }); + } + }, + { + accessorKey: "description_en", + header: "Descripción (EN)", + cell: ({ row }) => { + const descSnippet = createRawSnippet<[{ description: string }]>((getDesc) => { + const { description } = getDesc(); + return { + render: () => `
${description}
` + }; + }); + return renderSnippet(descSnippet, { description: row.original.description_en }); + } + }, + { + id: "actions", + cell: ({ row }) => { + return renderComponent(DataTableActions, { item: row.original, onSuccess }); + } + } + ]; +} + +// Mantener compatibilidad hacia atrás +export const columns = createColumns(); diff --git a/frontend/src/lib/components/dashboard/reference_data/countries/create-edit-dialog.svelte b/frontend/src/lib/components/dashboard/reference_data/countries/create-edit-dialog.svelte new file mode 100644 index 00000000..10ef56e8 --- /dev/null +++ b/frontend/src/lib/components/dashboard/reference_data/countries/create-edit-dialog.svelte @@ -0,0 +1,239 @@ + + + + + + + {isEditing ? "Editar" : "Nuevo"} País + + + {isEditing + ? "Modifica los datos del país." + : "Completa los datos para crear un nuevo país."} + + + +
+ {#if error} +
+ {error} +
+ {/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 new file mode 100644 index 00000000..1f5a9021 --- /dev/null +++ b/frontend/src/lib/components/dashboard/reference_data/countries/data-table-actions.svelte @@ -0,0 +1,66 @@ + + + + + {#snippet child({ props })} + + {/snippet} + + + + Acciones + + Copiar ID + + + + 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 new file mode 100644 index 00000000..ef98de23 --- /dev/null +++ b/frontend/src/lib/components/dashboard/reference_data/countries/data-table.svelte @@ -0,0 +1,123 @@ + + +
+
+ + + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} + + {#each headerGroup.headers as header (header.id)} + + {#if !header.isPlaceholder} + + {/if} + + {/each} + + {/each} + + + {#each table.getRowModel().rows as row (row.id)} + + {#each row.getVisibleCells() as cell (cell.id)} + + + + {/each} + + {:else} + + + No hay resultados. + + + {/each} + + + {#if hasMore} + + +
+ {#if loading} +
+
+ Cargando más... +
+ {:else} +
+ Desplázate para cargar más +
+ {/if} +
+
+
+ {/if} +
+
+
+
diff --git a/frontend/src/lib/components/dashboard/reference_data/countries/delete-dialog.svelte b/frontend/src/lib/components/dashboard/reference_data/countries/delete-dialog.svelte new file mode 100644 index 00000000..da7dbdd0 --- /dev/null +++ b/frontend/src/lib/components/dashboard/reference_data/countries/delete-dialog.svelte @@ -0,0 +1,116 @@ + + + + + + ¿Estás seguro? + +

Esta acción no se puede deshacer. Se eliminará permanentemente este país:

+ {#if item} +
+
+ Clave M3: + {item.m3_key} +
+
+ Clave MX: + {item.mex_key} +
+
+ Descripción: + {item.description_es} +
+
+ {/if} + {#if error} +
+ {error} +
+ {/if} +
+
+ + Cancelar + + {#if loading} + + + + + {/if} + Eliminar + + +
+
diff --git a/frontend/src/lib/components/dashboard/reference_data/countries/details-dialog.svelte b/frontend/src/lib/components/dashboard/reference_data/countries/details-dialog.svelte new file mode 100644 index 00000000..b13a4c14 --- /dev/null +++ b/frontend/src/lib/components/dashboard/reference_data/countries/details-dialog.svelte @@ -0,0 +1,79 @@ + + + + + + Detalles del País + + Información completa del país + + + + {#if item} +
+
+
+ Clave M3 + + {item.m3_key} + +
+ +
+ Clave MX + + {item.mex_key} + +
+ +
+ Clave AME + + {item.ame_key} + +
+
+ + +
+
+ Descripción en Español +

{item.description_es}

+
+ +
+ +
+
+ Descripción en Inglés +

{item.description_en}

+
+ +
+
+ {/if} + + + + +
+
diff --git a/frontend/src/routes/dashboard/reference_data/countries/+page.server.ts b/frontend/src/routes/dashboard/reference_data/countries/+page.server.ts new file mode 100644 index 00000000..3c8e022c --- /dev/null +++ b/frontend/src/routes/dashboard/reference_data/countries/+page.server.ts @@ -0,0 +1,81 @@ +import type { PageServerLoad } from './$types'; + +export const load: PageServerLoad = async ({ cookies, fetch, url, parent }) => { + // Esperar a que el layout padre valide/refresque el token + await parent(); + + const token = cookies.get('access_token'); + + if (!token) { + return { + error: 'No authenticated', + items: [], + total: 0, + page: 1, + page_size: 50 + }; + } + + try { + // Obtener parámetros de paginación de la URL + const page = parseInt(url.searchParams.get('page') || '1'); + const pageSize = parseInt(url.searchParams.get('page_size') || '50'); + + // Configurar la URL de la API para SSR + let apiUrl = process.env.INTERNAL_API_URL; + if (!apiUrl) { + apiUrl = import.meta.env.VITE_API_URL; + // Reemplazar 'localhost' con 'backend' para llamadas desde el servidor (SSR) + apiUrl = apiUrl?.replace('localhost', 'backend').replace('127.0.0.1', 'backend'); + } + + // Normalizar la URL + const baseUrl = apiUrl?.endsWith('/') ? apiUrl : `${apiUrl}/`; + + const response = await fetch( + `${baseUrl}v1/countries?page=${page}&page_size=${pageSize}`, + { + headers: { + 'Authorization': `Bearer ${token}`, + 'Content-Type': 'application/json' + } + } + ); + + if (!response.ok) { + const errorText = await response.text(); + console.error('📊 [Countries] API Error:', { + status: response.status, + statusText: response.statusText, + error: errorText + }); + + return { + error: `Error ${response.status}: ${response.statusText}`, + items: [], + total: 0, + page: page, + page_size: pageSize + }; + } + + const data = await response.json(); + + return { + items: data.items || [], + total: data.total || 0, + page: data.page || page, + page_size: data.page_size || pageSize, + error: null + }; + } catch (error) { + console.error('📊 [Countries] Load error:', error); + return { + error: 'Error loading data', + items: [], + total: 0, + page: 1, + page_size: 50 + }; + } +}; diff --git a/frontend/src/routes/dashboard/reference_data/countries/+page.svelte b/frontend/src/routes/dashboard/reference_data/countries/+page.svelte new file mode 100644 index 00000000..fd5ec3ef --- /dev/null +++ b/frontend/src/routes/dashboard/reference_data/countries/+page.svelte @@ -0,0 +1,196 @@ + + +
+ +
+
+

Países

+

+ Gestiona los países disponibles en el sistema +

+
+ +
+ + + {#if error} + + + 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 new file mode 100644 index 00000000..e69de29b