From 2fcebffb34598ee524b8194b75b956017fcfbb8b Mon Sep 17 00:00:00 2001 From: Jakob Wennberg <149234542+jakobwennberg@users.noreply.github.com> Date: Mon, 13 Apr 2026 16:54:58 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20remove=20delete=20button=20from=20list?= =?UTF-8?q?=20view=20=E2=80=94=20use=20detail=20page=20instead=20(#232)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The client-side lastInSeriesIds computation only sees the current page of entries (20 at a time), producing false positives when the true last voucher is on a different page or in a different fiscal period. Delete is now only available from the detail page (/bookkeeping/[id]) where is_last_in_series is computed server-side from the full dataset. Co-authored-by: Claude Opus 4.6 (1M context) --- components/bookkeeping/JournalEntryList.tsx | 76 +-------------------- 1 file changed, 1 insertion(+), 75 deletions(-) diff --git a/components/bookkeeping/JournalEntryList.tsx b/components/bookkeeping/JournalEntryList.tsx index 27d8ec84..d98bbcc5 100644 --- a/components/bookkeeping/JournalEntryList.tsx +++ b/components/bookkeeping/JournalEntryList.tsx @@ -1,6 +1,6 @@ 'use client' -import { useState, useEffect, useCallback, useMemo } from 'react' +import { useState, useEffect, useCallback } from 'react' import Link from 'next/link' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Badge } from '@/components/ui/badge' @@ -13,8 +13,6 @@ import { AccountNumber } from '@/components/ui/account-number' import { getAccountDescription } from '@/lib/bookkeeping/account-descriptions' import JournalEntryAttachments from '@/components/bookkeeping/JournalEntryAttachments' import CorrectionEntryDialog from '@/components/bookkeeping/CorrectionEntryDialog' -import { ConfirmationDialog } from '@/components/ui/confirmation-dialog' -import { useToast } from '@/components/ui/use-toast' import JournalEntryStatusBadge from '@/components/bookkeeping/JournalEntryStatusBadge' import type { JournalEntry, JournalEntryLine } from '@/types' @@ -32,7 +30,6 @@ interface Props { } export default function JournalEntryList({ periodId }: Props) { - const { toast } = useToast() const [entries, setEntries] = useState([]) const [loading, setLoading] = useState(true) const [expandedId, setExpandedId] = useState(null) @@ -41,8 +38,6 @@ export default function JournalEntryList({ periodId }: Props) { const [attachmentCounts, setAttachmentCounts] = useState>({}) const [showMissingOnly, setShowMissingOnly] = useState(false) const [correctionEntry, setCorrectionEntry] = useState(null) - const [deleteEntry, setDeleteEntry] = useState(null) - const [isDeleting, setIsDeleting] = useState(false) const [dateSortDir, setDateSortDir] = useState<'desc' | 'asc'>('desc') const [dateFrom, setDateFrom] = useState('') const [dateTo, setDateTo] = useState('') @@ -139,43 +134,6 @@ export default function JournalEntryList({ periodId }: Props) { setAttachmentCounts((prev) => ({ ...prev, [entryId]: count })) }, []) - // Compute which entries are the last in their series (enables delete button) - const lastInSeriesIds = useMemo(() => { - const maxPerSeries = new Map() - for (const e of entries) { - if (e.status !== 'posted') continue - const key = `${e.fiscal_period_id}:${e.voucher_series}` - const current = maxPerSeries.get(key) - if (!current || e.voucher_number > current.num) { - maxPerSeries.set(key, { id: e.id, num: e.voucher_number }) - } - } - return new Set(Array.from(maxPerSeries.values()).map(v => v.id)) - }, [entries]) - - const handleDeleteEntry = useCallback(async () => { - if (!deleteEntry) return - setIsDeleting(true) - try { - const res = await fetch(`/api/bookkeeping/journal-entries/${deleteEntry.id}`, { method: 'DELETE' }) - const result = await res.json() - if (res.ok) { - toast({ - title: 'Verifikat raderat', - description: `Verifikat ${result.data?.voucher_series ?? ''}${result.data?.voucher_number ?? ''} har raderats.`, - }) - setDeleteEntry(null) - fetchEntries() - } else { - toast({ title: 'Kunde inte radera', description: result.error, variant: 'destructive' }) - } - } catch { - toast({ title: 'Kunde inte radera verifikat', variant: 'destructive' }) - } finally { - setIsDeleting(false) - } - }, [deleteEntry, toast]) - const toggleExpand = (id: string) => { setExpandedId(expandedId === id ? null : id) } @@ -477,16 +435,6 @@ export default function JournalEntryList({ periodId }: Props) { - {entry.status === 'posted' && lastInSeriesIds.has(entry.id) && ( - - )} {entry.status === 'posted' && entry.source_type !== 'storno' && entry.source_type !== 'correction' && (