Files

161 lines
5.9 KiB
TypeScript
Raw Permalink Normal View History

'use client';
import { useState, useCallback } from 'react';
import { Button } from '@/components/ui/Button';
import { comparePrices, type PriceCompareResponse, type ComparableListing } from '@/lib/retouch';
interface PriceComparisonProps {
vehicleId?: string;
}
export function PriceComparison({ vehicleId }: PriceComparisonProps) {
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const [data, setData] = useState<PriceCompareResponse | null>(null);
const [inputVehicleId, setInputVehicleId] = useState(vehicleId || '');
const handleCompare = useCallback(async () => {
const vid = inputVehicleId.trim();
if (!vid) {
setError('Please enter a vehicle ID');
return;
}
setLoading(true);
setError(null);
try {
const result = await comparePrices(vid);
setData(result);
} catch (err: unknown) {
const apiErr = err as { error?: { message?: string } };
setError(apiErr?.error?.message || 'Price comparison failed');
setData(null);
} finally {
setLoading(false);
}
}, [inputVehicleId]);
const formatPrice = (price: number) => {
return new Intl.NumberFormat('de-DE', {
style: 'currency',
currency: 'EUR',
maximumFractionDigits: 0,
}).format(price);
};
return (
<div data-testid="price-comparison" className="space-y-4">
<div className="flex gap-2 items-end">
<div className="flex-1">
<label className="block text-sm font-medium text-text mb-1">
Vehicle ID
</label>
<input
type="text"
value={inputVehicleId}
onChange={(e) => setInputVehicleId(e.target.value)}
placeholder="Enter vehicle UUID"
className="w-full px-3 py-2 border border-border rounded-lg text-text focus:outline-none focus:ring-2 focus:ring-primary"
data-testid="price-compare-vehicle-input"
/>
</div>
<Button
onClick={handleCompare}
loading={loading}
data-testid="price-compare-button"
>
Compare Prices
</Button>
</div>
{error && (
<div data-testid="price-compare-error" className="p-4 bg-error/10 text-error rounded-lg">
{error}
</div>
)}
{loading && (
<div data-testid="price-compare-loading" className="text-center text-text-muted py-4">
Searching comparable listings...
</div>
)}
{data && !loading && (
<div data-testid="price-compare-results" className="space-y-4">
{/* Summary */}
<div className="flex items-center justify-between p-4 bg-primary/5 rounded-lg">
<div>
<p className="text-sm text-text-muted">Comparable Listings</p>
<p className="text-2xl font-bold text-text">{data.listing_count}</p>
</div>
<div className="text-right">
<p className="text-sm text-text-muted">Average Price</p>
<p className="text-2xl font-bold text-primary">
{data.average_price !== null ? formatPrice(data.average_price) : 'N/A'}
</p>
</div>
</div>
{/* Listings table */}
{data.comparable_listings.length > 0 ? (
<div className="overflow-x-auto">
<table className="w-full text-sm border border-border rounded-lg">
<thead className="bg-secondary/10">
<tr>
<th className="px-4 py-2 text-left text-text font-medium">Title</th>
<th className="px-4 py-2 text-right text-text font-medium">Price</th>
<th className="px-4 py-2 text-right text-text font-medium">Mileage</th>
<th className="px-4 py-2 text-left text-text font-medium">Location</th>
<th className="px-4 py-2 text-left text-text font-medium">Source</th>
</tr>
</thead>
<tbody>
{data.comparable_listings.map((listing: ComparableListing, idx: number) => (
<tr
key={idx}
className="border-t border-border hover:bg-secondary/5"
data-testid={`price-compare-row-${idx}`}
>
<td className="px-4 py-2 text-text">
{listing.url ? (
<a
href={listing.url}
target="_blank"
rel="noopener noreferrer"
className="text-primary hover:underline"
>
{listing.title}
</a>
) : (
listing.title
)}
</td>
<td className="px-4 py-2 text-right text-text font-medium">
{formatPrice(listing.price)}
</td>
<td className="px-4 py-2 text-right text-text-muted">
{listing.mileage_km !== null && listing.mileage_km !== undefined
? `${listing.mileage_km.toLocaleString('de-DE')} km`
: '-'}
</td>
<td className="px-4 py-2 text-text-muted">
{listing.location || '-'}
</td>
<td className="px-4 py-2 text-text-muted">
{listing.source}
</td>
</tr>
))}
</tbody>
</table>
</div>
) : (
<div data-testid="price-compare-empty" className="text-center text-text-muted py-8">
No comparable listings found.
</div>
)}
</div>
)}
</div>
);
}