feat(F-194): completed feature

This commit is contained in:
chattie
2026-08-22 22:29:26 +02:00
parent ca12f46bff
commit b85670cb51
15 changed files with 73 additions and 6 deletions

View File

@@ -1,5 +1,6 @@
'use client';
import { useState, useEffect, useCallback, useRef } from 'react';
import Link from 'next/link';
import { auditApi, type AuditEntry } from '@/lib/api-client';
const PAGE_SIZE = 50;
@@ -79,6 +80,7 @@ export default function AuditLogPage() {
return (
<div className="space-y-6">
<div>
<Link href="/settings" className="text-sm text-[#2D6A4F] hover:underline"> Ajustes</Link>
<h1 className="text-2xl font-bold text-gray-900">Log de auditoría
{pollingActive && (
<span className="ml-3 inline-flex items-center gap-1.5 text-xs text-green-600 font-medium align-middle">

View File

@@ -1,4 +1,5 @@
'use client';
import Link from 'next/link';
import { ServerLogViewer } from '@/components/ServerLogViewer';
export default function ServerLogsPage() {
@@ -10,6 +11,7 @@ export default function ServerLogsPage() {
return (
<div className="space-y-6">
<div>
<Link href="/settings" className="text-sm text-[#2D6A4F] hover:underline"> Ajustes</Link>
<h1 className="text-2xl font-bold text-gray-900">Logs del servidor</h1>
<p className="text-sm text-gray-500 mt-0.5">
Stream en tiempo real via SSE. Las líneas erróneas se resaltan en rojo. Máximo 200 líneas.

View File

@@ -1,5 +1,6 @@
'use client';
import { useState, useEffect } from 'react';
import Link from 'next/link';
import { settingsApi, type StoreSettings } from '@/lib/api-client';
type FormData = StoreSettings;
@@ -105,6 +106,17 @@ export default function SettingsPage() {
{t.label}
</button>
))}
<div className="my-3 border-t border-gray-200" />
<p className="px-4 text-xs font-semibold uppercase tracking-wide text-gray-400">Sistema</p>
<Link href="/settings/tax-rates" className="flex w-full items-center gap-2 px-4 py-2.5 rounded-xl text-sm font-medium text-gray-600 hover:bg-gray-100 transition-colors">
<span>💰</span> IVA
</Link>
<Link href="/settings/audit" className="flex w-full items-center gap-2 px-4 py-2.5 rounded-xl text-sm font-medium text-gray-600 hover:bg-gray-100 transition-colors">
<span>📋</span> Auditoría
</Link>
<Link href="/settings/logs" className="flex w-full items-center gap-2 px-4 py-2.5 rounded-xl text-sm font-medium text-gray-600 hover:bg-gray-100 transition-colors">
<span>🖥</span> Logs
</Link>
</nav>
{/* Form area */}

View File

@@ -1,6 +1,7 @@
'use client';
import { useState, useEffect, useCallback } from 'react';
import { taxApi, type TaxRate } from '@/lib/api-client';
import Link from 'next/link';
import { RowActions } from '@/components/ui/RowActions';
export default function TaxRatesPage() {
@@ -69,6 +70,7 @@ export default function TaxRatesPage() {
return (
<div className="space-y-6">
<div>
<Link href="/settings" className="text-sm text-[#2D6A4F] hover:underline"> Ajustes</Link>
<h1 className="text-2xl font-bold text-gray-900">Tipos impositivos (IVA)</h1>
<p className="text-sm text-gray-500 mt-0.5">Configura los tipos de IVA aplicables a los productos.</p>
</div>

View File

@@ -55,10 +55,10 @@ export const NAV_ITEMS: NavItem[] = [
{ href: '/reviews', label: 'Reseñas', icon: '⭐', permission: 'reviews.read' },
{ href: '/cms', label: 'CMS', icon: '📄', permission: 'cms.read' },
{ href: '/users', label: 'Usuarios', icon: '🔐', permission: 'admin-users.read' },
{ href: '/tax-rates', label: 'IVA', icon: '📊', permission: 'orders.read' },
{ href: '/audit', label: 'Auditoría', icon: '📋', permission: 'audit.read' },
{ href: '/logs', label: 'Logs', icon: '🖥️', permission: 'audit.read' },
{ href: '/settings', label: 'Ajustes', icon: '⚙️', permission: 'dashboard' },
{ href: '/settings/tax-rates', label: 'IVA', icon: '💰', permission: 'orders.read' },
{ href: '/settings/audit', label: 'Auditoría', icon: '📋', permission: 'audit.read' },
{ href: '/settings/logs', label: 'Logs', icon: '🖥️', permission: 'audit.read' },
];
export function visibleNavItems(role: Role): NavItem[] {

View File

@@ -274,7 +274,7 @@ export default function RegisterPage() {
setCart((current) => [
...current,
{
lineId: `free-${crypto.randomUUID()}`,
lineId: `free-${generateIdempotencyKey()}`,
kind: 'free',
variantId: null,
productId: null,

View File

@@ -3,6 +3,7 @@
import { useMemo, useState } from 'react';
import { formatPrice } from '@/lib/money';
import type { PaymentAllocation, PaymentMethod } from '@/types/checkout';
import { generateIdempotencyKey } from '@/lib/idempotency';
interface PaymentModalProps {
method: PaymentMethod;
@@ -48,7 +49,7 @@ export default function PaymentModal({
return;
}
onAdd({
id: crypto.randomUUID(),
id: generateIdempotencyKey(),
methodCode: method.code,
methodLabel: method.label,
kind: method.kind,