diff --git a/frontend/src/lib/config/shortcuts.ts b/frontend/src/lib/config/shortcuts.ts index 13ad46de..f3b5e82f 100644 --- a/frontend/src/lib/config/shortcuts.ts +++ b/frontend/src/lib/config/shortcuts.ts @@ -22,6 +22,9 @@ export const GLOBAL_NAV = { // Customs & Brokers 'a': '/dashboard/customs_brokers', + // Clients & Providers + 'o': '/dashboard/clients_and_providers', + // Invoices 'i': '/dashboard/invoices', diff --git a/frontend/src/lib/config/shortcuts/clients-providers-edit-shortcuts.ts b/frontend/src/lib/config/shortcuts/clients-providers-edit-shortcuts.ts new file mode 100644 index 00000000..8d2e4c35 --- /dev/null +++ b/frontend/src/lib/config/shortcuts/clients-providers-edit-shortcuts.ts @@ -0,0 +1,41 @@ +import type { ShortcutDef } from '$lib/stores/shortcut-store'; + +export const obtenerAtajosEdicionSocio = (acciones: { + irGeneral: () => void; + irDireccion: () => void; + irProgramas: () => void; + irConfig: () => void; + guardar: () => void; + cancelar: () => void; +}): ShortcutDef[] => [ + { + key: 'Alt+Digit1', + description: 'Tab General', + action: acciones.irGeneral + }, + { + key: 'Alt+Digit2', + description: 'Tab Dirección', + action: acciones.irDireccion + }, + { + key: 'Alt+Digit3', + description: 'Tab Programas', + action: acciones.irProgramas + }, + { + key: 'Alt+Digit4', + description: 'Tab Configuración', + action: acciones.irConfig + }, + { + key: 'Ctrl+S', + description: 'Guardar', + action: acciones.guardar + }, + { + key: 'Escape', + description: 'Cancelar / Volver', + action: acciones.cancelar + } + ]; diff --git a/frontend/src/lib/config/shortcuts/clients-providers-list-shortcuts.ts b/frontend/src/lib/config/shortcuts/clients-providers-list-shortcuts.ts new file mode 100644 index 00000000..6de7f9f2 --- /dev/null +++ b/frontend/src/lib/config/shortcuts/clients-providers-list-shortcuts.ts @@ -0,0 +1,38 @@ +import type { ShortcutDef } from '$lib/stores/shortcut-store'; + +export const obtenerAtajosListaSocios = (acciones: { + filtrarTodos: () => void; + filtrarClientes: () => void; + filtrarProveedores: () => void; + nuevo: () => void; + recargar: () => void; +}): ShortcutDef[] => [ + { + key: 'Alt+Digit1', + description: 'Ver Todos', + action: acciones.filtrarTodos, + context: 'Clients Providers Navigation' + }, + { + key: 'Alt+Digit2', + description: 'Ver Clientes', + action: acciones.filtrarClientes, + context: 'Clients Providers Navigation' + }, + { + key: 'Alt+Digit3', + description: 'Ver Proveedores', + action: acciones.filtrarProveedores, + context: 'Clients Providers Navigation' + }, + { + key: 'Alt+Shift+N', + description: 'Nuevo Socio', + action: acciones.nuevo + }, + { + key: 'Alt+Shift+R', + description: 'Actualizar Lista', + action: acciones.recargar + } + ]; diff --git a/frontend/src/routes/dashboard/clients_and_providers/+page.svelte b/frontend/src/routes/dashboard/clients_and_providers/+page.svelte index 173101a7..27bc72fb 100644 --- a/frontend/src/routes/dashboard/clients_and_providers/+page.svelte +++ b/frontend/src/routes/dashboard/clients_and_providers/+page.svelte @@ -3,7 +3,10 @@ import { browser } from '$app/environment'; import { goto } from '$app/navigation'; import { page } from '$app/stores'; - import { clientsProvidersApi, type ClientProvider } from '$lib/api/dashboard/a76/clients-providers'; + import { + clientsProvidersApi, + type ClientProvider + } from '$lib/api/dashboard/a76/clients-providers'; import { Button } from '$lib/components/ui/button'; import * as Card from '$lib/components/ui/card'; import { Input } from '$lib/components/ui/input'; @@ -21,7 +24,7 @@ let items = $state(data.items || []); let selectedItem = $state(null); let isLoading = $state(false); - + // Server-side filtering/pagination parameters let currentPage = $state(data.page || 1); let pageSize = $state(50); @@ -37,7 +40,7 @@ let error = $state(data.error || null); // --- Lifecycle --- - + onMount(() => { if (browser) { // Sincronizar token de cookies a localStorage si es necesario @@ -49,7 +52,8 @@ }; const cookieToken = getCookie('access_token'); const localToken = localStorage.getItem('access_token'); - if (cookieToken && cookieToken !== localToken) localStorage.setItem('access_token', cookieToken); + if (cookieToken && cookieToken !== localToken) + localStorage.setItem('access_token', cookieToken); // Listen for company changes const handleCompanyChange = () => loadItems(1); // Reload from page 1 @@ -68,9 +72,9 @@ try { const filters: any = {}; if (searchType !== 'both') filters.type = searchType; - // Note: The API technically supports name/rfc fitlering if backend implements it. - // Assuming backend supports 'name' and 'rfc' query params based on standard patterns, - // or we filter client side if the list is small. + // Note: The API technically supports name/rfc fitlering if backend implements it. + // Assuming backend supports 'name' and 'rfc' query params based on standard patterns, + // or we filter client side if the list is small. // Given pagination, we should try sending them. If backend ignores them, we might need client filtering. // Ideally backend should handle this. I will assume backend filters for now or add query params. if (searchName) filters.name = searchName; @@ -105,7 +109,7 @@ searchType = value; loadItems(1); } - + function handleSearch() { loadItems(1); } @@ -118,10 +122,13 @@ if (selectedItem) goto(`/dashboard/clients_and_providers/edit/${selectedItem.id}`); } + import { useShortcuts } from '$lib/hooks/use-shortcuts'; + import { obtenerAtajosListaSocios } from '$lib/config/shortcuts/clients-providers-list-shortcuts'; + async function handleDelete() { if (!selectedItem || !companyStore.activeCompany?.id) return; if (!confirm('¿Estás seguro de eliminar este registro?')) return; - + try { await clientsProvidersApi.delete(selectedItem.id, companyStore.activeCompany.id); toast.success('Registro eliminado'); @@ -132,6 +139,16 @@ } } + useShortcuts( + 'Clients Providers List', + obtenerAtajosListaSocios({ + filtrarTodos: () => handleTypeChange('both'), + filtrarClientes: () => handleTypeChange('client'), + filtrarProveedores: () => handleTypeChange('provider'), + nuevo: () => goto('/dashboard/clients_and_providers/edit/new'), + recargar: () => loadItems(1) + }) + );
@@ -145,7 +162,9 @@ {#if error} - + Error @@ -168,18 +187,18 @@
- e.key === 'Enter' && handleSearch()} />
- e.key === 'Enter' && handleSearch()} /> @@ -188,7 +207,11 @@ - {searchType === 'both' ? 'Todos' : searchType === 'client' ? 'Clientes' : 'Proveedores'} + {searchType === 'both' + ? 'Todos' + : searchType === 'client' + ? 'Clientes' + : 'Proveedores'} Todos @@ -234,13 +257,23 @@ {#if isLoading} - Cargando... + Cargando... {:else if items.length === 0} - No se encontraron registros + No se encontraron registros {:else} {#each items as item (item.id)} - selectItem(item)} > {item.id} @@ -248,15 +281,28 @@ {item.name} {#if item.client_or_provider === 'client'} - Cliente + Cliente {:else if item.client_or_provider === 'provider'} - Proveedor + Proveedor {:else} - Ambos + Ambos {/if} - + {item.is_active ? 'Activo' : 'Inactivo'} @@ -266,113 +312,140 @@
- -
- - - Página {currentPage} de {Math.ceil(totalItems / pageSize)} - - -
+ +
+ + + Página {currentPage} de {Math.ceil(totalItems / pageSize)} + + +
-
+
-

Detalles del Registro

-

+

+ Detalles del Registro +

+

{selectedItem?.name || '---'}

-
- {selectedItem?.rfc || ''} -
+
+ {selectedItem?.rfc || ''} +
{#if selectedItem}
-
- -

{selectedItem.client_or_provider}

-
- - {#if selectedItem.address} -
- -
-

{selectedItem.address.streets || ''} {selectedItem.address.exterior_number || ''} {selectedItem.address.interior_number ? 'Int ' + selectedItem.address.interior_number : ''}

-

{selectedItem.address.neighborhood || ''}

-

{selectedItem.address.city || ''}, {selectedItem.address.state || ''}

-

{selectedItem.address.postal_code || ''}, {selectedItem.address.country || ''}

-
-
- -
- - {#if selectedItem.address.email} -
- - {selectedItem.address.email} -
- {/if} - {#if selectedItem.address.phone} -
- - {selectedItem.address.phone} -
- {/if} -
- {:else} -
-

Sin dirección registrada

-
- {/if} +
+ +

{selectedItem.client_or_provider}

+
- {#if selectedItem.programs} -
- -
-
- Programa - {selectedItem.programs.program || '-'} -
-
- Número - {selectedItem.programs.program_number || '-'} -
-
- TAX ID - {selectedItem.programs.tax_id || '-'} -
-
-
- {/if} + {#if selectedItem.address} +
+ +
+

+ {selectedItem.address.streets || ''} + {selectedItem.address.exterior_number || ''} + {selectedItem.address.interior_number + ? 'Int ' + selectedItem.address.interior_number + : ''} +

+

{selectedItem.address.neighborhood || ''}

+

{selectedItem.address.city || ''}, {selectedItem.address.state || ''}

+

+ {selectedItem.address.postal_code || ''}, {selectedItem.address.country || ''} +

+
+
+ +
+ + {#if selectedItem.address.email} +
+ + {selectedItem.address.email} +
+ {/if} + {#if selectedItem.address.phone} +
+ + {selectedItem.address.phone} +
+ {/if} +
+ {:else} +
+

Sin dirección registrada

+
+ {/if} + + {#if selectedItem.programs} +
+ +
+
+ Programa + {selectedItem.programs.program || '-'} +
+
+ Número + {selectedItem.programs.program_number || '-'} +
+
+ TAX ID + {selectedItem.programs.tax_id || '-'} +
+
+
+ {/if}
{:else} -
+

Selecciona un registro

@@ -383,7 +456,9 @@
-
+
-
diff --git a/frontend/src/routes/dashboard/clients_and_providers/edit/[[id]]/+page.svelte b/frontend/src/routes/dashboard/clients_and_providers/edit/[[id]]/+page.svelte index 30b1ecd6..31c9cd50 100644 --- a/frontend/src/routes/dashboard/clients_and_providers/edit/[[id]]/+page.svelte +++ b/frontend/src/routes/dashboard/clients_and_providers/edit/[[id]]/+page.svelte @@ -1,517 +1,666 @@
- -
-
-
- -

- {isEditing ? `Socio Comercial #${id}` : 'Nuevo Socio Comercial'} -

- {#if isEditing} - - {formData.is_active ? 'Activo' : 'Inactivo'} - - {:else} - Nuevo - {/if} -
-

- {isEditing ? 'Edita la información del cliente o proveedor' : 'Registra un nuevo cliente o proveedor en el sistema'} -

-
-
+ +
+
+
+ +

+ {isEditing ? `Socio Comercial #${id}` : 'Nuevo Socio Comercial'} +

+ {#if isEditing} + + {formData.is_active ? 'Activo' : 'Inactivo'} + + {:else} + Nuevo + {/if} +
+

+ {isEditing + ? 'Edita la información del cliente o proveedor' + : 'Registra un nuevo cliente o proveedor en el sistema'} +

+
+
- + - -
-
{ e.preventDefault(); handleSubmit(); }}> - - - - - - - Información General - Datos principales de identificación y clasificación. - - -
-
- - -
-
- - - - {typeLabels[formData.client_or_provider] || "Selecciona un tipo"} - - - Cliente - Proveedor - Ambos - - -
-
+ +
+ + { + e.preventDefault(); + handleSubmit(); + }} + > + + + + + + Información General + Datos principales de identificación y clasificación. + + +
+
+ + +
+
+ + + + {typeLabels[formData.client_or_provider] || 'Selecciona un tipo'} + + + Cliente + Proveedor + Ambos + + +
+
-
-
- - -
-
- - -
-
+
+
+ + +
+
+ + +
+
-
-
- - -
-
- - - - {formData.type_nat_foreign === 'N' ? 'Nacional' : formData.type_nat_foreign === 'E' ? 'Extranjero' : 'Seleccione'} - - - Nacional - Extranjero - - -
-
+
+
+ + +
+
+ + + + {formData.type_nat_foreign === 'N' + ? 'Nacional' + : formData.type_nat_foreign === 'E' + ? 'Extranjero' + : 'Seleccione'} + + + Nacional + Extranjero + + +
+
-
-
- - -
-
- - -
-
-
-
-
+
+
+ + +
+
+ + +
+
+ + + - - - - - Dirección y Contacto - Ubicación fiscal y datos de contacto. - - -
-
- - -
-
-
- - -
-
- - -
-
-
+ + + + + Dirección y Contacto + Ubicación fiscal y datos de contacto. + + +
+
+ + +
+
+
+ + +
+
+ + +
+
+
-
-
- - -
-
- - -
-
- - -
-
+
+
+ + +
+
+ + +
+
+ + +
+
-
-
- - -
-
- - -
-
- - -
-
+
+
+ + +
+
+ + +
+
+ + +
+
- + -
-
- - -
-
- - -
-
-
-
-
+
+
+ + +
+
+ + +
+
+
+
+
- - - - - Programas y Certificaciones - Información sobre IMMEX, PROSEC y otras certificaciones. - - -
-
- - -
-
- - -
-
+ + + + + Programas y Certificaciones + Información sobre IMMEX, PROSEC y otras certificaciones. + + +
+
+ + +
+
+ + +
+
-
-
- - -
-
- - -
-
- - -
-
+
+
+ + +
+
+ + +
+
+ + +
+
-
-
- - -
-
- - -
-
-
-
-
+
+
+ + +
+
+ + +
+
+
+
+
- - - - - Configuración - Ajustes de estado y atributos especiales. - - -
-
- -
- -

Habilitar o deshabilitar este socio comercial

-
-
-
- -
- -

Marcar si es un proveedor nacional

-
-
-
-
-
-
-
- -
+ + + + + Configuración + Ajustes de estado y atributos especiales. + + +
+
+ +
+ +

+ Habilitar o deshabilitar este socio comercial +

+
+
+
+ +
+ +

Marcar si es un proveedor nacional

+
+
+
+
+
+
+
+ +
-
-
- - -
- - - General - - - Dirección - - - Programas - - - Config - - -
-
+
+
+ + +
+ + + General + + + Dirección + + + Programas + + + Config + + +
+
- -
- - {#if !isEditing} - - {/if} - -
-
-
\ No newline at end of file + +
+ + {#if !isEditing} + + {/if} + +
+
+