From 1da5570e1cf286bdca7b6d78dd8e89cafcfead51 Mon Sep 17 00:00:00 2001 From: David Date: Sun, 7 Jun 2026 17:42:27 +0200 Subject: [PATCH] fix: unauthorized on document upload and drag-drop in booking creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace localStorage.getItem('access_token') with getAuthToken() which also checks sessionStorage — fixes Unauthorized error for users logged in without 'remember me' - Add real drag-and-drop support to booking creation page (step 2): onDragOver/onDragLeave/onDrop handlers on the dropzone container, isDragging state with visual feedback (blue border + text change), click-to-browse still works via hidden input ref Co-Authored-By: Claude Sonnet 4.6 --- .../[locale]/dashboard/booking/new/page.tsx | 39 ++++++++++++++----- .../app/[locale]/dashboard/documents/page.tsx | 5 ++- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/apps/frontend/app/[locale]/dashboard/booking/new/page.tsx b/apps/frontend/app/[locale]/dashboard/booking/new/page.tsx index a613cb4..adedceb 100644 --- a/apps/frontend/app/[locale]/dashboard/booking/new/page.tsx +++ b/apps/frontend/app/[locale]/dashboard/booking/new/page.tsx @@ -6,7 +6,7 @@ 'use client'; -import { useState, useEffect, Suspense } from 'react'; +import { useState, useEffect, useRef, Suspense } from 'react'; import { useRouter, useSearchParams } from 'next/navigation'; import { ClipboardList, Mail, AlertTriangle } from 'lucide-react'; import type { CsvRateSearchResult } from '@/types/rates'; @@ -55,6 +55,8 @@ function NewBookingPageContent() { const [isSubmitting, setIsSubmitting] = useState(false); const [termsAccepted, setTermsAccepted] = useState(false); const [error, setError] = useState(null); + const [isDragging, setIsDragging] = useState(false); + const fileInputRef = useRef(null); const [formData, setFormData] = useState({ carrierName: '', @@ -419,8 +421,30 @@ function NewBookingPageContent() { {/* File Upload */}
-
+
{ + e.preventDefault(); + setIsDragging(true); + }} + onDragLeave={e => { + if (!e.currentTarget.contains(e.relatedTarget as Node)) { + setIsDragging(false); + } + }} + onDrop={e => { + e.preventDefault(); + setIsDragging(false); + handleFileChange(e.dataTransfer.files); + }} + onClick={() => fileInputRef.current?.click()} + > handleFileChange(e.target.files)} className="hidden" /> -
{/* Document Type Suggestions */} diff --git a/apps/frontend/app/[locale]/dashboard/documents/page.tsx b/apps/frontend/app/[locale]/dashboard/documents/page.tsx index cf17ae5..fc276b0 100644 --- a/apps/frontend/app/[locale]/dashboard/documents/page.tsx +++ b/apps/frontend/app/[locale]/dashboard/documents/page.tsx @@ -3,6 +3,7 @@ import { useState, useEffect, useCallback, useRef } from 'react'; import { useTranslations, useLocale } from 'next-intl'; import { listCsvBookings, CsvBookingResponse } from '@/lib/api/bookings'; +import { getAuthToken } from '@/lib/api/client'; import { FileText, Image as ImageIcon, FileEdit, FileSpreadsheet, Paperclip } from 'lucide-react'; import type { ReactNode } from 'react'; import ExportButton from '@/components/ExportButton'; @@ -277,7 +278,7 @@ export default function UserDocumentsPage() { const formData = new FormData(); addFiles.forEach(file => formData.append('documents', file)); - const token = localStorage.getItem('access_token'); + const token = getAuthToken(); const response = await fetch( `${process.env.NEXT_PUBLIC_API_URL}/api/v1/csv-bookings/${selectedBookingId}/documents`, { method: 'POST', headers: { Authorization: `Bearer ${token}` }, body: formData } @@ -335,7 +336,7 @@ export default function UserDocumentsPage() { const formData = new FormData(); formData.append('document', replaceFile); - const token = localStorage.getItem('access_token'); + const token = getAuthToken(); const response = await fetch( `${process.env.NEXT_PUBLIC_API_URL}/api/v1/csv-bookings/${documentToReplace.bookingId}/documents/${documentToReplace.id}`, { method: 'PATCH', headers: { Authorization: `Bearer ${token}` }, body: formData }