← 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>
  );
}