341d0c6f38
Backend (ruff): - F821: Add TYPE_CHECKING imports for Vehicle, Contact, File in models (file.py, retouch.py, sale.py, vehicle.py) - E741: Rename ambiguous variable to / (copilot_service.py, price_compare_service.py, openrouter.py) - F841: Remove unused variable in sale_service.py Frontend (ESLint): - react/no-unescaped-entities: Escape quotes in ContractPreview.tsx - @next/next/no-img-element: Replace <img> with <Image> from next/image (FileGallery.tsx, FileList.tsx, FilePreview.tsx, BeforeAfterSlider.tsx) Tests: 392 backend passed, 112 frontend passed, next build successful
77 lines
2.4 KiB
TypeScript
77 lines
2.4 KiB
TypeScript
'use client';
|
|
|
|
import { useState } from 'react';
|
|
import { Button } from '@/components/ui/Button';
|
|
import { getContractDownloadUrl, regenerateContract } from '@/lib/sales';
|
|
|
|
interface ContractPreviewProps {
|
|
saleId: string;
|
|
contractPdfPath?: string | null;
|
|
}
|
|
|
|
export function ContractPreview({ saleId, contractPdfPath }: ContractPreviewProps) {
|
|
const [regenerating, setRegenerating] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
const [pdfPath, setPdfPath] = useState<string | null>(contractPdfPath || null);
|
|
|
|
const handleRegenerate = async () => {
|
|
setRegenerating(true);
|
|
setError(null);
|
|
try {
|
|
const result = await regenerateContract(saleId);
|
|
setPdfPath(result.contract_pdf_path);
|
|
} catch (err: unknown) {
|
|
const apiErr = err as { error?: { message?: string } };
|
|
setError(apiErr?.error?.message || 'Failed to regenerate contract');
|
|
} finally {
|
|
setRegenerating(false);
|
|
}
|
|
};
|
|
|
|
const downloadUrl = getContractDownloadUrl(saleId);
|
|
|
|
return (
|
|
<div className="space-y-4" data-testid="contract-preview">
|
|
<div className="flex items-center justify-between">
|
|
<h2 className="text-xl font-bold">Vertrags-PDF</h2>
|
|
<div className="flex gap-2">
|
|
<Button
|
|
onClick={handleRegenerate}
|
|
disabled={regenerating}
|
|
data-testid="contract-regenerate-btn"
|
|
>
|
|
{regenerating ? 'Wird erstellt...' : 'Vertrag neu generieren'}
|
|
</Button>
|
|
{pdfPath && (
|
|
<a href={downloadUrl} target="_blank" rel="noopener noreferrer" data-testid="contract-download-link">
|
|
<Button>Herunterladen</Button>
|
|
</a>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
{error && (
|
|
<div className="bg-red-50 text-red-600 p-3 rounded" data-testid="contract-error">
|
|
{error}
|
|
</div>
|
|
)}
|
|
|
|
{pdfPath ? (
|
|
<iframe
|
|
src={downloadUrl}
|
|
className="w-full h-[600px] border rounded"
|
|
data-testid="contract-iframe"
|
|
title="Vertrags-PDF"
|
|
/>
|
|
) : (
|
|
<div className="bg-gray-50 p-8 text-center rounded" data-testid="contract-empty">
|
|
<p className="text-gray-500">Es wurde noch kein Vertrag generiert.</p>
|
|
<p className="text-sm text-gray-400 mt-2">
|
|
Klicken Sie auf "Vertrag neu generieren", um ein PDF zu erstellen.
|
|
</p>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|