Se eliminaron archivos inecesarios y se puso nombre a la tabla de acciones en catalogos generales
This commit is contained in:
@@ -118,6 +118,7 @@ export function createColumns(onSuccess?: () => void): ColumnDef<CustomsBroker>[
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
header: "Acciones",
|
||||
cell: ({ row }) => {
|
||||
return renderComponent(DataTableActions, {
|
||||
broker: row.original,
|
||||
|
||||
@@ -32,6 +32,7 @@ export function createColumns(onSuccess?: () => void): ColumnDef<Doda>[] {
|
||||
},
|
||||
{
|
||||
id: 'actions',
|
||||
Headers: 'Acciones',
|
||||
cell: ({ row }) => {
|
||||
return renderComponent(DataTableActions, {
|
||||
item: row.original,
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { ColumnDef } from '@tanstack/table-core';
|
||||
import type { ElectronicNotice } from '$lib/api/dashboard/a76/general_catalogs/electronic-notices';
|
||||
import { renderComponent } from '$lib/components/ui/data-table';
|
||||
import DataTableActions from './data-table-actions.svelte';
|
||||
import { Head } from '$lib/components/ui/table';
|
||||
|
||||
export function createColumns(onSuccess?: () => void): ColumnDef<ElectronicNotice>[] {
|
||||
return [
|
||||
@@ -32,6 +33,7 @@ export function createColumns(onSuccess?: () => void): ColumnDef<ElectronicNotic
|
||||
},
|
||||
{
|
||||
id: 'actions',
|
||||
Headers: 'Acciones',
|
||||
cell: ({ row }) => {
|
||||
return renderComponent(DataTableActions, {
|
||||
item: row.original,
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { ColumnDef } from '@tanstack/table-core';
|
||||
import type { Equivalency } from '$lib/api/dashboard/a76/general_catalogs/equivalencies';
|
||||
import { renderComponent } from '$lib/components/ui/data-table';
|
||||
import DataTableActions from './data-table-actions.svelte';
|
||||
import { Header } from '$lib/components/ui/alert-dialog';
|
||||
|
||||
export function createColumns(onSuccess?: () => void): ColumnDef<Equivalency>[] {
|
||||
return [
|
||||
@@ -22,6 +23,7 @@ export function createColumns(onSuccess?: () => void): ColumnDef<Equivalency>[]
|
||||
},
|
||||
{
|
||||
id: 'actions',
|
||||
Header: 'Acciones',
|
||||
cell: ({ row }) => {
|
||||
return renderComponent(DataTableActions, {
|
||||
item: row.original,
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { ColumnDef } from '@tanstack/table-core';
|
||||
import type { Identifier } from '$lib/api/dashboard/a76/general_catalogs/identifiers';
|
||||
import { renderComponent } from '$lib/components/ui/data-table';
|
||||
import DataTableActions from './data-table-actions.svelte';
|
||||
import { Header } from '$lib/components/ui/alert-dialog';
|
||||
|
||||
export function createColumns(onSuccess?: () => void): ColumnDef<Identifier>[] {
|
||||
return [
|
||||
@@ -27,6 +28,7 @@ export function createColumns(onSuccess?: () => void): ColumnDef<Identifier>[] {
|
||||
},
|
||||
{
|
||||
id: 'actions',
|
||||
Header: 'Acciones',
|
||||
cell: ({ row }) => {
|
||||
return renderComponent(DataTableActions, {
|
||||
item: row.original,
|
||||
|
||||
@@ -22,6 +22,7 @@ export function createColumns(onSuccess?: () => void): ColumnDef<INPC>[] {
|
||||
},
|
||||
{
|
||||
id: 'actions',
|
||||
header: 'Acciones',
|
||||
cell: ({ row }) => {
|
||||
return renderComponent(DataTableActions, {
|
||||
item: row.original,
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { ColumnDef } from '@tanstack/table-core';
|
||||
import type { Prevalidator } from '$lib/api/dashboard/a76/general_catalogs/prevalidators';
|
||||
import { renderComponent } from '$lib/components/ui/data-table';
|
||||
import DataTableActions from './data-table-actions.svelte';
|
||||
import { Header } from '$lib/components/ui/alert-dialog';
|
||||
|
||||
export function createColumns(onSuccess?: () => void): ColumnDef<Prevalidator>[] {
|
||||
return [
|
||||
@@ -27,6 +28,7 @@ export function createColumns(onSuccess?: () => void): ColumnDef<Prevalidator>[]
|
||||
},
|
||||
{
|
||||
id: 'actions',
|
||||
Header: 'Acciones',
|
||||
cell: ({ row }) => {
|
||||
return renderComponent(DataTableActions, {
|
||||
item: row.original,
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { ColumnDef } from '@tanstack/table-core';
|
||||
import type { UnitConversion } from '$lib/api/dashboard/a76/general_catalogs/unit-conversions';
|
||||
import { renderComponent } from '$lib/components/ui/data-table';
|
||||
import DataTableActions from './data-table-actions.svelte';
|
||||
import { Header } from '$lib/components/ui/alert-dialog';
|
||||
|
||||
export function createColumns(onSuccess?: () => void): ColumnDef<UnitConversion>[] {
|
||||
return [
|
||||
@@ -19,6 +20,7 @@ export function createColumns(onSuccess?: () => void): ColumnDef<UnitConversion>
|
||||
},
|
||||
{
|
||||
id: 'actions',
|
||||
header: 'Acciones',
|
||||
cell: ({ row }) =>
|
||||
renderComponent(DataTableActions, {
|
||||
conversion: row.original,
|
||||
|
||||
@@ -15,6 +15,7 @@ export function createColumns(onSuccess?: () => void): ColumnDef<UnitOfMeasureAm
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
header: "Acciones",
|
||||
cell: ({ row }) =>
|
||||
renderComponent(DataTableActions, {
|
||||
unit: row.original,
|
||||
|
||||
@@ -19,6 +19,7 @@ export function createColumns(onSuccess?: () => void): ColumnDef<UnitOfMeasureCu
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
header: "Acciones",
|
||||
cell: ({ row }) =>
|
||||
renderComponent(DataTableActions, {
|
||||
unit: row.original,
|
||||
|
||||
@@ -15,6 +15,7 @@ export function createColumns(onSuccess?: () => void): ColumnDef<UnitOfMeasureOM
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
header: "Acciones",
|
||||
cell: ({ row }) =>
|
||||
renderComponent(DataTableActions, {
|
||||
unit: row.original,
|
||||
|
||||
@@ -26,6 +26,7 @@ export function createColumns(onSuccess?: () => void): ColumnDef<Identifier>[] {
|
||||
},
|
||||
{
|
||||
id: 'actions',
|
||||
header: 'Acciones',
|
||||
cell: ({ row }) => {
|
||||
return renderComponent(DataTableActions, {
|
||||
item: row.original,
|
||||
|
||||
@@ -1,27 +1,26 @@
|
||||
/**
|
||||
* Column definitions for Seal table
|
||||
*/
|
||||
import type { ColumnDef } from '@tanstack/table-core';
|
||||
import type { Seal } from '$lib/api/dashboard/a76/general_catalogs/seal';
|
||||
import { renderComponent } from '$lib/components/ui/data-table';
|
||||
import DataTableActions from './data-table-actions.svelte';
|
||||
|
||||
export function createColumns(onSuccess?: () => void): ColumnDef<Seal>[] {
|
||||
return [
|
||||
{
|
||||
accessorKey: 'seal',
|
||||
header: 'Sello',
|
||||
cell: ({ row }) => row.original.seal
|
||||
},
|
||||
{
|
||||
id: 'actions',
|
||||
header: 'Acciones',
|
||||
cell: ({ row }) => {
|
||||
return renderComponent(DataTableActions, {
|
||||
item: row.original,
|
||||
onSuccess
|
||||
});
|
||||
}
|
||||
}
|
||||
];
|
||||
}
|
||||
return [
|
||||
|
||||
{
|
||||
accessorKey: 'seal',
|
||||
header: 'Sello',
|
||||
cell: ({ row }) => row.original.seal,
|
||||
},
|
||||
{
|
||||
id: 'actions',
|
||||
header: 'Acciones',
|
||||
meta: {
|
||||
class: 'w-[100px] text-right'
|
||||
},
|
||||
cell: ({ row }) => renderComponent(DataTableActions, {
|
||||
item: row.original,
|
||||
onSuccess
|
||||
})
|
||||
}
|
||||
];
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import type { UnitOfMeasureACE } from '$lib/api/dashboard/a76/general_catalogs/units-of-measure';
|
||||
import type { ColumnDef } from '@tanstack/table-core';
|
||||
import { renderComponent } from '$lib/components/ui/data-table';
|
||||
import DataTableActions from './data-table-actions.svelte';
|
||||
|
||||
export function createColumns(onSuccess?: () => void): ColumnDef<UnitOfMeasureACE>[] {
|
||||
return [
|
||||
{
|
||||
accessorKey: 'code',
|
||||
header: 'Código',
|
||||
},
|
||||
{
|
||||
accessorKey: 'description',
|
||||
header: 'Descripción',
|
||||
cell: ({ row }) => row.original.description || '-'
|
||||
},
|
||||
{
|
||||
id: 'actions',
|
||||
cell: ({ row }) => {
|
||||
return renderComponent(DataTableActions, {
|
||||
item: row.original,
|
||||
onSuccess
|
||||
});
|
||||
}
|
||||
}
|
||||
];
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import * as Dialog from "$lib/components/ui/dialog";
|
||||
import { Input } from "$lib/components/ui/input";
|
||||
import { Label } from "$lib/components/ui/label";
|
||||
import { createUnitOfMeasureACE, updateUnitOfMeasureACE, type UnitOfMeasureACE } from "$lib/api/dashboard/a76/general_catalogs/units-of-measure";
|
||||
|
||||
let {
|
||||
open = $bindable(false),
|
||||
mode = 'create',
|
||||
item = null,
|
||||
onSuccess
|
||||
}: {
|
||||
open: boolean;
|
||||
mode?: 'create' | 'edit';
|
||||
item?: UnitOfMeasureACE | null;
|
||||
onSuccess?: () => void;
|
||||
} = $props();
|
||||
|
||||
const isEdit = $derived(mode === 'edit');
|
||||
const title = $derived(isEdit ? "Editar Unidad ACE" : "Nueva Unidad ACE");
|
||||
|
||||
let formData = $state({
|
||||
code: '',
|
||||
description: ''
|
||||
});
|
||||
|
||||
let loading = $state(false);
|
||||
let error = $state<string | null>(null);
|
||||
|
||||
$effect(() => {
|
||||
if (open) {
|
||||
if (isEdit && item) {
|
||||
formData = {
|
||||
code: item.code,
|
||||
description: item.description || ''
|
||||
};
|
||||
} else {
|
||||
formData = {
|
||||
code: '',
|
||||
description: ''
|
||||
};
|
||||
}
|
||||
error = null;
|
||||
}
|
||||
});
|
||||
|
||||
async function handleSubmit() {
|
||||
loading = true;
|
||||
error = null;
|
||||
|
||||
try {
|
||||
let response;
|
||||
if (isEdit && item) {
|
||||
response = await updateUnitOfMeasureACE(item.id, {
|
||||
code: formData.code,
|
||||
description: formData.description || null
|
||||
});
|
||||
} else {
|
||||
response = await createUnitOfMeasureACE({
|
||||
code: formData.code,
|
||||
description: formData.description || null
|
||||
});
|
||||
}
|
||||
|
||||
if (response.error) {
|
||||
error = response.error;
|
||||
return;
|
||||
}
|
||||
|
||||
open = false;
|
||||
if (onSuccess) onSuccess();
|
||||
} catch (e) {
|
||||
error = 'Error de conexión';
|
||||
console.error(e);
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<Dialog.Root bind:open>
|
||||
<Dialog.Content class="sm:max-w-[425px]">
|
||||
<Dialog.Header>
|
||||
<Dialog.Title>{title}</Dialog.Title>
|
||||
</Dialog.Header>
|
||||
|
||||
<div class="grid gap-4 py-4">
|
||||
{#if error}
|
||||
<div class="text-red-500 text-sm mb-2">{error}</div>
|
||||
{/if}
|
||||
|
||||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
<Label for="code" class="text-right">Código</Label>
|
||||
<Input id="code" bind:value={formData.code} class="col-span-3" disabled={loading} />
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
<Label for="description" class="text-right">Descripción</Label>
|
||||
<Input id="description" bind:value={formData.description} class="col-span-3" disabled={loading} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Dialog.Footer>
|
||||
<Button type="submit" onclick={handleSubmit} disabled={loading}>
|
||||
{loading ? 'Guardando...' : 'Guardar'}
|
||||
</Button>
|
||||
</Dialog.Footer>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
@@ -1,79 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import * as DropdownMenu from "$lib/components/ui/dropdown-menu";
|
||||
import { deleteUnitOfMeasureACE, type UnitOfMeasureACE } from "$lib/api/dashboard/a76/general_catalogs/units-of-measure";
|
||||
import { EllipsisVertical, Pencil, LoaderCircle, Trash2 } from 'lucide-svelte';
|
||||
import CreateEditDialog from "./create-edit-dialog.svelte";
|
||||
|
||||
let {
|
||||
item,
|
||||
onSuccess
|
||||
}: {
|
||||
item: UnitOfMeasureACE;
|
||||
onSuccess?: () => void;
|
||||
} = $props();
|
||||
|
||||
let loading = $state(false);
|
||||
let error = $state<string | null>(null);
|
||||
let dialogOpen = $state(false);
|
||||
|
||||
async function handleDelete() {
|
||||
if (!confirm(`¿Estás seguro de eliminar la unidad "${item.code}"?`)) {
|
||||
return;
|
||||
}
|
||||
|
||||
loading = true;
|
||||
error = null;
|
||||
|
||||
try {
|
||||
const response = await deleteUnitOfMeasureACE(item.id);
|
||||
|
||||
if (response.error) {
|
||||
error = response.error;
|
||||
alert(`Error al eliminar: ${response.error}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (onSuccess) onSuccess();
|
||||
} catch (e) {
|
||||
error = 'Error de conexión';
|
||||
console.error(e);
|
||||
alert('Error de conexión al eliminar');
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger>
|
||||
{#snippet child({ props })}
|
||||
<Button {...props} variant="ghost" size="icon" class="h-8 w-8 p-0">
|
||||
<span class="sr-only">Abrir menú</span>
|
||||
<EllipsisVertical class="h-4 w-4" />
|
||||
</Button>
|
||||
{/snippet}
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Content align="end">
|
||||
<DropdownMenu.Label>Acciones</DropdownMenu.Label>
|
||||
<DropdownMenu.Item onclick={() => dialogOpen = true}>
|
||||
<Pencil class="mr-2 h-4 w-4" />
|
||||
Editar
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item onclick={handleDelete} class="text-red-600">
|
||||
{#if loading}
|
||||
<LoaderCircle class="mr-2 h-4 w-4 animate-spin" />
|
||||
{:else}
|
||||
<Trash2 class="mr-2 h-4 w-4" />
|
||||
{/if}
|
||||
Eliminar
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
|
||||
<CreateEditDialog
|
||||
bind:open={dialogOpen}
|
||||
mode="edit"
|
||||
{item}
|
||||
{onSuccess}
|
||||
/>
|
||||
@@ -1,106 +0,0 @@
|
||||
<script lang="ts" generics="TData, TValue">
|
||||
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 { Button } from "$lib/components/ui/button";
|
||||
import { goto } from "$app/navigation";
|
||||
import { page } from "$app/stores";
|
||||
|
||||
type DataTableProps<TData, TValue> = {
|
||||
columns: ColumnDef<TData, TValue>[];
|
||||
data: TData[];
|
||||
pageCount: number;
|
||||
totalItems: number;
|
||||
};
|
||||
|
||||
let {
|
||||
data,
|
||||
columns,
|
||||
pageCount,
|
||||
totalItems
|
||||
}: DataTableProps<TData, TValue> = $props();
|
||||
|
||||
const table = createSvelteTable({
|
||||
get data() {
|
||||
return data;
|
||||
},
|
||||
columns,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
manualPagination: true,
|
||||
pageCount: pageCount,
|
||||
});
|
||||
|
||||
function handlePageChange(newPage: number) {
|
||||
const url = new URL($page.url);
|
||||
url.searchParams.set('page', newPage.toString());
|
||||
goto(url);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="rounded-md border">
|
||||
<Table.Root>
|
||||
<Table.Header>
|
||||
{#each table.getHeaderGroups() as headerGroup (headerGroup.id)}
|
||||
<Table.Row>
|
||||
{#each headerGroup.headers as header (header.id)}
|
||||
<Table.Head>
|
||||
{#if !header.isPlaceholder}
|
||||
<FlexRender
|
||||
content={header.column.columnDef.header}
|
||||
context={header.getContext()}
|
||||
/>
|
||||
{/if}
|
||||
</Table.Head>
|
||||
{/each}
|
||||
</Table.Row>
|
||||
{/each}
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{#each table.getRowModel().rows as row (row.id)}
|
||||
<Table.Row data-state={row.getIsSelected() && "selected"}>
|
||||
{#each row.getVisibleCells() as cell (cell.id)}
|
||||
<Table.Cell>
|
||||
<FlexRender
|
||||
content={cell.column.columnDef.cell}
|
||||
context={cell.getContext()}
|
||||
/>
|
||||
</Table.Cell>
|
||||
{/each}
|
||||
</Table.Row>
|
||||
{:else}
|
||||
<Table.Row>
|
||||
<Table.Cell colspan={columns.length} class="h-24 text-center">
|
||||
No hay resultados.
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
{/each}
|
||||
</Table.Body>
|
||||
</Table.Root>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-end space-x-2 py-4">
|
||||
<div class="flex-1 text-sm text-muted-foreground">
|
||||
Total: {totalItems}
|
||||
</div>
|
||||
<div class="space-x-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onclick={() => handlePageChange(Number($page.url.searchParams.get('page') || 1) - 1)}
|
||||
disabled={Number($page.url.searchParams.get('page') || 1) <= 1}
|
||||
>
|
||||
Anterior
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onclick={() => handlePageChange(Number($page.url.searchParams.get('page') || 1) + 1)}
|
||||
disabled={Number($page.url.searchParams.get('page') || 1) >= pageCount}
|
||||
>
|
||||
Siguiente
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,27 +0,0 @@
|
||||
import type { UnitOfMeasureAmerican } from '$lib/api/dashboard/a76/general_catalogs/units-of-measure';
|
||||
import type { ColumnDef } from '@tanstack/table-core';
|
||||
import { renderComponent } from '$lib/components/ui/data-table';
|
||||
import DataTableActions from './data-table-actions.svelte';
|
||||
|
||||
export function createColumns(onSuccess?: () => void): ColumnDef<UnitOfMeasureAmerican>[] {
|
||||
return [
|
||||
{
|
||||
accessorKey: 'code',
|
||||
header: 'Código',
|
||||
},
|
||||
{
|
||||
accessorKey: 'description',
|
||||
header: 'Descripción',
|
||||
cell: ({ row }) => row.original.description || '-'
|
||||
},
|
||||
{
|
||||
id: 'actions',
|
||||
cell: ({ row }) => {
|
||||
return renderComponent(DataTableActions, {
|
||||
item: row.original,
|
||||
onSuccess
|
||||
});
|
||||
}
|
||||
}
|
||||
];
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import * as Dialog from "$lib/components/ui/dialog";
|
||||
import { Input } from "$lib/components/ui/input";
|
||||
import { Label } from "$lib/components/ui/label";
|
||||
import { createUnitOfMeasureAmerican, updateUnitOfMeasureAmerican, type UnitOfMeasureAmerican } from "$lib/api/dashboard/a76/general_catalogs/units-of-measure";
|
||||
|
||||
let {
|
||||
open = $bindable(false),
|
||||
mode = 'create',
|
||||
item = null,
|
||||
onSuccess
|
||||
}: {
|
||||
open: boolean;
|
||||
mode?: 'create' | 'edit';
|
||||
item?: UnitOfMeasureAmerican | null;
|
||||
onSuccess?: () => void;
|
||||
} = $props();
|
||||
|
||||
const isEdit = $derived(mode === 'edit');
|
||||
const title = $derived(isEdit ? "Editar Unidad Americana" : "Nueva Unidad Americana");
|
||||
|
||||
let formData = $state({
|
||||
code: '',
|
||||
description: ''
|
||||
});
|
||||
|
||||
let loading = $state(false);
|
||||
let error = $state<string | null>(null);
|
||||
|
||||
$effect(() => {
|
||||
if (open) {
|
||||
if (isEdit && item) {
|
||||
formData = {
|
||||
code: item.code,
|
||||
description: item.description || ''
|
||||
};
|
||||
} else {
|
||||
formData = {
|
||||
code: '',
|
||||
description: ''
|
||||
};
|
||||
}
|
||||
error = null;
|
||||
}
|
||||
});
|
||||
|
||||
async function handleSubmit() {
|
||||
loading = true;
|
||||
error = null;
|
||||
|
||||
try {
|
||||
let response;
|
||||
if (isEdit && item) {
|
||||
response = await updateUnitOfMeasureAmerican(item.id, {
|
||||
code: formData.code,
|
||||
description: formData.description || null
|
||||
});
|
||||
} else {
|
||||
response = await createUnitOfMeasureAmerican({
|
||||
code: formData.code,
|
||||
description: formData.description || null
|
||||
});
|
||||
}
|
||||
|
||||
if (response.error) {
|
||||
error = response.error;
|
||||
return;
|
||||
}
|
||||
|
||||
open = false;
|
||||
if (onSuccess) onSuccess();
|
||||
} catch (e) {
|
||||
error = 'Error de conexión';
|
||||
console.error(e);
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<Dialog.Root bind:open>
|
||||
<Dialog.Content class="sm:max-w-[425px]">
|
||||
<Dialog.Header>
|
||||
<Dialog.Title>{title}</Dialog.Title>
|
||||
</Dialog.Header>
|
||||
|
||||
<div class="grid gap-4 py-4">
|
||||
{#if error}
|
||||
<div class="text-red-500 text-sm mb-2">{error}</div>
|
||||
{/if}
|
||||
|
||||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
<Label for="code" class="text-right">Código</Label>
|
||||
<Input id="code" bind:value={formData.code} class="col-span-3" disabled={loading} />
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
<Label for="description" class="text-right">Descripción</Label>
|
||||
<Input id="description" bind:value={formData.description} class="col-span-3" disabled={loading} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Dialog.Footer>
|
||||
<Button type="submit" onclick={handleSubmit} disabled={loading}>
|
||||
{loading ? 'Guardando...' : 'Guardar'}
|
||||
</Button>
|
||||
</Dialog.Footer>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
@@ -1,79 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import * as DropdownMenu from "$lib/components/ui/dropdown-menu";
|
||||
import { deleteUnitOfMeasureAmerican, type UnitOfMeasureAmerican } from "$lib/api/dashboard/a76/general_catalogs/units-of-measure";
|
||||
import { EllipsisVertical, Pencil, LoaderCircle, Trash2 } from 'lucide-svelte';
|
||||
import CreateEditDialog from "./create-edit-dialog.svelte";
|
||||
|
||||
let {
|
||||
item,
|
||||
onSuccess
|
||||
}: {
|
||||
item: UnitOfMeasureAmerican;
|
||||
onSuccess?: () => void;
|
||||
} = $props();
|
||||
|
||||
let loading = $state(false);
|
||||
let error = $state<string | null>(null);
|
||||
let dialogOpen = $state(false);
|
||||
|
||||
async function handleDelete() {
|
||||
if (!confirm(`¿Estás seguro de eliminar la unidad "${item.code}"?`)) {
|
||||
return;
|
||||
}
|
||||
|
||||
loading = true;
|
||||
error = null;
|
||||
|
||||
try {
|
||||
const response = await deleteUnitOfMeasureAmerican(item.id);
|
||||
|
||||
if (response.error) {
|
||||
error = response.error;
|
||||
alert(`Error al eliminar: ${response.error}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (onSuccess) onSuccess();
|
||||
} catch (e) {
|
||||
error = 'Error de conexión';
|
||||
console.error(e);
|
||||
alert('Error de conexión al eliminar');
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger>
|
||||
{#snippet child({ props })}
|
||||
<Button {...props} variant="ghost" size="icon" class="h-8 w-8 p-0">
|
||||
<span class="sr-only">Abrir menú</span>
|
||||
<EllipsisVertical class="h-4 w-4" />
|
||||
</Button>
|
||||
{/snippet}
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Content align="end">
|
||||
<DropdownMenu.Label>Acciones</DropdownMenu.Label>
|
||||
<DropdownMenu.Item onclick={() => dialogOpen = true}>
|
||||
<Pencil class="mr-2 h-4 w-4" />
|
||||
Editar
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item onclick={handleDelete} class="text-red-600">
|
||||
{#if loading}
|
||||
<LoaderCircle class="mr-2 h-4 w-4 animate-spin" />
|
||||
{:else}
|
||||
<Trash2 class="mr-2 h-4 w-4" />
|
||||
{/if}
|
||||
Eliminar
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
|
||||
<CreateEditDialog
|
||||
bind:open={dialogOpen}
|
||||
mode="edit"
|
||||
{item}
|
||||
{onSuccess}
|
||||
/>
|
||||
@@ -1,32 +0,0 @@
|
||||
import type { ColumnDef } from '@tanstack/table-core';
|
||||
import { renderComponent } from '$lib/components/ui/data-table';
|
||||
import DataTableActions from './data-table-actions.svelte';
|
||||
|
||||
export interface UMCustomsMex {
|
||||
id: number;
|
||||
code: string;
|
||||
description: string | null;
|
||||
}
|
||||
|
||||
export function createColumns(onSuccess?: () => void): ColumnDef<UMCustomsMex>[] {
|
||||
return [
|
||||
{
|
||||
accessorKey: 'code',
|
||||
header: 'Código',
|
||||
},
|
||||
{
|
||||
accessorKey: 'description',
|
||||
header: 'Descripción',
|
||||
cell: ({ row }) => row.original.description || '-'
|
||||
},
|
||||
{
|
||||
id: 'actions',
|
||||
cell: ({ row }) => {
|
||||
return renderComponent(DataTableActions, {
|
||||
item: row.original,
|
||||
onSuccess
|
||||
});
|
||||
}
|
||||
}
|
||||
];
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import * as Dialog from "$lib/components/ui/dialog";
|
||||
import { Input } from "$lib/components/ui/input";
|
||||
import { Label } from "$lib/components/ui/label";
|
||||
import { createUMCustomsMex, updateUMCustomsMex, type UMCustomsMex } from "$lib/api/dashboard/a76/general_catalogs/um-customs-mex";
|
||||
|
||||
let {
|
||||
open = $bindable(false),
|
||||
mode = 'create',
|
||||
item = null,
|
||||
onSuccess
|
||||
}: {
|
||||
open: boolean;
|
||||
mode?: 'create' | 'edit';
|
||||
item?: UMCustomsMex | null;
|
||||
onSuccess?: () => void;
|
||||
} = $props();
|
||||
|
||||
const isEdit = $derived(mode === 'edit');
|
||||
const title = $derived(isEdit ? "Editar Unidad Customs MEX" : "Nueva Unidad Customs MEX");
|
||||
|
||||
let formData = $state({
|
||||
code: '',
|
||||
description: ''
|
||||
});
|
||||
|
||||
let loading = $state(false);
|
||||
let error = $state<string | null>(null);
|
||||
|
||||
$effect(() => {
|
||||
if (open) {
|
||||
if (isEdit && item) {
|
||||
formData = {
|
||||
code: item.code,
|
||||
description: item.description || ''
|
||||
};
|
||||
} else {
|
||||
formData = {
|
||||
code: '',
|
||||
description: ''
|
||||
};
|
||||
}
|
||||
error = null;
|
||||
}
|
||||
});
|
||||
|
||||
async function handleSubmit() {
|
||||
loading = true;
|
||||
error = null;
|
||||
|
||||
try {
|
||||
let response;
|
||||
if (isEdit && item) {
|
||||
response = await updateUMCustomsMex(item.id, {
|
||||
code: formData.code,
|
||||
description: formData.description || null
|
||||
});
|
||||
} else {
|
||||
response = await createUMCustomsMex({
|
||||
code: formData.code,
|
||||
description: formData.description || null
|
||||
});
|
||||
}
|
||||
|
||||
if (response.error) {
|
||||
error = response.error;
|
||||
return;
|
||||
}
|
||||
|
||||
open = false;
|
||||
if (onSuccess) onSuccess();
|
||||
} catch (e) {
|
||||
error = 'Error de conexión';
|
||||
console.error(e);
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<Dialog.Root bind:open>
|
||||
<Dialog.Content class="sm:max-w-[425px]">
|
||||
<Dialog.Header>
|
||||
<Dialog.Title>{title}</Dialog.Title>
|
||||
</Dialog.Header>
|
||||
|
||||
<div class="grid gap-4 py-4">
|
||||
{#if error}
|
||||
<div class="text-red-500 text-sm mb-2">{error}</div>
|
||||
{/if}
|
||||
|
||||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
<Label for="code" class="text-right">Código</Label>
|
||||
<Input id="code" bind:value={formData.code} class="col-span-3" disabled={loading} />
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
<Label for="description" class="text-right">Descripción</Label>
|
||||
<Input id="description" bind:value={formData.description} class="col-span-3" disabled={loading} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end gap-2">
|
||||
<Button variant="outline" onclick={() => open = false} disabled={loading}>
|
||||
Cancelar
|
||||
</Button>
|
||||
<Button onclick={handleSubmit} disabled={loading}>
|
||||
{loading ? 'Guardando...' : 'Guardar'}
|
||||
</Button>
|
||||
</div>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
@@ -1,79 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import * as DropdownMenu from "$lib/components/ui/dropdown-menu";
|
||||
import { deleteUMCustomsMex, type UMCustomsMex } from "$lib/api/dashboard/a76/general_catalogs/um-customs-mex";
|
||||
import { EllipsisVertical, Pencil, LoaderCircle, Trash2 } from 'lucide-svelte';
|
||||
import CreateEditDialog from "./create-edit-dialog.svelte";
|
||||
|
||||
let {
|
||||
item,
|
||||
onSuccess
|
||||
}: {
|
||||
item: UMCustomsMex;
|
||||
onSuccess?: () => void;
|
||||
} = $props();
|
||||
|
||||
let loading = $state(false);
|
||||
let error = $state<string | null>(null);
|
||||
let dialogOpen = $state(false);
|
||||
|
||||
async function handleDelete() {
|
||||
if (!confirm(`¿Estás seguro de eliminar la unidad "${item.code}"?`)) {
|
||||
return;
|
||||
}
|
||||
|
||||
loading = true;
|
||||
error = null;
|
||||
|
||||
try {
|
||||
const response = await deleteUMCustomsMex(item.id);
|
||||
|
||||
if (response.error) {
|
||||
error = response.error;
|
||||
alert(`Error al eliminar: ${response.error}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (onSuccess) onSuccess();
|
||||
} catch (e) {
|
||||
error = 'Error de conexión';
|
||||
console.error(e);
|
||||
alert('Error de conexión al eliminar');
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger>
|
||||
{#snippet child({ props })}
|
||||
<Button {...props} variant="ghost" size="icon" class="h-8 w-8 p-0">
|
||||
<span class="sr-only">Abrir menú</span>
|
||||
<EllipsisVertical class="h-4 w-4" />
|
||||
</Button>
|
||||
{/snippet}
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Content align="end">
|
||||
<DropdownMenu.Label>Acciones</DropdownMenu.Label>
|
||||
<DropdownMenu.Item onclick={() => dialogOpen = true}>
|
||||
<Pencil class="mr-2 h-4 w-4" />
|
||||
Editar
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item onclick={handleDelete} class="text-red-600">
|
||||
{#if loading}
|
||||
<LoaderCircle class="mr-2 h-4 w-4 animate-spin" />
|
||||
{:else}
|
||||
<Trash2 class="mr-2 h-4 w-4" />
|
||||
{/if}
|
||||
Eliminar
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
|
||||
<CreateEditDialog
|
||||
bind:open={dialogOpen}
|
||||
mode="edit"
|
||||
{item}
|
||||
{onSuccess}
|
||||
/>
|
||||
@@ -1,106 +0,0 @@
|
||||
<script lang="ts" generics="TData, TValue">
|
||||
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 { Button } from "$lib/components/ui/button";
|
||||
import { goto } from "$app/navigation";
|
||||
import { page } from "$app/stores";
|
||||
|
||||
type DataTableProps<TData, TValue> = {
|
||||
columns: ColumnDef<TData, TValue>[];
|
||||
data: TData[];
|
||||
pageCount: number;
|
||||
totalItems: number;
|
||||
};
|
||||
|
||||
let {
|
||||
data,
|
||||
columns,
|
||||
pageCount,
|
||||
totalItems
|
||||
}: DataTableProps<TData, TValue> = $props();
|
||||
|
||||
const table = createSvelteTable({
|
||||
get data() {
|
||||
return data;
|
||||
},
|
||||
columns,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
manualPagination: true,
|
||||
pageCount: pageCount,
|
||||
});
|
||||
|
||||
function handlePageChange(newPage: number) {
|
||||
const url = new URL($page.url);
|
||||
url.searchParams.set('page', newPage.toString());
|
||||
goto(url);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="rounded-md border">
|
||||
<Table.Root>
|
||||
<Table.Header>
|
||||
{#each table.getHeaderGroups() as headerGroup (headerGroup.id)}
|
||||
<Table.Row>
|
||||
{#each headerGroup.headers as header (header.id)}
|
||||
<Table.Head>
|
||||
{#if !header.isPlaceholder}
|
||||
<FlexRender
|
||||
content={header.column.columnDef.header}
|
||||
context={header.getContext()}
|
||||
/>
|
||||
{/if}
|
||||
</Table.Head>
|
||||
{/each}
|
||||
</Table.Row>
|
||||
{/each}
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{#each table.getRowModel().rows as row (row.id)}
|
||||
<Table.Row data-state={row.getIsSelected() && "selected"}>
|
||||
{#each row.getVisibleCells() as cell (cell.id)}
|
||||
<Table.Cell>
|
||||
<FlexRender
|
||||
content={cell.column.columnDef.cell}
|
||||
context={cell.getContext()}
|
||||
/>
|
||||
</Table.Cell>
|
||||
{/each}
|
||||
</Table.Row>
|
||||
{:else}
|
||||
<Table.Row>
|
||||
<Table.Cell colspan={columns.length} class="h-24 text-center">
|
||||
No hay resultados.
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
{/each}
|
||||
</Table.Body>
|
||||
</Table.Root>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-end space-x-2 py-4">
|
||||
<div class="flex-1 text-sm text-muted-foreground">
|
||||
Total: {totalItems}
|
||||
</div>
|
||||
<div class="space-x-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onclick={() => handlePageChange(Number($page.url.searchParams.get('page') || 1) - 1)}
|
||||
disabled={Number($page.url.searchParams.get('page') || 1) <= 1}
|
||||
>
|
||||
Anterior
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onclick={() => handlePageChange(Number($page.url.searchParams.get('page') || 1) + 1)}
|
||||
disabled={Number($page.url.searchParams.get('page') || 1) >= pageCount}
|
||||
>
|
||||
Siguiente
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,32 +0,0 @@
|
||||
import type { ColumnDef } from '@tanstack/table-core';
|
||||
import { renderComponent } from '$lib/components/ui/data-table';
|
||||
import DataTableActions from './data-table-actions.svelte';
|
||||
|
||||
export interface UnitMeasure {
|
||||
id: number;
|
||||
code: string;
|
||||
description: string | null;
|
||||
}
|
||||
|
||||
export function createColumns(onSuccess?: () => void): ColumnDef<UnitMeasure>[] {
|
||||
return [
|
||||
{
|
||||
accessorKey: 'code',
|
||||
header: 'Código',
|
||||
},
|
||||
{
|
||||
accessorKey: 'description',
|
||||
header: 'Descripción',
|
||||
cell: ({ row }) => row.original.description || '-'
|
||||
},
|
||||
{
|
||||
id: 'actions',
|
||||
cell: ({ row }) => {
|
||||
return renderComponent(DataTableActions, {
|
||||
item: row.original,
|
||||
onSuccess
|
||||
});
|
||||
}
|
||||
}
|
||||
];
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import * as Dialog from "$lib/components/ui/dialog";
|
||||
import { Input } from "$lib/components/ui/input";
|
||||
import { Label } from "$lib/components/ui/label";
|
||||
import { createUnitMeasure, updateUnitMeasure, type UnitMeasure } from "$lib/api/dashboard/a76/general_catalogs/unit-measures";
|
||||
|
||||
let {
|
||||
open = $bindable(false),
|
||||
mode = 'create',
|
||||
item = null,
|
||||
onSuccess
|
||||
}: {
|
||||
open: boolean;
|
||||
mode?: 'create' | 'edit';
|
||||
item?: UnitMeasure | null;
|
||||
onSuccess?: () => void;
|
||||
} = $props();
|
||||
|
||||
const isEdit = $derived(mode === 'edit');
|
||||
const title = $derived(isEdit ? "Editar Unidad de Medida" : "Nueva Unidad de Medida");
|
||||
|
||||
let formData = $state({
|
||||
code: '',
|
||||
description: ''
|
||||
});
|
||||
|
||||
let loading = $state(false);
|
||||
let error = $state<string | null>(null);
|
||||
|
||||
$effect(() => {
|
||||
if (open) {
|
||||
if (isEdit && item) {
|
||||
formData = {
|
||||
code: item.code,
|
||||
description: item.description || ''
|
||||
};
|
||||
} else {
|
||||
formData = {
|
||||
code: '',
|
||||
description: ''
|
||||
};
|
||||
}
|
||||
error = null;
|
||||
}
|
||||
});
|
||||
|
||||
async function handleSubmit() {
|
||||
loading = true;
|
||||
error = null;
|
||||
|
||||
try {
|
||||
let response;
|
||||
if (isEdit && item) {
|
||||
response = await updateUnitMeasure(item.id, {
|
||||
code: formData.code,
|
||||
description: formData.description || null
|
||||
});
|
||||
} else {
|
||||
response = await createUnitMeasure({
|
||||
code: formData.code,
|
||||
description: formData.description || null
|
||||
});
|
||||
}
|
||||
|
||||
if (response.error) {
|
||||
error = response.error;
|
||||
return;
|
||||
}
|
||||
|
||||
open = false;
|
||||
if (onSuccess) onSuccess();
|
||||
} catch (e) {
|
||||
error = 'Error de conexión';
|
||||
console.error(e);
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<Dialog.Root bind:open>
|
||||
<Dialog.Content class="sm:max-w-[425px]">
|
||||
<Dialog.Header>
|
||||
<Dialog.Title>{title}</Dialog.Title>
|
||||
</Dialog.Header>
|
||||
|
||||
<div class="grid gap-4 py-4">
|
||||
{#if error}
|
||||
<div class="text-red-500 text-sm mb-2">{error}</div>
|
||||
{/if}
|
||||
|
||||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
<Label for="code" class="text-right">Código</Label>
|
||||
<Input id="code" bind:value={formData.code} class="col-span-3" disabled={loading} />
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
<Label for="description" class="text-right">Descripción</Label>
|
||||
<Input id="description" bind:value={formData.description} class="col-span-3" disabled={loading} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end gap-2">
|
||||
<Button variant="outline" onclick={() => open = false} disabled={loading}>
|
||||
Cancelar
|
||||
</Button>
|
||||
<Button onclick={handleSubmit} disabled={loading}>
|
||||
{loading ? 'Guardando...' : 'Guardar'}
|
||||
</Button>
|
||||
</div>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
@@ -1,79 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import * as DropdownMenu from "$lib/components/ui/dropdown-menu";
|
||||
import { deleteUnitMeasure, type UnitMeasure } from "$lib/api/dashboard/a76/general_catalogs/unit-measures";
|
||||
import { EllipsisVertical, Pencil, LoaderCircle, Trash2 } from 'lucide-svelte';
|
||||
import CreateEditDialog from "./create-edit-dialog.svelte";
|
||||
|
||||
let {
|
||||
item,
|
||||
onSuccess
|
||||
}: {
|
||||
item: UnitMeasure;
|
||||
onSuccess?: () => void;
|
||||
} = $props();
|
||||
|
||||
let loading = $state(false);
|
||||
let error = $state<string | null>(null);
|
||||
let dialogOpen = $state(false);
|
||||
|
||||
async function handleDelete() {
|
||||
if (!confirm(`¿Estás seguro de eliminar la unidad "${item.code}"?`)) {
|
||||
return;
|
||||
}
|
||||
|
||||
loading = true;
|
||||
error = null;
|
||||
|
||||
try {
|
||||
const response = await deleteUnitMeasure(item.id);
|
||||
|
||||
if (response.error) {
|
||||
error = response.error;
|
||||
alert(`Error al eliminar: ${response.error}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (onSuccess) onSuccess();
|
||||
} catch (e) {
|
||||
error = 'Error de conexión';
|
||||
console.error(e);
|
||||
alert('Error de conexión al eliminar');
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger>
|
||||
{#snippet child({ props })}
|
||||
<Button {...props} variant="ghost" size="icon" class="h-8 w-8 p-0">
|
||||
<span class="sr-only">Abrir menú</span>
|
||||
<EllipsisVertical class="h-4 w-4" />
|
||||
</Button>
|
||||
{/snippet}
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Content align="end">
|
||||
<DropdownMenu.Label>Acciones</DropdownMenu.Label>
|
||||
<DropdownMenu.Item onclick={() => dialogOpen = true}>
|
||||
<Pencil class="mr-2 h-4 w-4" />
|
||||
Editar
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item onclick={handleDelete} class="text-red-600">
|
||||
{#if loading}
|
||||
<LoaderCircle class="mr-2 h-4 w-4 animate-spin" />
|
||||
{:else}
|
||||
<Trash2 class="mr-2 h-4 w-4" />
|
||||
{/if}
|
||||
Eliminar
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
|
||||
<CreateEditDialog
|
||||
bind:open={dialogOpen}
|
||||
mode="edit"
|
||||
{item}
|
||||
{onSuccess}
|
||||
/>
|
||||
@@ -1,106 +0,0 @@
|
||||
<script lang="ts" generics="TData, TValue">
|
||||
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 { Button } from "$lib/components/ui/button";
|
||||
import { goto } from "$app/navigation";
|
||||
import { page } from "$app/stores";
|
||||
|
||||
type DataTableProps<TData, TValue> = {
|
||||
columns: ColumnDef<TData, TValue>[];
|
||||
data: TData[];
|
||||
pageCount: number;
|
||||
totalItems: number;
|
||||
};
|
||||
|
||||
let {
|
||||
data,
|
||||
columns,
|
||||
pageCount,
|
||||
totalItems
|
||||
}: DataTableProps<TData, TValue> = $props();
|
||||
|
||||
const table = createSvelteTable({
|
||||
get data() {
|
||||
return data;
|
||||
},
|
||||
columns,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
manualPagination: true,
|
||||
pageCount: pageCount,
|
||||
});
|
||||
|
||||
function handlePageChange(newPage: number) {
|
||||
const url = new URL($page.url);
|
||||
url.searchParams.set('page', newPage.toString());
|
||||
goto(url);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="rounded-md border">
|
||||
<Table.Root>
|
||||
<Table.Header>
|
||||
{#each table.getHeaderGroups() as headerGroup (headerGroup.id)}
|
||||
<Table.Row>
|
||||
{#each headerGroup.headers as header (header.id)}
|
||||
<Table.Head>
|
||||
{#if !header.isPlaceholder}
|
||||
<FlexRender
|
||||
content={header.column.columnDef.header}
|
||||
context={header.getContext()}
|
||||
/>
|
||||
{/if}
|
||||
</Table.Head>
|
||||
{/each}
|
||||
</Table.Row>
|
||||
{/each}
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{#each table.getRowModel().rows as row (row.id)}
|
||||
<Table.Row data-state={row.getIsSelected() && "selected"}>
|
||||
{#each row.getVisibleCells() as cell (cell.id)}
|
||||
<Table.Cell>
|
||||
<FlexRender
|
||||
content={cell.column.columnDef.cell}
|
||||
context={cell.getContext()}
|
||||
/>
|
||||
</Table.Cell>
|
||||
{/each}
|
||||
</Table.Row>
|
||||
{:else}
|
||||
<Table.Row>
|
||||
<Table.Cell colspan={columns.length} class="h-24 text-center">
|
||||
No hay resultados.
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
{/each}
|
||||
</Table.Body>
|
||||
</Table.Root>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-end space-x-2 py-4">
|
||||
<div class="flex-1 text-sm text-muted-foreground">
|
||||
Total: {totalItems}
|
||||
</div>
|
||||
<div class="space-x-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onclick={() => handlePageChange(Number($page.url.searchParams.get('page') || 1) - 1)}
|
||||
disabled={Number($page.url.searchParams.get('page') || 1) <= 1}
|
||||
>
|
||||
Anterior
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onclick={() => handlePageChange(Number($page.url.searchParams.get('page') || 1) + 1)}
|
||||
disabled={Number($page.url.searchParams.get('page') || 1) >= pageCount}
|
||||
>
|
||||
Siguiente
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,27 +0,0 @@
|
||||
import type { UnitOfMeasureOMA } from '$lib/api/dashboard/a76/general_catalogs/units-of-measure';
|
||||
import type { ColumnDef } from '@tanstack/table-core';
|
||||
import { renderComponent } from '$lib/components/ui/data-table';
|
||||
import DataTableActions from './data-table-actions.svelte';
|
||||
|
||||
export function createColumns(onSuccess?: () => void): ColumnDef<UnitOfMeasureOMA>[] {
|
||||
return [
|
||||
{
|
||||
accessorKey: 'code',
|
||||
header: 'Código',
|
||||
},
|
||||
{
|
||||
accessorKey: 'description',
|
||||
header: 'Descripción',
|
||||
cell: ({ row }) => row.original.description || '-'
|
||||
},
|
||||
{
|
||||
id: 'actions',
|
||||
cell: ({ row }) => {
|
||||
return renderComponent(DataTableActions, {
|
||||
item: row.original,
|
||||
onSuccess
|
||||
});
|
||||
}
|
||||
}
|
||||
];
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import * as Dialog from "$lib/components/ui/dialog";
|
||||
import { Input } from "$lib/components/ui/input";
|
||||
import { Label } from "$lib/components/ui/label";
|
||||
import { createUnitOfMeasureOMA, updateUnitOfMeasureOMA, type UnitOfMeasureOMA } from "$lib/api/dashboard/a76/general_catalogs/units-of-measure";
|
||||
|
||||
let {
|
||||
open = $bindable(false),
|
||||
mode = 'create',
|
||||
item = null,
|
||||
onSuccess
|
||||
}: {
|
||||
open: boolean;
|
||||
mode?: 'create' | 'edit';
|
||||
item?: UnitOfMeasureOMA | null;
|
||||
onSuccess?: () => void;
|
||||
} = $props();
|
||||
|
||||
const isEdit = $derived(mode === 'edit');
|
||||
const title = $derived(isEdit ? "Editar Unidad OMA" : "Nueva Unidad OMA");
|
||||
|
||||
let formData = $state({
|
||||
code: '',
|
||||
description: ''
|
||||
});
|
||||
|
||||
let loading = $state(false);
|
||||
let error = $state<string | null>(null);
|
||||
|
||||
$effect(() => {
|
||||
if (open) {
|
||||
if (isEdit && item) {
|
||||
formData = {
|
||||
code: item.code,
|
||||
description: item.description || ''
|
||||
};
|
||||
} else {
|
||||
formData = {
|
||||
code: '',
|
||||
description: ''
|
||||
};
|
||||
}
|
||||
error = null;
|
||||
}
|
||||
});
|
||||
|
||||
async function handleSubmit() {
|
||||
loading = true;
|
||||
error = null;
|
||||
|
||||
try {
|
||||
let response;
|
||||
if (isEdit && item) {
|
||||
response = await updateUnitOfMeasureOMA(item.id, {
|
||||
code: formData.code,
|
||||
description: formData.description || null
|
||||
});
|
||||
} else {
|
||||
response = await createUnitOfMeasureOMA({
|
||||
code: formData.code,
|
||||
description: formData.description || null
|
||||
});
|
||||
}
|
||||
|
||||
if (response.error) {
|
||||
error = response.error;
|
||||
return;
|
||||
}
|
||||
|
||||
open = false;
|
||||
if (onSuccess) onSuccess();
|
||||
} catch (e) {
|
||||
error = 'Error de conexión';
|
||||
console.error(e);
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<Dialog.Root bind:open>
|
||||
<Dialog.Content class="sm:max-w-[425px]">
|
||||
<Dialog.Header>
|
||||
<Dialog.Title>{title}</Dialog.Title>
|
||||
</Dialog.Header>
|
||||
|
||||
<div class="grid gap-4 py-4">
|
||||
{#if error}
|
||||
<div class="text-red-500 text-sm mb-2">{error}</div>
|
||||
{/if}
|
||||
|
||||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
<Label for="code" class="text-right">Código</Label>
|
||||
<Input id="code" bind:value={formData.code} class="col-span-3" disabled={loading} />
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
<Label for="description" class="text-right">Descripción</Label>
|
||||
<Input id="description" bind:value={formData.description} class="col-span-3" disabled={loading} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Dialog.Footer>
|
||||
<Button type="submit" onclick={handleSubmit} disabled={loading}>
|
||||
{loading ? 'Guardando...' : 'Guardar'}
|
||||
</Button>
|
||||
</Dialog.Footer>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
@@ -1,79 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import * as DropdownMenu from "$lib/components/ui/dropdown-menu";
|
||||
import { deleteUnitOfMeasureOMA, type UnitOfMeasureOMA } from "$lib/api/dashboard/a76/general_catalogs/units-of-measure";
|
||||
import { EllipsisVertical, Pencil, LoaderCircle, Trash2 } from 'lucide-svelte';
|
||||
import CreateEditDialog from "./create-edit-dialog.svelte";
|
||||
|
||||
let {
|
||||
item,
|
||||
onSuccess
|
||||
}: {
|
||||
item: UnitOfMeasureOMA;
|
||||
onSuccess?: () => void;
|
||||
} = $props();
|
||||
|
||||
let loading = $state(false);
|
||||
let error = $state<string | null>(null);
|
||||
let dialogOpen = $state(false);
|
||||
|
||||
async function handleDelete() {
|
||||
if (!confirm(`¿Estás seguro de eliminar la unidad "${item.code}"?`)) {
|
||||
return;
|
||||
}
|
||||
|
||||
loading = true;
|
||||
error = null;
|
||||
|
||||
try {
|
||||
const response = await deleteUnitOfMeasureOMA(item.id);
|
||||
|
||||
if (response.error) {
|
||||
error = response.error;
|
||||
alert(`Error al eliminar: ${response.error}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (onSuccess) onSuccess();
|
||||
} catch (e) {
|
||||
error = 'Error de conexión';
|
||||
console.error(e);
|
||||
alert('Error de conexión al eliminar');
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger>
|
||||
{#snippet child({ props })}
|
||||
<Button {...props} variant="ghost" size="icon" class="h-8 w-8 p-0">
|
||||
<span class="sr-only">Abrir menú</span>
|
||||
<EllipsisVertical class="h-4 w-4" />
|
||||
</Button>
|
||||
{/snippet}
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Content align="end">
|
||||
<DropdownMenu.Label>Acciones</DropdownMenu.Label>
|
||||
<DropdownMenu.Item onclick={() => dialogOpen = true}>
|
||||
<Pencil class="mr-2 h-4 w-4" />
|
||||
Editar
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item onclick={handleDelete} class="text-red-600">
|
||||
{#if loading}
|
||||
<LoaderCircle class="mr-2 h-4 w-4 animate-spin" />
|
||||
{:else}
|
||||
<Trash2 class="mr-2 h-4 w-4" />
|
||||
{/if}
|
||||
Eliminar
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
|
||||
<CreateEditDialog
|
||||
bind:open={dialogOpen}
|
||||
mode="edit"
|
||||
{item}
|
||||
{onSuccess}
|
||||
/>
|
||||
Reference in New Issue
Block a user