Files
Atlas/components/ContractSection.tsx
2025-11-12 20:21:32 +01:00

219 lines
7.2 KiB
TypeScript

'use client';
import { useState } from 'react';
import { FiFileText, FiDownload, FiMail, FiUpload, FiCheck, FiClock } from 'react-icons/fi';
import { formatDateTime } from '@/lib/date-utils';
interface ContractSectionProps {
booking: any;
onRefresh: () => void;
}
export default function ContractSection({ booking, onRefresh }: ContractSectionProps) {
const [generating, setGenerating] = useState(false);
const [sending, setSending] = useState(false);
const [uploading, setUploading] = useState(false);
const handleGenerate = async () => {
setGenerating(true);
try {
const res = await fetch(`/api/bookings/${booking.id}/contract`, {
method: 'POST',
});
if (res.ok) {
alert('Vertrag erfolgreich erstellt!');
onRefresh();
} else {
alert('Fehler beim Erstellen des Vertrags');
}
} catch (error) {
alert('Fehler beim Erstellen des Vertrags');
} finally {
setGenerating(false);
}
};
const handleDownload = async () => {
window.open(`/api/bookings/${booking.id}/contract`, '_blank');
};
const handleSend = async () => {
setSending(true);
try {
const res = await fetch(`/api/bookings/${booking.id}/contract/send`, {
method: 'POST',
});
const data = await res.json();
if (res.ok) {
alert(`Vertrag versendet! Link: ${data.signUrl}`);
onRefresh();
} else {
alert('Fehler beim Versenden des Vertrags');
}
} catch (error) {
alert('Fehler beim Versenden des Vertrags');
} finally {
setSending(false);
}
};
const handleUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file) return;
setUploading(true);
const formData = new FormData();
formData.append('file', file);
try {
const res = await fetch(`/api/bookings/${booking.id}/contract/upload`, {
method: 'POST',
body: formData,
});
if (res.ok) {
alert('Vertrag erfolgreich hochgeladen!');
onRefresh();
} else {
alert('Fehler beim Hochladen');
}
} catch (error) {
alert('Fehler beim Hochladen');
} finally {
setUploading(false);
}
};
const getStatus = () => {
if (booking.contractSigned) {
return {
icon: <FiCheck className="text-green-600" />,
text: 'Unterschrieben',
color: 'bg-green-50 border-green-200',
};
}
if (booking.contractSentAt) {
return {
icon: <FiClock className="text-yellow-600" />,
text: 'Versendet',
color: 'bg-yellow-50 border-yellow-200',
};
}
if (booking.contractGenerated) {
return {
icon: <FiFileText className="text-blue-600" />,
text: 'Erstellt',
color: 'bg-blue-50 border-blue-200',
};
}
return {
icon: <FiClock className="text-gray-600" />,
text: 'Nicht erstellt',
color: 'bg-gray-50 border-gray-200',
};
};
const status = getStatus();
return (
<div className="bg-white rounded-xl shadow-sm border border-gray-200 p-6">
<div className="flex items-center justify-between mb-4">
<h3 className="text-xl font-bold text-gray-900">📋 Vertrag</h3>
<div className={`flex items-center gap-2 px-3 py-1 rounded-full border ${status.color}`}>
{status.icon}
<span className="text-sm font-semibold">{status.text}</span>
</div>
</div>
{booking.contractSigned && (
<div className="mb-4 p-4 bg-green-50 border border-green-200 rounded-lg">
<p className="text-green-800 font-semibold mb-2"> Vertrag unterschrieben</p>
<div className="text-sm text-green-700 space-y-1">
<p><span className="font-medium">Unterschrieben von:</span> {booking.contractSignedBy}</p>
<p><span className="font-medium">Datum:</span> {formatDateTime(booking.contractSignedAt)}</p>
<p><span className="font-medium">Art:</span> {booking.contractSignedOnline ? 'Online-Signatur' : 'Analog hochgeladen'}</p>
{booking.contractSignedIp && (
<p><span className="font-medium">IP-Adresse:</span> {booking.contractSignedIp}</p>
)}
</div>
</div>
)}
{booking.contractGenerated && !booking.contractSigned && (
<div className="mb-4 space-y-2 text-sm text-gray-600">
{booking.contractGeneratedAt && (
<p>Erstellt am: {formatDateTime(booking.contractGeneratedAt)}</p>
)}
{booking.contractSentAt && (
<p>Versendet am: {formatDateTime(booking.contractSentAt)}</p>
)}
</div>
)}
<div className="space-y-3">
{!booking.contractGenerated ? (
<button
onClick={handleGenerate}
disabled={generating}
className="w-full flex items-center justify-center gap-2 px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors disabled:bg-gray-400"
>
<FiFileText /> {generating ? 'Wird erstellt...' : 'Vertrag erstellen'}
</button>
) : (
<>
<button
onClick={handleDownload}
className="w-full flex items-center justify-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
>
<FiDownload /> PDF herunterladen
</button>
{!booking.contractSigned && (
<>
<button
onClick={handleSend}
disabled={sending}
className="w-full flex items-center justify-center gap-2 px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors disabled:bg-gray-400"
>
<FiMail /> {sending ? 'Wird versendet...' : 'Per E-Mail versenden'}
</button>
<div className="relative">
<input
type="file"
accept=".pdf,.jpg,.jpeg,.png"
onChange={handleUpload}
disabled={uploading}
className="absolute inset-0 w-full h-full opacity-0 cursor-pointer disabled:cursor-not-allowed"
/>
<button
disabled={uploading}
className="w-full flex items-center justify-center gap-2 px-4 py-2 bg-gray-600 text-white rounded-lg hover:bg-gray-700 transition-colors disabled:bg-gray-400"
>
<FiUpload /> {uploading ? 'Wird hochgeladen...' : 'Signiertes PDF hochladen'}
</button>
</div>
</>
)}
{booking.contractSigned && booking.contractPdfUrl && (
<a
href={booking.contractPdfUrl}
target="_blank"
rel="noopener noreferrer"
className="w-full flex items-center justify-center gap-2 px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors"
>
<FiDownload /> Signiertes PDF herunterladen
</a>
)}
</>
)}
</div>
</div>
);
}