magricambi/src/components/PriceSearchPanel.tsx
AV77web 751b7f24d7
All checks were successful
Deploy to VPS / build (push) Successful in 41s
Deploy to VPS / deploy (push) Successful in 31s
modifiche a workflow n8n
2026-06-07 18:34:46 +02:00

162 lines
5.7 KiB
TypeScript

"use client";
import type { PriceOffer, PriceSearchResponse } from "@/src/types/priceSearch";
const CONFIDENCE_LABELS: Record<PriceOffer["confidence"], string> = {
high: "Alta",
medium: "Media",
low: "Bassa",
};
const CONFIDENCE_STYLES: Record<PriceOffer["confidence"], string> = {
high: "bg-green-500/15 text-green-400 border-green-500/30",
medium: "bg-yellow-500/15 text-yellow-400 border-yellow-500/30",
low: "bg-zinc-500/15 text-zinc-400 border-zinc-500/30",
};
function formatPrice(price: number | null, currency: string) {
if (price === null) return "N/D";
return new Intl.NumberFormat("it-IT", {
style: "currency",
currency,
}).format(price);
}
interface PriceSearchPanelProps {
isLoading: boolean;
error: string | null;
result: PriceSearchResponse | null;
onApplyPrice: (price: number) => void;
onCancel: () => void;
}
export default function PriceSearchPanel({
isLoading,
error,
result,
onApplyPrice,
onCancel,
}: PriceSearchPanelProps) {
if (!isLoading && !error && !result) return null;
return (
<div className="p-4 rounded-lg bg-blue-500/5 border border-blue-500/30 space-y-3">
<div className="flex items-center justify-between gap-3">
<h3 className="text-sm font-semibold text-blue-400 flex items-center gap-2">
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
/>
</svg>
Ricerca prezzi online
</h3>
{isLoading && (
<button
type="button"
onClick={onCancel}
className="text-xs text-zinc-400 hover:text-white transition-colors"
>
Annulla
</button>
)}
</div>
{isLoading && (
<div className="flex items-center gap-3 text-sm text-zinc-400">
<svg className="w-4 h-4 animate-spin text-blue-400" viewBox="0 0 24 24">
<circle
className="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="4"
fill="none"
/>
<path
className="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
/>
</svg>
Ricerca in corso può richiedere fino a 30 secondi
</div>
)}
{error && (
<div className="p-3 rounded-lg bg-red-500/10 border border-red-500/50 text-red-400 text-sm">
{error}
</div>
)}
{result && (
<>
<p className="text-xs text-zinc-500">
Query: <span className="text-zinc-400">{result.query}</span>
</p>
{result.offers.length === 0 ? (
<p className="text-sm text-zinc-400">Nessuna offerta trovata.</p>
) : (
<ul className="space-y-2 max-h-48 overflow-y-auto">
{result.offers.map((offer, index) => (
<li
key={`${offer.vendor}-${offer.url}-${index}`}
className="p-3 rounded-lg bg-zinc-800/80 border border-zinc-700"
>
<div className="flex items-start justify-between gap-3">
<div className="min-w-0 flex-1">
<div className="flex items-center gap-2 flex-wrap">
<span className="text-sm font-medium text-white truncate">
{offer.vendor}
</span>
<span
className={`text-[10px] px-1.5 py-0.5 rounded border ${CONFIDENCE_STYLES[offer.confidence]}`}
>
{CONFIDENCE_LABELS[offer.confidence]}
</span>
</div>
<p className="text-xs text-zinc-400 mt-0.5 line-clamp-2">{offer.title}</p>
{offer.shippingNote && (
<p className="text-[11px] text-zinc-500 mt-1">{offer.shippingNote}</p>
)}
</div>
<div className="flex flex-col items-end gap-2 flex-shrink-0">
<span className="text-sm font-semibold text-green-400">
{formatPrice(offer.price, offer.currency)}
</span>
<div className="flex items-center gap-2">
<a
href={offer.url}
target="_blank"
rel="noopener noreferrer"
className="text-[11px] text-blue-400 hover:text-blue-300 transition-colors"
>
Apri
</a>
{offer.price !== null && (
<button
type="button"
onClick={() => onApplyPrice(offer.price as number)}
className="text-[11px] px-2 py-1 rounded bg-blue-600 text-white hover:bg-blue-500 transition-colors"
>
Applica
</button>
)}
</div>
</div>
</div>
</li>
))}
</ul>
)}
<p className="text-[11px] text-zinc-500 leading-relaxed">{result.disclaimer}</p>
</>
)}
</div>
);
}