219 lines
7.2 KiB
TypeScript
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>
|
|
);
|
|
}
|