124 lines
4.3 KiB
TypeScript
124 lines
4.3 KiB
TypeScript
'use client'
|
|
// =============================================================================
|
|
// QRCodeModal — extracted from DocumentUploadSection for LOC compliance
|
|
// =============================================================================
|
|
|
|
import { useEffect, useState } from 'react'
|
|
import { QRIcon, CloseIcon } from './DocumentUploadIcons'
|
|
|
|
interface QRModalProps {
|
|
isOpen: boolean
|
|
onClose: () => void
|
|
sessionId: string
|
|
onFileUploaded?: (file: File) => void
|
|
}
|
|
|
|
export function QRCodeModal({ isOpen, onClose, sessionId }: QRModalProps) {
|
|
const [uploadUrl, setUploadUrl] = useState('')
|
|
const [qrCodeUrl, setQrCodeUrl] = useState<string | null>(null)
|
|
|
|
useEffect(() => {
|
|
if (!isOpen) return
|
|
|
|
let baseUrl = typeof window !== 'undefined' ? window.location.origin : ''
|
|
|
|
// Hostname to IP mapping for local network
|
|
const hostnameToIP: Record<string, string> = {
|
|
'macmini': '192.168.178.100',
|
|
'macmini.local': '192.168.178.100',
|
|
}
|
|
|
|
Object.entries(hostnameToIP).forEach(([hostname, ip]) => {
|
|
if (baseUrl.includes(hostname)) {
|
|
baseUrl = baseUrl.replace(hostname, ip)
|
|
}
|
|
})
|
|
|
|
// Force HTTP for mobile access (SSL cert is for hostname, not IP)
|
|
// This is safe because it's only used on the local network
|
|
if (baseUrl.startsWith('https://')) {
|
|
baseUrl = baseUrl.replace('https://', 'http://')
|
|
}
|
|
|
|
const uploadPath = `/upload/sdk/${sessionId}`
|
|
const fullUrl = `${baseUrl}${uploadPath}`
|
|
setUploadUrl(fullUrl)
|
|
|
|
const qrApiUrl = `https://api.qrserver.com/v1/create-qr-code/?size=250x250&data=${encodeURIComponent(fullUrl)}`
|
|
setQrCodeUrl(qrApiUrl)
|
|
}, [isOpen, sessionId])
|
|
|
|
const copyToClipboard = async () => {
|
|
try {
|
|
await navigator.clipboard.writeText(uploadUrl)
|
|
} catch (err) {
|
|
console.error('Copy failed:', err)
|
|
}
|
|
}
|
|
|
|
if (!isOpen) return null
|
|
|
|
return (
|
|
<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
|
|
<div className="absolute inset-0 bg-black/50 backdrop-blur-sm" onClick={onClose} />
|
|
<div className="relative bg-white rounded-2xl shadow-xl max-w-md w-full p-6">
|
|
<div className="flex items-center justify-between mb-6">
|
|
<div className="flex items-center gap-3">
|
|
<div className="w-10 h-10 rounded-xl bg-purple-100 flex items-center justify-center">
|
|
<QRIcon />
|
|
</div>
|
|
<div>
|
|
<h3 className="font-semibold text-gray-900">Mit Handy hochladen</h3>
|
|
<p className="text-sm text-gray-500">QR-Code scannen</p>
|
|
</div>
|
|
</div>
|
|
<button onClick={onClose} className="p-2 hover:bg-gray-100 rounded-lg">
|
|
<CloseIcon />
|
|
</button>
|
|
</div>
|
|
|
|
<div className="flex flex-col items-center">
|
|
<div className="p-4 bg-white border border-gray-200 rounded-xl">
|
|
{qrCodeUrl ? (
|
|
<img src={qrCodeUrl} alt="QR Code" className="w-[200px] h-[200px]" />
|
|
) : (
|
|
<div className="w-[200px] h-[200px] flex items-center justify-center">
|
|
<div className="w-8 h-8 border-2 border-purple-500 border-t-transparent rounded-full animate-spin" />
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
<p className="mt-4 text-center text-sm text-gray-600">
|
|
Scannen Sie den Code mit Ihrem Handy,<br />
|
|
um Dokumente hochzuladen.
|
|
</p>
|
|
|
|
<div className="mt-4 w-full">
|
|
<p className="text-xs text-gray-400 mb-2">Oder Link teilen:</p>
|
|
<div className="flex gap-2">
|
|
<input
|
|
type="text"
|
|
value={uploadUrl}
|
|
readOnly
|
|
className="flex-1 px-3 py-2 text-sm border border-gray-200 rounded-lg bg-gray-50"
|
|
/>
|
|
<button
|
|
onClick={copyToClipboard}
|
|
className="px-4 py-2 text-sm bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors"
|
|
>
|
|
Kopieren
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="mt-4 p-3 bg-amber-50 border border-amber-200 rounded-lg w-full">
|
|
<p className="text-xs text-amber-800">
|
|
<strong>Hinweis:</strong> Ihr Handy muss im gleichen Netzwerk sein.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|