Movidos botones de Actualizar Est y Desactualizar
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
import type { ColumnDef } from "@tanstack/table-core";
|
||||
import { renderComponent, renderSnippet } from "$lib/components/ui/data-table/index.js";
|
||||
import { renderSnippet } from "$lib/components/ui/data-table/index.js";
|
||||
import { createRawSnippet } from "svelte";
|
||||
import DataTableActions from "./data-table-actions.svelte";
|
||||
import type { Invoice } from '$lib/api/dashboard/a76/invoices';
|
||||
import { getInvoiceTypeColor } from "$lib/utils";
|
||||
|
||||
@@ -18,29 +17,71 @@ export function createColumns(
|
||||
onSuccess?: () => void
|
||||
): ColumnDef<Invoice>[] {
|
||||
return [
|
||||
// 0. NUEVA COLUMNA: Checkbox visual (el estado real lo maneja la opacidad)
|
||||
// Checkbox visual
|
||||
{
|
||||
id: "select",
|
||||
header: ({ table }) => {
|
||||
return renderSnippet(
|
||||
createRawSnippet(() => ({
|
||||
render: () => `<div class="w-4"></div>`
|
||||
}))
|
||||
);
|
||||
const isAllSelected = table.getIsAllPageRowsSelected();
|
||||
const isSomeSelected = table.getIsSomePageRowsSelected();
|
||||
|
||||
const selectAllSnippet = createRawSnippet<[
|
||||
{ checked: boolean; indeterminate: boolean; onchange: (e: Event) => void }
|
||||
]>((getProps) => {
|
||||
const { checked, indeterminate, onchange } = getProps();
|
||||
return {
|
||||
render: () => `<div class="w-4">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="h-4 w-4 cursor-pointer"
|
||||
${checked ? 'checked' : ''}
|
||||
${indeterminate ? 'indeterminate="true"' : ''}
|
||||
/>
|
||||
</div>`,
|
||||
setup: (node) => {
|
||||
const input = node.querySelector('input') as HTMLInputElement;
|
||||
if (input) {
|
||||
input.indeterminate = indeterminate;
|
||||
input.addEventListener('change', onchange);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
return renderSnippet(selectAllSnippet, {
|
||||
checked: isAllSelected,
|
||||
indeterminate: isSomeSelected && !isAllSelected,
|
||||
onchange: (e: Event) => {
|
||||
table.toggleAllPageRowsSelected(!!(e.target as HTMLInputElement).checked);
|
||||
}
|
||||
});
|
||||
},
|
||||
cell: ({ row }) => {
|
||||
const isSelected = row.getIsSelected();
|
||||
|
||||
const checkboxSnippet = createRawSnippet<[{ selected: boolean }]>((getProps) => {
|
||||
const { selected } = getProps();
|
||||
const checkboxSnippet = createRawSnippet<[
|
||||
{ selected: boolean; onchange: (e: Event) => void }
|
||||
]>((getProps) => {
|
||||
const { selected, onchange } = getProps();
|
||||
return {
|
||||
render: () => `<div class="flex items-center justify-center">
|
||||
<input type="checkbox" class="h-4 w-4" ${selected ? 'checked' : ''} />
|
||||
</div>`
|
||||
<input type="checkbox" class="h-4 w-4 cursor-pointer" ${selected ? 'checked' : ''} />
|
||||
</div>`,
|
||||
setup: (node) => {
|
||||
const input = node.querySelector('input') as HTMLInputElement;
|
||||
if (input) {
|
||||
input.addEventListener('change', onchange);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
return renderSnippet(checkboxSnippet, { selected: isSelected });
|
||||
return renderSnippet(checkboxSnippet, {
|
||||
selected: isSelected,
|
||||
onchange: (e: Event) => {
|
||||
e.stopPropagation(); // Evitar que el clic en el checkbox dispare el rowClick
|
||||
row.toggleSelected(!!(e.target as HTMLInputElement).checked);
|
||||
}
|
||||
});
|
||||
},
|
||||
enableSorting: false,
|
||||
enableHiding: false,
|
||||
@@ -298,16 +339,6 @@ export function createColumns(
|
||||
return renderSnippet(relDocSnippet, { relDoc });
|
||||
}
|
||||
},
|
||||
// 2. MODIFICAMOS AQUÍ: Pasamos onDownload al componente
|
||||
{
|
||||
id: "actions",
|
||||
cell: ({ row }) => {
|
||||
return renderComponent(DataTableActions, {
|
||||
invoice: row.original,
|
||||
onSuccess
|
||||
});
|
||||
}
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
<script lang="ts" generics="TData, TValue">
|
||||
import { onMount } from 'svelte';
|
||||
import {
|
||||
type ColumnDef,
|
||||
getCoreRowModel
|
||||
} from "@tanstack/table-core";
|
||||
import { createSvelteTable, FlexRender } from "$lib/components/ui/data-table/index.js";
|
||||
import * as Table from "$lib/components/ui/table/index.js";
|
||||
import { type ColumnDef, getCoreRowModel } from '@tanstack/table-core';
|
||||
import { createSvelteTable, FlexRender } from '$lib/components/ui/data-table/index.js';
|
||||
import * as Table from '$lib/components/ui/table/index.js';
|
||||
|
||||
type DataTableProps<TData, TValue> = {
|
||||
columns: ColumnDef<TData, TValue>[];
|
||||
@@ -14,7 +11,7 @@
|
||||
hasMore: boolean;
|
||||
loadMore: () => void;
|
||||
// Props para selección
|
||||
selectedId?: number | null;
|
||||
selectedIds?: number[];
|
||||
onRowClick?: (row: TData) => void;
|
||||
};
|
||||
|
||||
@@ -24,7 +21,7 @@
|
||||
loading,
|
||||
hasMore,
|
||||
loadMore,
|
||||
selectedId = null,
|
||||
selectedIds = [],
|
||||
onRowClick
|
||||
}: DataTableProps<TData, TValue> = $props();
|
||||
|
||||
@@ -37,12 +34,17 @@
|
||||
getRowId: (row: any) => row.id?.toString(), // Usar ID para identificar filas
|
||||
state: {
|
||||
get rowSelection() {
|
||||
// Mapear el ID seleccionado al formato que espera TanStack Table
|
||||
return selectedId ? { [selectedId]: true } : {};
|
||||
// Mapear los IDs seleccionados al formato que espera TanStack Table
|
||||
const selection: Record<string, boolean> = {};
|
||||
selectedIds.forEach((id) => {
|
||||
selection[id.toString()] = true;
|
||||
});
|
||||
return selection;
|
||||
}
|
||||
},
|
||||
enableRowSelection: true,
|
||||
enableMultiRowSelection: false, // Solo permitir una selección a la vez
|
||||
enableMultiRowSelection: true
|
||||
|
||||
// No necesitamos onRowSelectionChange porque controlamos el estado desde fuera
|
||||
});
|
||||
|
||||
@@ -75,7 +77,7 @@
|
||||
</script>
|
||||
|
||||
<div class="w-full">
|
||||
<div class="rounded-md border max-h-[600px] overflow-y-auto" bind:this={scrollContainer}>
|
||||
<div class="max-h-[600px] overflow-y-auto rounded-md border" bind:this={scrollContainer}>
|
||||
<Table.Root>
|
||||
<Table.Header class="bg-background">
|
||||
{#each table.getHeaderGroups() as headerGroup (headerGroup.id)}
|
||||
@@ -95,17 +97,16 @@
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{#each table.getRowModel().rows as row (row.id)}
|
||||
<Table.Row
|
||||
data-state={row.getIsSelected() && "selected"}
|
||||
class="cursor-pointer transition-colors {row.getIsSelected() ? 'bg-gray-300 dark:bg-gray-600' : 'hover:bg-gray-100 dark:hover:bg-gray-700'}"
|
||||
<Table.Row
|
||||
data-state={row.getIsSelected() && 'selected'}
|
||||
class="cursor-pointer transition-colors {row.getIsSelected()
|
||||
? 'bg-gray-300 dark:bg-gray-600'
|
||||
: 'hover:bg-gray-100 dark:hover:bg-gray-700'}"
|
||||
onclick={() => onRowClick && onRowClick(row.original)}
|
||||
>
|
||||
{#each row.getVisibleCells() as cell (cell.id)}
|
||||
<Table.Cell>
|
||||
<FlexRender
|
||||
content={cell.column.columnDef.cell}
|
||||
context={cell.getContext()}
|
||||
/>
|
||||
<FlexRender content={cell.column.columnDef.cell} context={cell.getContext()} />
|
||||
</Table.Cell>
|
||||
{/each}
|
||||
</Table.Row>
|
||||
@@ -116,7 +117,7 @@
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
{/each}
|
||||
|
||||
|
||||
<!-- Loading Trigger - Se activa cuando es visible -->
|
||||
{#if hasMore}
|
||||
<Table.Row>
|
||||
@@ -124,13 +125,13 @@
|
||||
<div bind:this={loadingTrigger}>
|
||||
{#if loading}
|
||||
<div class="flex items-center justify-center gap-2">
|
||||
<div class="h-4 w-4 animate-spin rounded-full border-2 border-primary border-t-transparent"></div>
|
||||
<span class="text-muted-foreground text-sm">Cargando más...</span>
|
||||
<div
|
||||
class="h-4 w-4 animate-spin rounded-full border-2 border-primary border-t-transparent"
|
||||
></div>
|
||||
<span class="text-sm text-muted-foreground">Cargando más...</span>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="text-muted-foreground text-sm">
|
||||
Desplázate para cargar más
|
||||
</div>
|
||||
<div class="text-sm text-muted-foreground">Desplázate para cargar más</div>
|
||||
{/if}
|
||||
</div>
|
||||
</Table.Cell>
|
||||
|
||||
@@ -1,44 +1,63 @@
|
||||
<script lang="ts">
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import * as AlertDialog from "$lib/components/ui/alert-dialog";
|
||||
import { invoicesApi, type Invoice } from "$lib/api/dashboard/a76/invoices";
|
||||
import { companyStore } from "$lib/stores/company.svelte";
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import * as AlertDialog from '$lib/components/ui/alert-dialog';
|
||||
import { invoicesApi, type Invoice } from '$lib/api/dashboard/a76/invoices';
|
||||
import { companyStore } from '$lib/stores/company.svelte';
|
||||
import { LoaderCircle } from 'lucide-svelte';
|
||||
|
||||
interface Props {
|
||||
invoice: Invoice;
|
||||
invoice?: Invoice | null;
|
||||
invoicesToDelete?: Invoice[];
|
||||
onClose: () => void;
|
||||
onSuccess?: () => void;
|
||||
}
|
||||
|
||||
let { invoice, onClose, onSuccess }: Props = $props();
|
||||
let { invoice = null, invoicesToDelete = [], onClose, onSuccess }: Props = $props();
|
||||
let open = $state(true);
|
||||
|
||||
let isMultiDelete = $derived(invoicesToDelete.length > 1);
|
||||
let isSingleDelete = $derived(invoicesToDelete.length <= 1 && invoice !== null);
|
||||
|
||||
let loading = $state(false);
|
||||
let error = $state<string | null>(null);
|
||||
|
||||
async function handleDelete() {
|
||||
if (!invoice || !companyStore.activeCompany) return;
|
||||
const itemsToDelete = invoicesToDelete.length > 0 ? invoicesToDelete : invoice ? [invoice] : [];
|
||||
if (itemsToDelete.length === 0 || !companyStore.activeCompany) return;
|
||||
|
||||
loading = true;
|
||||
error = null;
|
||||
|
||||
try {
|
||||
const response = await invoicesApi.delete(invoice.id, companyStore.activeCompany.id);
|
||||
let successCount = 0;
|
||||
let failCount = 0;
|
||||
|
||||
if (response.error) {
|
||||
error = response.error;
|
||||
return;
|
||||
try {
|
||||
for (const item of itemsToDelete) {
|
||||
const response = await invoicesApi.delete(item.id, companyStore.activeCompany.id);
|
||||
|
||||
if (response.error) {
|
||||
failCount++;
|
||||
console.error(`Error deleting invoice ${item.id}:`, response.error);
|
||||
} else {
|
||||
successCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// Éxito
|
||||
onClose();
|
||||
if (onSuccess) {
|
||||
onSuccess();
|
||||
if (failCount > 0) {
|
||||
error = `Se eliminaron ${successCount} facturas, pero fallaron ${failCount}. Revisa la consola para más detalles.`;
|
||||
if (successCount === 0) return; // Si todas fallaron, no cerramos
|
||||
}
|
||||
|
||||
// Si al menos una tuvo éxito (o todas), refrescamos
|
||||
if (successCount > 0) {
|
||||
onClose();
|
||||
if (onSuccess) {
|
||||
onSuccess();
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
error = e instanceof Error ? e.message : "Error al eliminar";
|
||||
console.error("Error deleting:", e);
|
||||
error = e instanceof Error ? e.message : 'Error al eliminar';
|
||||
console.error('Error deleting:', e);
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
@@ -59,9 +78,17 @@
|
||||
<AlertDialog.Header>
|
||||
<AlertDialog.Title>¿Estás seguro?</AlertDialog.Title>
|
||||
<AlertDialog.Description class="space-y-2">
|
||||
<p>Esta acción no se puede deshacer. Se eliminará permanentemente esta factura:</p>
|
||||
{#if invoice}
|
||||
<div class="mt-2 rounded-lg bg-muted p-3 space-y-2">
|
||||
{#if isMultiDelete}
|
||||
<p>
|
||||
Esta acción no se puede deshacer. Se eliminarán permanentemente <strong
|
||||
>{invoicesToDelete.length}</strong
|
||||
> facturas seleccionadas.
|
||||
</p>
|
||||
{:else}
|
||||
<p>Esta acción no se puede deshacer. Se eliminará permanentemente esta factura:</p>
|
||||
{/if}
|
||||
{#if isSingleDelete && invoice}
|
||||
<div class="mt-2 space-y-2 rounded-lg bg-muted p-3">
|
||||
<div class="flex items-center justify-between text-sm">
|
||||
<span class="font-medium">ID:</span>
|
||||
<span class="font-semibold">{invoice.id}</span>
|
||||
@@ -73,8 +100,11 @@
|
||||
<div class="flex items-center justify-between text-sm">
|
||||
<span class="font-medium">Tipo:</span>
|
||||
<span class="text-xs">
|
||||
{invoice.operation_type === 'imp' ? 'Importación' :
|
||||
invoice.operation_type === 'exp' ? 'Exportación' : 'N/A'}
|
||||
{invoice.operation_type === 'imp'
|
||||
? 'Importación'
|
||||
: invoice.operation_type === 'exp'
|
||||
? 'Exportación'
|
||||
: 'N/A'}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between text-sm">
|
||||
@@ -88,7 +118,9 @@
|
||||
</div>
|
||||
{/if}
|
||||
{#if error}
|
||||
<div class="mt-2 rounded-lg border border-destructive bg-destructive/10 p-3 text-sm text-destructive">
|
||||
<div
|
||||
class="mt-2 rounded-lg border border-destructive bg-destructive/10 p-3 text-sm text-destructive"
|
||||
>
|
||||
{error}
|
||||
</div>
|
||||
{/if}
|
||||
@@ -99,7 +131,7 @@
|
||||
<AlertDialog.Action
|
||||
onclick={handleDelete}
|
||||
disabled={loading}
|
||||
class="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
||||
class="text-destructive-foreground bg-destructive hover:bg-destructive/90"
|
||||
>
|
||||
{#if loading}
|
||||
<LoaderCircle class="mr-2 h-4 w-4 animate-spin" />
|
||||
|
||||
@@ -27,11 +27,26 @@
|
||||
Package,
|
||||
ClipboardList,
|
||||
Settings,
|
||||
Send
|
||||
Send,
|
||||
Eye,
|
||||
Pencil,
|
||||
Trash2,
|
||||
Download,
|
||||
MonitorUp,
|
||||
Files,
|
||||
ScrollText,
|
||||
BadgeCent,
|
||||
ArrowRightLeft,
|
||||
Database,
|
||||
ChevronUp
|
||||
} from 'lucide-svelte';
|
||||
import DetailsDialog from '$lib/components/dashboard/invoices/details-dialog.svelte';
|
||||
import DeleteDialog from '$lib/components/dashboard/invoices/delete-dialog.svelte';
|
||||
import * as DropdownMenu from '$lib/components/ui/dropdown-menu';
|
||||
|
||||
// IMPORTANTE: Asegúrate de tener instalada svelte-sonner para las notificaciones
|
||||
import { toast } from 'svelte-sonner';
|
||||
import { fly } from 'svelte/transition';
|
||||
import PdfProgressDialog from '$lib/components/dashboard/invoices/pdf-progress-dialog.svelte';
|
||||
import { useShortcuts } from '$lib/hooks/use-shortcuts';
|
||||
import { obtenerAtajosListaFacturas } from '$lib/config/shortcuts/dashboard/invoices/list';
|
||||
@@ -180,23 +195,29 @@
|
||||
let hasMore = $derived(allItems.length < totalItems);
|
||||
let error = $state<string | null>(data.error || null);
|
||||
|
||||
// Estado para selección de fila
|
||||
let selectedInvoiceId = $state<number | null>(null);
|
||||
// Estado para selección de filas (múltiple)
|
||||
let selectedInvoiceIds = $state<number[]>([]);
|
||||
// Estado para los diálogos de acciones
|
||||
let showDetailsDialog = $state(false);
|
||||
let showDeleteDialog = $state(false);
|
||||
|
||||
function handleRowClick(invoice: Invoice) {
|
||||
// Si ya está seleccionado, lo deseleccionamos (opcional, si queremos permitir toggle)
|
||||
// O simplemente lo seleccionamos. Aquí implemento toggle.
|
||||
if (selectedInvoiceId === invoice.id) {
|
||||
selectedInvoiceId = null;
|
||||
const id = invoice.id;
|
||||
if (selectedInvoiceIds.includes(id)) {
|
||||
// Deseleccionar si ya estaba
|
||||
selectedInvoiceIds = selectedInvoiceIds.filter((selectedId) => selectedId !== id);
|
||||
} else {
|
||||
selectedInvoiceId = invoice.id;
|
||||
// Seleccionar agregando a la lista
|
||||
selectedInvoiceIds = [...selectedInvoiceIds, id];
|
||||
}
|
||||
}
|
||||
|
||||
const selectedInvoice = $derived(
|
||||
selectedInvoiceId ? allItems.find((i) => i.id === selectedInvoiceId) : null
|
||||
selectedInvoiceIds.length === 1 ? allItems.find((i) => i.id === selectedInvoiceIds[0]) : null
|
||||
);
|
||||
|
||||
const hasSelection = $derived(selectedInvoiceIds.length > 0);
|
||||
|
||||
async function loadMore() {
|
||||
if (loading || !hasMore) return;
|
||||
|
||||
@@ -781,10 +802,12 @@
|
||||
Mostrando {allItems.length} de {totalItems} registros
|
||||
</Card.Description>
|
||||
</div>
|
||||
<Button variant="outline" onclick={reloadData}>
|
||||
<RefreshCw class="mr-2" size={16} />
|
||||
Actualizar
|
||||
</Button>
|
||||
<div class="flex items-center gap-2">
|
||||
<Button variant="outline" onclick={reloadData}>
|
||||
<RefreshCw class="mr-2" size={16} />
|
||||
Actualizar
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Card.Header>
|
||||
<Card.Content>
|
||||
@@ -794,7 +817,7 @@
|
||||
{loading}
|
||||
{hasMore}
|
||||
{loadMore}
|
||||
selectedId={selectedInvoiceId}
|
||||
selectedIds={selectedInvoiceIds}
|
||||
onRowClick={handleRowClick}
|
||||
/>
|
||||
</Card.Content>
|
||||
@@ -814,20 +837,147 @@
|
||||
>
|
||||
<div class="mx-auto max-w-[1400px] px-4 py-4">
|
||||
<!-- Botones de acción -->
|
||||
<div class="flex justify-end gap-2">
|
||||
<div class="flex w-full items-center justify-end gap-2">
|
||||
{#if hasSelection}
|
||||
<div transition:fly={{ x: 40, duration: 250 }} class="flex items-center gap-2">
|
||||
<!-- Dropdown: Reportes -->
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger>
|
||||
{#snippet child({ props })}
|
||||
<Button
|
||||
{...props}
|
||||
variant="outline"
|
||||
size="sm"
|
||||
disabled={selectedInvoiceIds.length !== 1}
|
||||
>
|
||||
Reportes
|
||||
<ChevronUp class="ml-2 h-4 w-4" />
|
||||
</Button>
|
||||
{/snippet}
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Content align="end" class="max-h-[400px] w-56 overflow-y-auto">
|
||||
<DropdownMenu.Group>
|
||||
<DropdownMenu.Label>Descargas</DropdownMenu.Label>
|
||||
<DropdownMenu.Item onclick={() => (isDownloadModalOpen = true)}>
|
||||
<FileText class="mr-2 h-4 w-4" />
|
||||
Factura PDF
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item
|
||||
onclick={() => toast.info('Generar Factura CSV - Próximamente')}
|
||||
>
|
||||
<Download class="mr-2 h-4 w-4" />
|
||||
Factura CSV
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item
|
||||
onclick={() => selectedInvoice && handleDownloadConsolidated(selectedInvoice)}
|
||||
>
|
||||
<Boxes class="mr-2 h-4 w-4" />
|
||||
Consolidado
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item
|
||||
onclick={() =>
|
||||
selectedInvoice && handleDownloadAvisoConsolidado(selectedInvoice)}
|
||||
>
|
||||
<Boxes class="mr-2 h-4 w-4" />
|
||||
Aviso Consolidado
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item
|
||||
onclick={() => selectedInvoice && handleDownloadPackingList(selectedInvoice)}
|
||||
>
|
||||
<Package class="mr-2 h-4 w-4" />
|
||||
Packing List
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item onclick={() => toast.info('4 Copias Rem - Próximamente')}>
|
||||
<Files class="mr-2 h-4 w-4" />
|
||||
4 Copias Rem
|
||||
</DropdownMenu.Item>
|
||||
{#if selectedInvoice?.operation_type === 'exp'}
|
||||
<DropdownMenu.Item onclick={() => handleDownloadDescargo(selectedInvoice)}>
|
||||
<ClipboardList class="mr-2 h-4 w-4" />
|
||||
Descargo PEPS
|
||||
</DropdownMenu.Item>
|
||||
{/if}
|
||||
</DropdownMenu.Group>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
|
||||
<!-- Dropdown: Más Acciones -->
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger>
|
||||
{#snippet child({ props })}
|
||||
<Button
|
||||
{...props}
|
||||
variant="outline"
|
||||
size="sm"
|
||||
disabled={selectedInvoiceIds.length !== 1}
|
||||
>
|
||||
Más Acciones
|
||||
<ChevronUp class="ml-2 h-4 w-4" />
|
||||
</Button>
|
||||
{/snippet}
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Content align="end" class="max-h-[400px] w-56 overflow-y-auto">
|
||||
<DropdownMenu.Group>
|
||||
<DropdownMenu.Label>Otras Acciones</DropdownMenu.Label>
|
||||
<DropdownMenu.Item
|
||||
onclick={() => (isTransferenciaModalOpen = true)}
|
||||
disabled={!companyStore.activeCompany}
|
||||
>
|
||||
<Send class="mr-2 h-4 w-4" />
|
||||
Transferencia Electrónica
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item onclick={() => toast.info('Interface VU - Próximamente')}>
|
||||
<MonitorUp class="mr-2 h-4 w-4" />
|
||||
Interface VU
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item onclick={() => toast.info('Cons SED - Próximamente')}>
|
||||
<ScrollText class="mr-2 h-4 w-4" />
|
||||
Cons SED
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item onclick={() => toast.info('Encomienda - Próximamente')}>
|
||||
<BadgeCent class="mr-2 h-4 w-4" />
|
||||
Encomienda
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item
|
||||
onclick={() => toast.info('Factura Mex Consolidada - Próximamente')}
|
||||
>
|
||||
<FileText class="mr-2 h-4 w-4" />
|
||||
Fact Mex Cons
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item
|
||||
onclick={() => toast.info('Factura Mex Orden Captura - Próximamente')}
|
||||
>
|
||||
<FileText class="mr-2 h-4 w-4" />
|
||||
Fact Mex Ord Cat
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item onclick={() => toast.info('Export SIA - Próximamente')}>
|
||||
<Database class="mr-2 h-4 w-4" />
|
||||
Export SIA
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item onclick={() => toast.info('Interface - Próximamente')}>
|
||||
<ArrowRightLeft class="mr-2 h-4 w-4" />
|
||||
Interface
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.Group>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
<div class="h-6 w-px bg-border"></div>
|
||||
</div>
|
||||
{/if}
|
||||
<!-- Por ahora, Actualizar Estado funciona solo si hay ESTRICTAMENTE UNA seleccionada -->
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
disabled={!selectedInvoice || loading}
|
||||
disabled={loading || selectedInvoiceIds.length !== 1}
|
||||
onclick={() => handleUpdateStatus(true)}
|
||||
>
|
||||
<RefreshCw class="mr-2 h-4 w-4" />
|
||||
Actualizar
|
||||
Actualizar Est
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
disabled={!selectedInvoice || loading}
|
||||
disabled={loading || selectedInvoiceIds.length !== 1}
|
||||
onclick={() => handleUpdateStatus(false)}
|
||||
>
|
||||
<RotateCcw class="mr-2 h-4 w-4" />
|
||||
@@ -836,64 +986,30 @@
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onclick={() => (isDownloadModalOpen = true)}
|
||||
disabled={!selectedInvoice}
|
||||
disabled={selectedInvoiceIds.length !== 1}
|
||||
onclick={() => (showDetailsDialog = true)}
|
||||
>
|
||||
<FileText class="mr-2 h-4 w-4" />
|
||||
Factura
|
||||
<Eye class="mr-2 h-4 w-4" />
|
||||
Ver Detalles
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onclick={() => selectedInvoice && handleDownloadConsolidated(selectedInvoice)}
|
||||
disabled={!selectedInvoice}
|
||||
disabled={selectedInvoiceIds.length !== 1}
|
||||
onclick={handleEditSelected}
|
||||
>
|
||||
<Boxes class="mr-2 h-4 w-4" />
|
||||
Consolidado
|
||||
<Pencil class="mr-2 h-4 w-4" />
|
||||
Editar
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="outline"
|
||||
variant="destructive"
|
||||
size="sm"
|
||||
onclick={() => selectedInvoice && handleDownloadAvisoConsolidado(selectedInvoice)}
|
||||
disabled={!selectedInvoice}
|
||||
disabled={selectedInvoiceIds.length === 0}
|
||||
onclick={() => (showDeleteDialog = true)}
|
||||
>
|
||||
<Boxes class="mr-2 h-4 w-4" />
|
||||
Aviso Consolidado
|
||||
<Trash2 class="mr-2 h-4 w-4" />
|
||||
Eliminar
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onclick={() => selectedInvoice && handleDownloadPackingList(selectedInvoice)}
|
||||
disabled={!selectedInvoice}
|
||||
>
|
||||
<Package class="mr-2 h-4 w-4" />
|
||||
Packing List
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onclick={() => (isTransferenciaModalOpen = true)}
|
||||
disabled={!companyStore.activeCompany}
|
||||
>
|
||||
<Send class="mr-2 h-4 w-4" />
|
||||
Transferencia Electrónica
|
||||
</Button>
|
||||
|
||||
{#if selectedInvoice?.operation_type === 'exp'}
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onclick={() => selectedInvoice && handleDownloadDescargo(selectedInvoice)}
|
||||
disabled={!selectedInvoice}
|
||||
>
|
||||
<ClipboardList class="mr-2 h-4 w-4" />
|
||||
Descargo PEPS
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -904,4 +1020,26 @@
|
||||
<InvoiceDownloadModal bind:open={isDownloadModalOpen} onConfirm={handleModalConfirm} />
|
||||
<TransferenciaElectronicaModal bind:open={isTransferenciaModalOpen} invoice={selectedInvoice} />
|
||||
{/if}
|
||||
|
||||
{#if showDetailsDialog && selectedInvoice}
|
||||
<DetailsDialog invoice={selectedInvoice} onClose={() => (showDetailsDialog = false)} />
|
||||
{/if}
|
||||
|
||||
{#if showDeleteDialog}
|
||||
<DeleteDialog
|
||||
invoice={selectedInvoice}
|
||||
invoicesToDelete={selectedInvoiceIds
|
||||
.map((id) => allItems.find((i) => i.id === id))
|
||||
.filter((i): i is Invoice => i !== undefined)}
|
||||
onClose={() => {
|
||||
showDeleteDialog = false;
|
||||
selectedInvoiceIds = [];
|
||||
}}
|
||||
onSuccess={() => {
|
||||
showDeleteDialog = false;
|
||||
selectedInvoiceIds = [];
|
||||
handleSuccess();
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user