← back to Wine Finder Next
app/wines/[id]/page.tsx
161 lines
// app/wines/[id]/page.tsx
import { getWineById, getWinePriceHistory } from '@/lib/wines';
import Link from 'next/link';
type Props = { params: { id: string } };
export default async function WineDetailPage({ params }: Props) {
const id = Number(params.id);
const wine: any = getWineById(id);
if (!wine) {
return (
<div className="max-w-3xl mx-auto p-6">
<h1 className="text-2xl font-bold text-red-600">Wine not found</h1>
<Link href="/wines" className="text-purple-600 hover:underline mt-4 inline-block">
← Back to wines
</Link>
</div>
);
}
const history = getWinePriceHistory(id, 365);
return (
<main className="max-w-4xl mx-auto p-6 space-y-6">
<Link href="/wines" className="text-purple-600 hover:underline">
← Back to wines
</Link>
<div className="bg-white rounded-lg shadow-lg p-8">
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
<div>
{wine.image_url && (
<img
src={wine.image_url}
alt={wine.name}
className="w-full max-w-sm mx-auto h-96 object-cover rounded-lg shadow"
/>
)}
</div>
<div className="space-y-4">
<div>
<h1 className="text-3xl font-bold text-gray-900 mb-2">{wine.name}</h1>
<div className="grid grid-cols-2 gap-4 text-gray-600">
<div><span className="font-medium">Varietal:</span> {wine.varietal || 'N/A'}</div>
<div><span className="font-medium">Vintage:</span> {wine.vintage || 'NV'}</div>
<div><span className="font-medium">Region:</span> {wine.region || 'N/A'}</div>
<div><span className="font-medium">Country:</span> {wine.country || 'N/A'}</div>
{wine.alc_percent && (
<div><span className="font-medium">Alcohol:</span> {wine.alc_percent}%</div>
)}
</div>
</div>
{wine.latestPrice && (
<div className="bg-green-50 p-4 rounded-lg">
<div className="text-3xl font-bold text-green-700">
${wine.latestPrice.price.toLocaleString()}
</div>
<div className="text-sm text-green-600 mt-1">
via {wine.latestPrice.vendor} • {new Date(wine.latestPrice.collected_at).toLocaleDateString()}
</div>
</div>
)}
{wine.critic_scores && (
<div className="space-y-2">
<h3 className="font-semibold text-gray-900">Critic Scores</h3>
<div className="flex gap-3">
{wine.critic_scores.ws && (
<div className="bg-yellow-100 px-3 py-2 rounded-lg">
<div className="font-bold text-yellow-800">WS {wine.critic_scores.ws}</div>
</div>
)}
{wine.critic_scores.we && (
<div className="bg-red-100 px-3 py-2 rounded-lg">
<div className="font-bold text-red-800">WE {wine.critic_scores.we}</div>
</div>
)}
{wine.critic_scores.js && (
<div className="bg-blue-100 px-3 py-2 rounded-lg">
<div className="font-bold text-blue-800">JS {wine.critic_scores.js}</div>
</div>
)}
</div>
</div>
)}
{wine.ratingInfo?.avg_rating && (
<div className="bg-gray-50 p-4 rounded-lg">
<h3 className="font-semibold text-gray-900 mb-2">User Ratings</h3>
<div className="text-2xl font-bold text-purple-600">
⭐ {Number(wine.ratingInfo.avg_rating).toFixed(1)}
</div>
<div className="text-sm text-gray-600">
Based on {wine.ratingInfo.count_rating} rating{wine.ratingInfo.count_rating !== 1 ? 's' : ''}
</div>
</div>
)}
{wine.tasting_notes && (
<div>
<h3 className="font-semibold text-gray-900 mb-2">Tasting Notes</h3>
<p className="text-gray-700">{wine.tasting_notes}</p>
</div>
)}
</div>
</div>
{/* Price History */}
<div className="mt-8 pt-8 border-t">
<h2 className="text-xl font-bold mb-4">Price History (Last Year)</h2>
{history.length === 0 ? (
<p className="text-gray-500">No price history available</p>
) : (
<div className="bg-gray-50 rounded-lg p-4 max-h-64 overflow-y-auto">
<div className="grid grid-cols-2 gap-4 text-sm">
{history.map((p, i) => (
<div key={i} className="flex justify-between border-b pb-2">
<span className="text-gray-600">{new Date(p.collected_at).toLocaleDateString()}</span>
<span className="font-medium">${p.price.toLocaleString()}</span>
</div>
))}
</div>
</div>
)}
</div>
{/* Buy Links */}
<div className="mt-8 pt-8 border-t">
<h2 className="text-xl font-bold mb-4">Where to Buy</h2>
<div className="flex flex-wrap gap-3">
{wine.winecom_id && (
<a
href={`/api/aff/link?vendor=winecom&wineId=${wine.id}&productId=${wine.winecom_id}`}
className="inline-flex items-center px-6 py-3 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition"
>
View on Wine.com
</a>
)}
{wine.vivino_id && (
<a
href={`/api/aff/link?vendor=vivino&wineId=${wine.id}&productId=${wine.vivino_id}`}
className="inline-flex items-center px-6 py-3 bg-red-600 text-white rounded-lg hover:bg-red-700 transition"
>
View on Vivino
</a>
)}
{wine.winebid_id && (
<a
href={`/api/aff/link?vendor=winebid&wineId=${wine.id}&productId=${wine.winebid_id}`}
className="inline-flex items-center px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition"
>
View on WineBid
</a>
)}
</div>
</div>
</div>
</main>
);
}