fix: unauthorized on document upload and drag-drop in booking creation
- 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 <noreply@anthropic.com>
This commit is contained in:
parent
b344650608
commit
1da5570e1c
@ -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<string | null>(null);
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const [formData, setFormData] = useState<BookingForm>({
|
||||
carrierName: '',
|
||||
@ -419,8 +421,30 @@ function NewBookingPageContent() {
|
||||
|
||||
{/* File Upload */}
|
||||
<div className="space-y-4 mb-8">
|
||||
<div className="border-2 border-dashed border-gray-300 rounded-lg p-8 text-center hover:border-blue-400 transition-colors">
|
||||
<div
|
||||
className={`border-2 border-dashed rounded-lg p-8 text-center transition-colors cursor-pointer ${
|
||||
isDragging
|
||||
? 'border-blue-500 bg-blue-50'
|
||||
: 'border-gray-300 hover:border-blue-400 hover:bg-gray-50'
|
||||
}`}
|
||||
onDragOver={e => {
|
||||
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()}
|
||||
>
|
||||
<input
|
||||
ref={fileInputRef}
|
||||
type="file"
|
||||
id="file-upload"
|
||||
multiple
|
||||
@ -428,12 +452,9 @@ function NewBookingPageContent() {
|
||||
onChange={e => handleFileChange(e.target.files)}
|
||||
className="hidden"
|
||||
/>
|
||||
<label
|
||||
htmlFor="file-upload"
|
||||
className="cursor-pointer flex flex-col items-center"
|
||||
>
|
||||
<div className="flex flex-col items-center">
|
||||
<svg
|
||||
className="w-16 h-16 text-gray-400 mb-4"
|
||||
className={`w-16 h-16 mb-4 transition-colors ${isDragging ? 'text-blue-500' : 'text-gray-400'}`}
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
@ -446,10 +467,10 @@ function NewBookingPageContent() {
|
||||
/>
|
||||
</svg>
|
||||
<p className="text-lg font-semibold text-gray-700 mb-2">
|
||||
Cliquez pour sélectionner des fichiers
|
||||
{isDragging ? 'Déposez vos fichiers ici' : 'Cliquez pour sélectionner des fichiers'}
|
||||
</p>
|
||||
<p className="text-sm text-gray-500">ou glissez-déposez vos documents ici</p>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Document Type Suggestions */}
|
||||
|
||||
@ -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 }
|
||||
|
||||
Loading…
Reference in New Issue
Block a user