diff --git a/app/api/documents/[id]/versions/route.ts b/app/api/documents/[id]/versions/route.ts index 2459d087..4a4c00d4 100644 --- a/app/api/documents/[id]/versions/route.ts +++ b/app/api/documents/[id]/versions/route.ts @@ -1,7 +1,7 @@ import { createClient } from '@/lib/supabase/server' import { NextResponse } from 'next/server' import { ensureInitialized } from '@/lib/init' -import { createNewVersion } from '@/lib/core/documents/document-service' +import { createNewVersion, validateDocumentFile } from '@/lib/core/documents/document-service' import { requireCompanyId } from '@/lib/company/context' ensureInitialized() @@ -37,6 +37,11 @@ export async function POST( return NextResponse.json({ error: 'No file provided' }, { status: 400 }) } + const validationError = validateDocumentFile({ size: file.size, type: file.type }) + if (validationError) { + return NextResponse.json({ error: validationError }, { status: 400 }) + } + const buffer = await file.arrayBuffer() const newVersion = await createNewVersion(supabase, user.id, id, { diff --git a/app/api/documents/route.ts b/app/api/documents/route.ts index d30ff262..b500b3ea 100644 --- a/app/api/documents/route.ts +++ b/app/api/documents/route.ts @@ -1,7 +1,7 @@ import { createClient } from '@/lib/supabase/server' import { NextResponse } from 'next/server' import { ensureInitialized } from '@/lib/init' -import { uploadDocument } from '@/lib/core/documents/document-service' +import { uploadDocument, validateDocumentFile } from '@/lib/core/documents/document-service' import { requireCompanyId } from '@/lib/company/context' ensureInitialized() @@ -35,6 +35,11 @@ export async function POST(request: Request) { return NextResponse.json({ error: 'No file provided' }, { status: 400 }) } + const validationError = validateDocumentFile({ size: file.size, type: file.type }) + if (validationError) { + return NextResponse.json({ error: validationError }, { status: 400 }) + } + const uploadSource = (formData.get('upload_source') as string) || 'file_upload' const journalEntryId = formData.get('journal_entry_id') as string | null const journalEntryLineId = formData.get('journal_entry_line_id') as string | null diff --git a/components/bookkeeping/DocumentUploadZone.tsx b/components/bookkeeping/DocumentUploadZone.tsx index 2ed48d11..c0af2084 100644 --- a/components/bookkeeping/DocumentUploadZone.tsx +++ b/components/bookkeeping/DocumentUploadZone.tsx @@ -12,6 +12,8 @@ export interface UploadedFile { error?: string fileName: string fileSize: number + /** Unique key to track this upload (handles duplicate filenames) */ + uploadKey: string } interface DocumentUploadZoneProps { @@ -23,6 +25,7 @@ interface DocumentUploadZoneProps { compact?: boolean } +let uploadCounter = 0 const MAX_FILE_SIZE = 10 * 1024 * 1024 // 10 MB const ACCEPTED_TYPES = ['application/pdf', 'image/jpeg', 'image/png', 'image/webp'] const ACCEPTED_EXTENSIONS = '.pdf,.jpg,.jpeg,.png,.webp' @@ -87,6 +90,7 @@ export default function DocumentUploadZone({ error: 'Filtypen stöds inte', fileName: file.name, fileSize: file.size, + uploadKey: `upload-${++uploadCounter}`, }) continue } @@ -97,6 +101,7 @@ export default function DocumentUploadZone({ error: 'Filen är för stor (max 10 MB)', fileName: file.name, fileSize: file.size, + uploadKey: `upload-${++uploadCounter}`, }) continue } @@ -105,6 +110,7 @@ export default function DocumentUploadZone({ status: 'uploading', fileName: file.name, fileSize: file.size, + uploadKey: `upload-${++uploadCounter}`, }) } @@ -115,7 +121,7 @@ export default function DocumentUploadZone({ for (const f of validFiles.filter((f) => f.status === 'uploading')) { const result = await uploadFile(f) currentFiles = currentFiles.map((cf) => - cf.fileName === result.fileName && cf.status === 'uploading' ? result : cf + cf.uploadKey === f.uploadKey ? result : cf ) onFilesChange([...currentFiles]) } @@ -200,7 +206,7 @@ export default function DocumentUploadZone({