diff --git a/src/app/quickaction-dashboard/register-upload-id/company/hooks/useCompanyUploadId.ts b/src/app/quickaction-dashboard/register-upload-id/company/hooks/useCompanyUploadId.ts new file mode 100644 index 0000000..26c1d64 --- /dev/null +++ b/src/app/quickaction-dashboard/register-upload-id/company/hooks/useCompanyUploadId.ts @@ -0,0 +1,150 @@ +'use client' + +import { useState, useRef, useEffect, useCallback } from 'react' +import useAuthStore from '../../../../store/authStore' +import { useUserStatus } from '../../../../hooks/useUserStatus' + +export function useCompanyUploadId() { + // Auth + status + const { accessToken } = useAuthStore() + const { refreshStatus } = useUserStatus() + + // Form state + const [docNumber, setDocNumber] = useState('') + const [docType, setDocType] = useState('') + const [issueDate, setIssueDate] = useState('') + const [hasBack, setHasBack] = useState(true) + + // Files + previews + const [frontFile, setFrontFile] = useState(null) + const [extraFile, setExtraFile] = useState(null) + const [frontPreview, setFrontPreview] = useState(null) + const [extraPreview, setExtraPreview] = useState(null) + + // UI state + const [submitting, setSubmitting] = useState(false) + const [error, setError] = useState('') + const [success, setSuccess] = useState(false) + + // Refs + const frontRef = useRef(null) + const extraRef = useRef(null) + + // Unified input style + const inputBase = + 'w-full h-11 rounded-lg border border-gray-300 px-4 text-sm text-gray-900 placeholder:text-gray-900 placeholder:opacity-100 focus:ring-2 focus:ring-indigo-500 focus:border-transparent bg-white' + + // File handlers + const handleFile = (file: File, which: 'front' | 'extra') => { + if (file.size > 10 * 1024 * 1024) { + setError('Datei größer als 10 MB.') + return + } + setError('') + which === 'front' ? setFrontFile(file) : setExtraFile(file) + } + + const onDrop = (e: React.DragEvent, which: 'front' | 'extra') => { + e.preventDefault() + const f = e.dataTransfer.files?.[0] + if (f) handleFile(f, which) + } + + const clearFile = (which: 'front' | 'extra') => { + which === 'front' ? setFrontFile(null) : setExtraFile(null) + } + + const dropHandlers = { + onDragOver: (e: React.DragEvent) => e.preventDefault(), + onDragEnter: (e: React.DragEvent) => e.preventDefault(), + } + + const openPicker = useCallback((which: 'front' | 'extra') => { + (which === 'front' ? frontRef.current : extraRef.current)?.click() + }, []) + + // Previews (images only) + useEffect(() => { + if (!frontFile || !frontFile.type?.startsWith('image/')) { setFrontPreview(null); return } + const url = URL.createObjectURL(frontFile) + setFrontPreview(url) + return () => URL.revokeObjectURL(url) + }, [frontFile]) + + useEffect(() => { + if (!extraFile || !extraFile.type?.startsWith('image/')) { setExtraPreview(null); return } + const url = URL.createObjectURL(extraFile) + setExtraPreview(url) + return () => URL.revokeObjectURL(url) + }, [extraFile]) + + // Validation + const validate = () => { + if (!docNumber.trim() || !docType || !issueDate || !frontFile) { + setError('Bitte alle Pflichtfelder (mit *) ausfüllen.') + return false + } + setError('') + return true + } + + // Submit + const submit = async (e: React.FormEvent) => { + e.preventDefault() + if (!validate()) return + if (!accessToken) { + setError('Not authenticated. Please log in again.') + return + } + + setSubmitting(true) + setError('') + + try { + const formData = new FormData() + if (frontFile) formData.append('frontFile', frontFile) + if (hasBack && extraFile) formData.append('backFile', extraFile) + formData.append('docType', docType) + formData.append('docNumber', docNumber.trim()) + formData.append('issueDate', issueDate) + + const response = await fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/api/upload/company-id`, { + method: 'POST', + headers: { 'Authorization': `Bearer ${accessToken}` }, + body: formData, + }) + + if (!response.ok) { + const errorData = await response.json().catch(() => ({ message: 'Upload failed' })) + throw new Error(errorData.message || 'Upload failed') + } + + setSuccess(true) + await refreshStatus() + + setTimeout(() => { + // keep same redirect as page used before + window.location.href = '/quickaction-dashboard/register-additional-information' + }, 1500) + } catch (err: any) { + console.error('Company ID upload error:', err) + setError(err?.message || 'Upload fehlgeschlagen.') + } finally { + setSubmitting(false) + } + } + + return { + // values + docNumber, docType, issueDate, hasBack, + frontFile, extraFile, + frontPreview, extraPreview, + submitting, error, success, + frontRef, extraRef, + inputBase, + // setters + setDocNumber, setDocType, setIssueDate, setHasBack, setExtraFile, + // handlers + handleFile, onDrop, clearFile, dropHandlers, openPicker, submit, + } +} diff --git a/src/app/quickaction-dashboard/register-upload-id/company/page.tsx b/src/app/quickaction-dashboard/register-upload-id/company/page.tsx index 270e7da..d710c6b 100644 --- a/src/app/quickaction-dashboard/register-upload-id/company/page.tsx +++ b/src/app/quickaction-dashboard/register-upload-id/company/page.tsx @@ -1,99 +1,57 @@ 'use client' -import { useState, useRef } from 'react' -import { useRouter } from 'next/navigation' import PageLayout from '../../../components/PageLayout' import { DocumentArrowUpIcon, XMarkIcon } from '@heroicons/react/24/outline' -import useAuthStore from '../../../store/authStore' -import { useUserStatus } from '../../../hooks/useUserStatus' +import { useCompanyUploadId } from './hooks/useCompanyUploadId' +import useAuthStore from '../../../store/authStore' // NEW +import { useEffect, useState } from 'react' // NEW +import { useRouter } from 'next/navigation' // NEW const DOC_TYPES = ['Handelsregisterauszug', 'Gewerbeanmeldung', 'Steuerbescheid', 'Sonstiges'] export default function CompanyIdUploadPage() { - const router = useRouter() - const { accessToken } = useAuthStore() - const { refreshStatus } = useUserStatus() - - const [docNumber, setDocNumber] = useState('') - const [docType, setDocType] = useState('') - const [issueDate, setIssueDate] = useState('') - const [frontFile, setFrontFile] = useState(null) - const [extraFile, setExtraFile] = useState(null) - const [submitting, setSubmitting] = useState(false) - const [error, setError] = useState('') - const [success, setSuccess] = useState(false) + const { + // values + docNumber, setDocNumber, + docType, setDocType, + issueDate, setIssueDate, + hasBack, setHasBack, setExtraFile, + frontFile, extraFile, + frontPreview, extraPreview, + submitting, error, success, + frontRef, extraRef, + inputBase, + // handlers + handleFile, onDrop, clearFile, dropHandlers, openPicker, submit, + } = useCompanyUploadId() - const frontRef = useRef(null) - const extraRef = useRef(null) + const user = useAuthStore(s => s.user) // NEW + const router = useRouter() // NEW + const [blocked, setBlocked] = useState(false) // NEW - const handleFile = (file: File, which: 'front' | 'extra') => { - if (file.size > 10 * 1024 * 1024) { - setError('Datei größer als 10 MB.') - return + // Guard: only 'company' users allowed on this page + useEffect(() => { + const ut = (user as any)?.userType || (user as any)?.role + console.log('🧭 UploadID Guard [company]: userType =', ut) + if (ut && ut !== 'company') { + console.warn('🚫 UploadID Guard [company]: access denied for userType:', ut, '-> redirecting to personal upload') + setBlocked(true) + router.replace('/quickaction-dashboard/register-upload-id/personal') + } else if (ut === 'company') { + console.log('✅ UploadID Guard [company]: access granted') } - setError('') - which === 'front' ? setFrontFile(file) : setExtraFile(file) - } + }, [user, router]) - const dropHandlers = { - onDragOver: (e: React.DragEvent) => e.preventDefault(), - onDragEnter: (e: React.DragEvent) => e.preventDefault() - } - - const submit = async (e: React.FormEvent) => { - e.preventDefault() - if (!docNumber.trim() || !docType || !issueDate || !frontFile) { - setError('Bitte alle Pflichtfelder (mit *) ausfüllen.') - return - } - - if (!accessToken) { - setError('Not authenticated. Please log in again.') - return - } - - setError('') - setSubmitting(true) - - try { - const formData = new FormData() - formData.append('frontFile', frontFile) - if (extraFile) { - formData.append('backFile', extraFile) - } - formData.append('docType', docType) - formData.append('docNumber', docNumber.trim()) - formData.append('issueDate', issueDate) - - const response = await fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/api/upload/company-id`, { - method: 'POST', - headers: { - 'Authorization': `Bearer ${accessToken}` - }, - body: formData - }) - - if (!response.ok) { - const errorData = await response.json().catch(() => ({ message: 'Upload failed' })) - throw new Error(errorData.message || 'Upload failed') - } - - setSuccess(true) - - // Refresh user status to update verification state - await refreshStatus() - - // Redirect to next step after short delay - setTimeout(() => { - router.push('/quickaction-dashboard/register-additional-information') - }, 1500) - - } catch (error: any) { - console.error('Company ID upload error:', error) - setError(error.message || 'Upload fehlgeschlagen.') - } finally { - setSubmitting(false) - } + if (blocked) { + return ( + +
+
+ Redirecting to the correct upload page… +
+
+
+ ) } return ( @@ -118,10 +76,7 @@ export default function CompanyIdUploadPage() { -
+

Company Document Verification @@ -130,15 +85,16 @@ export default function CompanyIdUploadPage() { Upload a valid company registration or compliance document

-
-
+ {/* Fields: 3 in one row on md+ with unified inputs */} +
+
setDocNumber(e.target.value)} - className="w-full rounded-lg border border-gray-300 px-4 py-2.5 text-sm focus:ring-2 focus:ring-indigo-500 focus:border-transparent" + className={`${inputBase} ${docNumber ? 'text-gray-900' : 'text-gray-700'}`} placeholder="Enter reference number" required /> @@ -151,7 +107,7 @@ export default function CompanyIdUploadPage() { { - const f = e.target.files?.[0] - if (f) handleFile(f, 'front') - }} + onChange={e => { const f = e.target.files?.[0]; if (f) handleFile(f, 'front') }} /> {frontFile ? ( -
- -

{frontFile.name}

+
+ {/* Preview only for images */} + {frontPreview && ( + Primary document preview + )} +

{frontFile.name}

-
{ - e.preventDefault() - const f = e.dataTransfer.files?.[0] - if (f) handleFile(f, 'extra') - }} - onClick={() => extraRef.current?.click()} - className="group flex flex-col items-center justify-center rounded-lg border-2 border-dashed border-gray-300 bg-gray-50/60 px-4 py-10 text-center hover:border-indigo-400 hover:bg-indigo-50/40 cursor-pointer transition" - > - { - const f = e.target.files?.[0] - if (f) handleFile(f, 'extra') - }} - /> - {extraFile ? ( -
- -

{extraFile.name}

- -
- ) : ( - <> - -

- Optional supporting file -

-

- (Invoice, license, certificate…) -

- - )} -
- - {extraFile &&
- Extra space for clarity -
} + {/* Back/supporting document */} + {hasBack && ( +
onDrop(e, 'extra')} + onClick={() => openPicker('extra')} + className="group relative flex flex-col items-center justify-center rounded-lg border-2 border-dashed border-gray-300 bg-gray-50/60 px-4 py-6 sm:py-10 text-center hover:border-indigo-400 hover:bg-indigo-50/40 cursor-pointer transition" + > + { const f = e.target.files?.[0]; if (f) handleFile(f, 'extra') }} + /> + {extraFile ? ( +
+ {/* Preview only for images */} + {extraPreview && ( + Supporting document preview + )} +

{extraFile.name}

+ +
+ ) : ( + <> + +

+ Optional supporting file +

+

+ (Invoice, license, certificate…) +

+ + )} +
+ )}
{/* Info */} diff --git a/src/app/quickaction-dashboard/register-upload-id/personal/hooks/usePersonalUploadId.ts b/src/app/quickaction-dashboard/register-upload-id/personal/hooks/usePersonalUploadId.ts new file mode 100644 index 0000000..1f10e83 --- /dev/null +++ b/src/app/quickaction-dashboard/register-upload-id/personal/hooks/usePersonalUploadId.ts @@ -0,0 +1,157 @@ +'use client' + +import { useState, useRef, useCallback, useEffect } from 'react' +import useAuthStore from '../../../../store/authStore' +import { useUserStatus } from '../../../../hooks/useUserStatus' + +export function usePersonalUploadId() { + // Auth and status + const token = useAuthStore(s => s.accessToken) + const { refreshStatus } = useUserStatus() + + // Form state + const [idNumber, setIdNumber] = useState('') + const [idType, setIdType] = useState('') + const [expiry, setExpiry] = useState('') + const [hasBack, setHasBack] = useState(true) + + // Files + previews + const [frontFile, setFrontFile] = useState(null) + const [backFile, setBackFile] = useState(null) + const [frontPreview, setFrontPreview] = useState(null) + const [backPreview, setBackPreview] = useState(null) + + // UI state + const [submitting, setSubmitting] = useState(false) + const [error, setError] = useState('') + const [success, setSuccess] = useState(false) + + // Refs + const frontInputRef = useRef(null) + const backInputRef = useRef(null) + + // Shared input style + const inputBase = + 'w-full h-11 rounded-lg border border-gray-300 px-4 text-sm text-gray-900 placeholder:text-gray-900 placeholder:opacity-100 focus:ring-2 focus:ring-indigo-500 focus:border-transparent bg-white' + + // File handlers + const handleFile = (f: File, side: 'front' | 'back') => { + if (f.size > 10 * 1024 * 1024) { + setError('Datei größer als 10 MB.') + return + } + setError('') + side === 'front' ? setFrontFile(f) : setBackFile(f) + } + + const onDrop = (e: React.DragEvent, side: 'front' | 'back') => { + e.preventDefault() + const f = e.dataTransfer.files?.[0] + if (f) handleFile(f, side) + } + + const clearFile = (side: 'front' | 'back') => { + side === 'front' ? setFrontFile(null) : setBackFile(null) + } + + const dropEvents = { + onDragOver: (e: React.DragEvent) => e.preventDefault(), + onDragEnter: (e: React.DragEvent) => e.preventDefault(), + } + + const openPicker = useCallback((side: 'front' | 'back') => { + (side === 'front' ? frontInputRef.current : backInputRef.current)?.click() + }, []) + + // Previews + useEffect(() => { + if (!frontFile) { setFrontPreview(null); return } + const url = URL.createObjectURL(frontFile) + setFrontPreview(url) + return () => URL.revokeObjectURL(url) + }, [frontFile]) + + useEffect(() => { + if (!backFile) { setBackPreview(null); return } + const url = URL.createObjectURL(backFile) + setBackPreview(url) + return () => URL.revokeObjectURL(url) + }, [backFile]) + + // Validation + const validate = () => { + if (!idNumber.trim() || !idType || !expiry) { + setError('Bitte alle Pflichtfelder ausfüllen.') + return false + } + if (!frontFile) { + setError('Vorderseite hochladen.') + return false + } + if (hasBack && !backFile) { + setError('Rückseite hochladen oder Schalter deaktivieren.') + return false + } + setError('') + return true + } + + // Submit + const submit = async (e: React.FormEvent) => { + e.preventDefault() + if (!validate()) return + if (!token) { + setError('Nicht authentifiziert. Bitte erneut einloggen.') + return + } + + setSubmitting(true) + setError('') + + try { + const formData = new FormData() + if (frontFile) formData.append('front', frontFile) + if (hasBack && backFile) formData.append('back', backFile) + formData.append('idType', idType) + formData.append('idNumber', idNumber) + formData.append('expiryDate', expiry) + + const response = await fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/api/upload/personal-id`, { + method: 'POST', + headers: { 'Authorization': `Bearer ${token}` }, + body: formData + }) + + const data = await response.json().catch(() => ({})) + + if (response.ok && data.success) { + setSuccess(true) + await refreshStatus() + setTimeout(() => { + window.location.href = '/quickaction-dashboard' + }, 2000) + } else { + setError(data.message || 'Upload fehlgeschlagen. Bitte erneut versuchen.') + } + } catch (err) { + console.error('Upload error:', err) + setError('Netzwerkfehler. Bitte erneut versuchen.') + } finally { + setSubmitting(false) + } + } + + return { + // values + idNumber, idType, expiry, hasBack, + frontFile, backFile, + frontPreview, backPreview, + submitting, error, success, + frontInputRef, backInputRef, + inputBase, + // setters + setIdNumber, setIdType, setExpiry, setHasBack, + // handlers + handleFile, onDrop, clearFile, dropEvents, openPicker, submit, + } +} diff --git a/src/app/quickaction-dashboard/register-upload-id/personal/page.tsx b/src/app/quickaction-dashboard/register-upload-id/personal/page.tsx index 907c091..2f66193 100644 --- a/src/app/quickaction-dashboard/register-upload-id/personal/page.tsx +++ b/src/app/quickaction-dashboard/register-upload-id/personal/page.tsx @@ -1,130 +1,54 @@ 'use client' -import { useState, useRef, useCallback } from 'react' +import { usePersonalUploadId } from './hooks/usePersonalUploadId' import PageLayout from '../../../components/PageLayout' +import { useEffect, useState } from 'react' +import { useRouter } from 'next/navigation' import useAuthStore from '../../../store/authStore' -import { useUserStatus } from '../../../hooks/useUserStatus' -import { - DocumentArrowUpIcon, - XMarkIcon -} from '@heroicons/react/24/outline' - -const ID_TYPES = [ - { value: 'national_id', label: 'Personalausweis' }, - { value: 'passport', label: 'Reisepass' }, - { value: 'driver_license', label: 'Führerschein' }, - { value: 'other', label: 'Aufenthaltstitel' } -] +import { DocumentArrowUpIcon, XMarkIcon } from '@heroicons/react/24/outline' export default function PersonalIdUploadPage() { - const token = useAuthStore(s => s.accessToken) - const { refreshStatus } = useUserStatus() - const [idNumber, setIdNumber] = useState('') - const [idType, setIdType] = useState('') - const [expiry, setExpiry] = useState('') - const [hasBack, setHasBack] = useState(true) - const [frontFile, setFrontFile] = useState(null) - const [backFile, setBackFile] = useState(null) - const [submitting, setSubmitting] = useState(false) - const [error, setError] = useState('') - const [success, setSuccess] = useState(false) + // NEW: guard company users from accessing personal page + const user = useAuthStore(s => s.user) + const router = useRouter() + const [blocked, setBlocked] = useState(false) - const frontInputRef = useRef(null) - const backInputRef = useRef(null) - - const handleFile = (f: File, side: 'front' | 'back') => { - if (f.size > 10 * 1024 * 1024) { - setError('Datei größer als 10 MB.') - return + useEffect(() => { + const ut = (user as any)?.userType || (user as any)?.role + console.log('🧭 UploadID Guard [personal]: userType =', ut) + if (ut && ut !== 'personal') { + console.warn('🚫 UploadID Guard [personal]: access denied for userType:', ut, '-> redirecting to company upload') + setBlocked(true) + router.replace('/quickaction-dashboard/register-upload-id/company') + } else if (ut === 'personal') { + console.log('✅ UploadID Guard [personal]: access granted') } - setError('') - side === 'front' ? setFrontFile(f) : setBackFile(f) + }, [user, router]) + + if (blocked) { + return ( + +
+
+ Redirecting to the correct upload page… +
+
+
+ ) } - const onDrop = (e: React.DragEvent, side: 'front' | 'back') => { - e.preventDefault() - const f = e.dataTransfer.files?.[0] - if (f) handleFile(f, side) - } - - const validate = () => { - if (!idNumber.trim() || !idType || !expiry) { - setError('Bitte alle Pflichtfelder ausfüllen.') - return false - } - if (!frontFile) { - setError('Vorderseite hochladen.') - return false - } - if (hasBack && !backFile) { - setError('Rückseite hochladen oder Schalter deaktivieren.') - return false - } - setError('') - return true - } - - const submit = async (e: React.FormEvent) => { - e.preventDefault() - if (!validate()) return - if (!token) { - setError('Nicht authentifiziert. Bitte erneut einloggen.') - return - } - - setSubmitting(true) - setError('') - - try { - const formData = new FormData() - formData.append('front', frontFile!) - if (hasBack && backFile) { - formData.append('back', backFile) - } - formData.append('idType', idType) - formData.append('idNumber', idNumber) - formData.append('expiryDate', expiry) - - const response = await fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/api/upload/personal-id`, { - method: 'POST', - headers: { - 'Authorization': `Bearer ${token}` - }, - body: formData - }) - - const data = await response.json() - - if (response.ok && data.success) { - setSuccess(true) - await refreshStatus() // Refresh user status - // Redirect after 2 seconds - setTimeout(() => { - window.location.href = '/quickaction-dashboard' - }, 2000) - } else { - setError(data.message || 'Upload fehlgeschlagen. Bitte erneut versuchen.') - } - } catch (error) { - console.error('Upload error:', error) - setError('Netzwerkfehler. Bitte erneut versuchen.') - } finally { - setSubmitting(false) - } - } - - const clearFile = (side: 'front' | 'back') => { - side === 'front' ? setFrontFile(null) : setBackFile(null) - } - - const dropEvents = { - onDragOver: (e: React.DragEvent) => e.preventDefault(), - onDragEnter: (e: React.DragEvent) => e.preventDefault() - } - - const openPicker = useCallback((side: 'front' | 'back') => { - (side === 'front' ? frontInputRef.current : backInputRef.current)?.click() - }, []) + const { + idNumber, setIdNumber, + idType, setIdType, + expiry, setExpiry, + hasBack, setHasBack, + frontFile, backFile, + frontPreview, backPreview, + submitting, error, success, + frontInputRef, backInputRef, + handleFile, onDrop, clearFile, dropEvents, openPicker, submit, + inputBase, + } = usePersonalUploadId() return ( @@ -148,10 +72,7 @@ export default function PersonalIdUploadPage() {
- +

Personal Identity Verification @@ -160,9 +81,9 @@ export default function PersonalIdUploadPage() { Please upload clear photos of both sides of your government‑issued ID

- {/* Grid Fields */} -
-
+ {/* Grid Fields: put all three inputs on the same line on md+ */} +
+
@@ -170,10 +91,10 @@ export default function PersonalIdUploadPage() { value={idNumber} onChange={e => setIdNumber(e.target.value)} placeholder="Enter your ID number" - className="w-full rounded-lg border border-gray-300 px-4 py-2.5 text-sm focus:ring-2 focus:ring-indigo-500 focus:border-transparent" + className={`${inputBase} ${idNumber ? 'text-gray-900' : 'text-gray-700'}`} required /> -

+

Enter the number exactly as shown on your ID

@@ -185,11 +106,11 @@ export default function PersonalIdUploadPage() {
@@ -201,11 +122,11 @@ export default function PersonalIdUploadPage() { type="date" value={expiry} onChange={e => setExpiry(e.target.value)} - className="w-full rounded-lg border border-gray-300 px-4 py-2.5 text-sm focus:ring-2 focus:ring-indigo-500 focus:border-transparent" + placeholder="tt.mm jjjj" + className={`${inputBase} ${expiry ? 'text-gray-900' : 'text-gray-700'} appearance-none [&::-webkit-calendar-picker-indicator]:opacity-80`} required />
-
{/* Back side toggle */} @@ -230,29 +151,33 @@ export default function PersonalIdUploadPage() { {hasBack ? 'Yes' : 'No'}

- {/* Upload Areas */} -
+ {/* Upload Areas: full width, 1 col if no back, 2 cols if back */} +
{/* Front */}
onDrop(e, 'front')} onClick={() => openPicker('front')} - className="group relative flex flex-col items-center justify-center rounded-lg border-2 border-dashed border-gray-300 bg-gray-50/60 px-4 py-10 text-center hover:border-indigo-400 hover:bg-indigo-50/40 cursor-pointer transition" + className="group relative flex flex-col items-center justify-center rounded-lg border-2 border-dashed border-gray-300 bg-gray-50/60 px-4 py-6 sm:py-10 text-center hover:border-indigo-400 hover:bg-indigo-50/40 cursor-pointer transition" > { - const f = e.target.files?.[0] - if (f) handleFile(f, 'front') - }} + onChange={e => { const f = e.target.files?.[0]; if (f) handleFile(f, 'front') }} /> {frontFile ? ( -
- -

{frontFile.name}

+
+ {/* NEW preview */} + {frontPreview && ( + Front ID preview + )} +

{frontFile.name}

) : ( <> - +

Click to upload front side

@@ -282,22 +207,26 @@ export default function PersonalIdUploadPage() { {...dropEvents} onDrop={e => onDrop(e, 'back')} onClick={() => openPicker('back')} - className="group relative flex flex-col items-center justify-center rounded-lg border-2 border-dashed border-gray-300 bg-gray-50/60 px-4 py-10 text-center hover:border-indigo-400 hover:bg-indigo-50/40 cursor-pointer transition" + className="group relative flex flex-col items-center justify-center rounded-lg border-2 border-dashed border-gray-300 bg-gray-50/60 px-4 py-6 sm:py-10 text-center hover:border-indigo-400 hover:bg-indigo-50/40 cursor-pointer transition" > { - const f = e.target.files?.[0] - if (f) handleFile(f, 'back') - }} + onChange={e => { const f = e.target.files?.[0]; if (f) handleFile(f, 'back') }} /> {backFile ? ( -
- -

{backFile.name}

+
+ {/* NEW preview */} + {backPreview && ( + Back ID preview + )} +

{backFile.name}

) : ( <> - +

Click to upload back side

@@ -321,12 +250,9 @@ export default function PersonalIdUploadPage() { )}
)} - {hasBack &&
- Extra space for clarity -
}
- {/* Info Box */} + {/* Info Box, errors, success, submit */}

Please ensure your ID documents: