feat: bugfixes, spedup, bulk actions,

This commit is contained in:
Vasily Zubarev
2025-03-17 18:36:25 +01:00
parent b27f07043e
commit 14967e1c85
34 changed files with 433 additions and 225 deletions

View File

@@ -26,9 +26,9 @@ export default async function TransactionPage({ params }: { params: Promise<{ tr
const projects = await getProjects()
return (
<>
<Card className="flex flex-col md:flex-row flex-wrap justify-center items-start gap-10 p-5 bg-accent max-w-6xl">
<div className="flex-1">
<div className="flex flex-wrap flex-row items-start justify-center gap-4 max-w-6xl">
<Card className="w-full flex-1 flex flex-col flex-wrap justify-center items-start gap-10 p-5 bg-accent">
<div className="w-full">
<TransactionEditForm
transaction={transaction}
categories={categories}
@@ -37,26 +37,29 @@ export default async function TransactionPage({ params }: { params: Promise<{ tr
fields={fields}
projects={projects}
/>
</div>
<div className="max-w-[320px] space-y-4">
<TransactionFiles transaction={transaction} files={files} />
{transaction.text && (
<details className="mt-10">
<summary className="cursor-pointer text-sm font-medium">Recognized Text</summary>
<Card className="flex items-stretch p-2 max-w-6xl">
<div className="flex-1">
<FormTextarea
title=""
name="text"
defaultValue={transaction.text || ""}
hideIfEmpty={true}
className="w-full h-[400px]"
/>
</div>
</Card>
</details>
)}
</div>
</Card>
{transaction.text && (
<Card className="flex items-stretch p-5 mt-10 max-w-6xl">
<div className="flex-1">
<FormTextarea
title="Recognized Text"
name="text"
defaultValue={transaction.text || ""}
hideIfEmpty={true}
className="w-full h-[400px]"
/>
</div>
</Card>
)}
</>
<div className="w-1/3 max-w-[380px] space-y-4">
<TransactionFiles transaction={transaction} files={files} />
</div>
</div>
)
}

View File

@@ -2,6 +2,7 @@
import { createFile, deleteFile } from "@/data/files"
import {
bulkDeleteTransactions,
createTransaction,
deleteTransaction,
getTransactionById,
@@ -90,13 +91,13 @@ export async function deleteTransactionFileAction(
return { success: true }
}
export async function uploadTransactionFileAction(formData: FormData): Promise<{ success: boolean; error?: string }> {
export async function uploadTransactionFilesAction(formData: FormData): Promise<{ success: boolean; error?: string }> {
try {
const transactionId = formData.get("transactionId") as string
const file = formData.get("file") as File
const files = formData.getAll("files") as File[]
if (!file || !transactionId) {
return { success: false, error: "No file or transaction ID provided" }
if (!files || !transactionId) {
return { success: false, error: "No files or transaction ID provided" }
}
const transaction = await getTransactionById(transactionId)
@@ -109,29 +110,36 @@ export async function uploadTransactionFileAction(formData: FormData): Promise<{
await mkdir(FILE_UPLOAD_PATH, { recursive: true })
}
// Save file to filesystem
const { fileUuid, filePath } = await getTransactionFileUploadPath(file.name, transaction)
const arrayBuffer = await file.arrayBuffer()
const buffer = Buffer.from(arrayBuffer)
await writeFile(filePath, buffer)
const fileRecords = await Promise.all(
files.map(async (file) => {
const { fileUuid, filePath } = await getTransactionFileUploadPath(file.name, transaction)
const arrayBuffer = await file.arrayBuffer()
const buffer = Buffer.from(arrayBuffer)
await writeFile(filePath, buffer)
// Create file record in database
const fileRecord = await createFile({
id: fileUuid,
filename: file.name,
path: filePath,
mimetype: file.type,
isReviewed: true,
metadata: {
size: file.size,
lastModified: file.lastModified,
},
})
// Create file record in database
const fileRecord = await createFile({
id: fileUuid,
filename: file.name,
path: filePath,
mimetype: file.type,
isReviewed: true,
metadata: {
size: file.size,
lastModified: file.lastModified,
},
})
return fileRecord
})
)
// Update invoice with the new file ID
await updateTransactionFiles(
transactionId,
transaction.files ? [...(transaction.files as string[]), fileRecord.id] : [fileRecord.id]
transaction.files
? [...(transaction.files as string[]), ...fileRecords.map((file) => file.id)]
: fileRecords.map((file) => file.id)
)
revalidatePath(`/transactions/${transactionId}`)
@@ -141,3 +149,14 @@ export async function uploadTransactionFileAction(formData: FormData): Promise<{
return { success: false, error: `File upload failed: ${error}` }
}
}
export async function bulkDeleteTransactionsAction(transactionIds: string[]) {
try {
await bulkDeleteTransactions(transactionIds)
revalidatePath("/transactions")
return { success: true }
} catch (error) {
console.error("Failed to delete transactions:", error)
return { success: false, error: "Failed to delete transactions" }
}
}

View File

@@ -28,7 +28,7 @@ export default async function TransactionsPage({ searchParams }: { searchParams:
<header className="flex flex-wrap items-center justify-between gap-2 mb-8">
<h2 className="text-3xl font-bold tracking-tight">Transactions</h2>
<div className="flex gap-2">
<ExportTransactionsDialog filters={filters} fields={fields} categories={categories} projects={projects}>
<ExportTransactionsDialog fields={fields} categories={categories} projects={projects}>
<Button variant="outline">
<Download />
<span className="hidden md:block">Export</span>