← back to Wine Finder Next

components/WineCard.tsx

263 lines

'use client'

import { useState, useEffect } from 'react'
import Image from 'next/image'
import PriceChart from './PriceChart'

interface WineCardProps {
  wine: {
    name: string
    vintage?: string
    price: string
    rating?: number
    image?: string
    source: string
    url?: string
    badge?: 'new' | 'deal' | 'featured'
    availability?: string
    winery?: string
    region?: string
    country?: string
    type?: string
    varietal?: string
    alcohol?: string
    description?: string
    reviews?: number
    priceHistory?: {
      previousPrice?: string
      priceChange?: string
    }
  }
  onPriceCheck?: (wine: any) => void
}

export default function WineCard({ wine }: WineCardProps) {
  const [showChart, setShowChart] = useState(false)
  const [chartData, setChartData] = useState<any>(null)
  const [loadingChart, setLoadingChart] = useState(false)
  const badgeClass = wine.badge === 'new' ? 'wine-badge-new' :
                     wine.badge === 'deal' ? 'wine-badge-deal' :
                     'wine-badge-featured'

  const badgeText = wine.badge === 'new' ? '🆕 New Vintage' :
                    wine.badge === 'deal' ? '🔥 Hot Deal' :
                    '⭐ Featured'

  const isInStock = wine.availability?.toLowerCase().includes('stock')

  const loadPriceHistory = async () => {
    if (chartData || loadingChart) return

    setLoadingChart(true)
    try {
      const response = await fetch(
        `/api/price-history?wine=${encodeURIComponent(wine.name)}&vintage=${wine.vintage || ''}`
      )
      const data = await response.json()

      // Only set chart data if we have real historical data
      if (data.success && data.pricePoints && data.pricePoints.length > 0) {
        setChartData(data)
      } else {
        setChartData({
          success: false,
          error: data.error || 'No historical price data available for this wine yet',
          pricePoints: []
        })
      }
    } catch (error) {
      console.error('Failed to load price history:', error)
      setChartData({
        success: false,
        error: 'Failed to load price history',
        pricePoints: []
      })
    } finally {
      setLoadingChart(false)
    }
  }

  const toggleChart = () => {
    if (!showChart && !chartData) {
      loadPriceHistory()
    }
    setShowChart(!showChart)
  }

  return (
    <div className="wine-card group">
      <div className="relative h-72 bg-gradient-to-br from-purple-100 to-pink-100">
        {wine.image ? (
          <Image
            src={wine.image}
            alt={wine.name}
            fill
            className="object-contain p-4 group-hover:scale-110 transition-transform duration-300"
            sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
          />
        ) : (
          <div className="flex items-center justify-center h-full text-6xl">
            🍷
          </div>
        )}
        {wine.badge && (
          <div className="absolute top-4 right-4">
            <span className={badgeClass}>{badgeText}</span>
          </div>
        )}

        {/* Price Change Indicator */}
        {wine.priceHistory?.priceChange && (
          <div className="absolute bottom-4 left-4 bg-black/70 text-white px-3 py-1 rounded-full text-xs font-semibold">
            {wine.priceHistory.priceChange.startsWith('-') ? '📉' : '📈'} {wine.priceHistory.priceChange}
          </div>
        )}
      </div>

      <div className="p-5 space-y-3">
        {/* Wine Name */}
        <h3 className="font-bold text-lg text-gray-900 mb-1 line-clamp-2 group-hover:text-purple-700 transition-colors leading-tight">
          {wine.name}
        </h3>

        {/* Winery */}
        {wine.winery && (
          <p className="text-sm font-medium text-purple-600 flex items-center gap-1">
            🏛️ {wine.winery}
          </p>
        )}

        {/* Region & Country */}
        {(wine.region || wine.country) && (
          <p className="text-sm text-gray-600 flex items-center gap-1">
            📍 {wine.region}{wine.region && wine.country ? ', ' : ''}{wine.country}
          </p>
        )}

        {/* Vintage & Type */}
        <div className="flex items-center gap-2 text-sm">
          {wine.vintage && (
            <span className="bg-purple-100 text-purple-800 px-2 py-1 rounded-md font-semibold">
              🗓️ {wine.vintage}
            </span>
          )}
          {wine.type && (
            <span className="bg-pink-100 text-pink-800 px-2 py-1 rounded-md font-medium">
              {wine.type}
            </span>
          )}
        </div>

        {/* Varietal */}
        {wine.varietal && (
          <p className="text-sm text-gray-700 font-medium flex items-center gap-1">
            🍇 {wine.varietal}
          </p>
        )}

        {/* Alcohol Content */}
        {wine.alcohol && (
          <p className="text-xs text-gray-500">
            Alcohol: {wine.alcohol}
          </p>
        )}

        {/* Description */}
        {wine.description && (
          <p className="text-sm text-gray-600 line-clamp-3 italic border-l-2 border-purple-300 pl-3">
            "{wine.description}"
          </p>
        )}

        {/* Price & Rating Section */}
        <div className="pt-2 border-t border-gray-200">
          <div className="flex items-center justify-between mb-2">
            <div>
              <div className="text-3xl font-bold text-purple-700">
                ${wine.price}
              </div>
              {wine.priceHistory?.previousPrice && (
                <div className="text-xs text-gray-500 line-through">
                  ${wine.priceHistory.previousPrice}
                </div>
              )}
            </div>
            {wine.rating && (
              <div className="text-right">
                <div className="flex items-center gap-1 bg-yellow-50 px-3 py-2 rounded-lg border border-yellow-200">
                  <span className="text-yellow-500 text-lg">⭐</span>
                  <span className="text-lg font-bold text-gray-800">{wine.rating}</span>
                </div>
                {wine.reviews && (
                  <div className="text-xs text-gray-500 mt-1">
                    {wine.reviews.toLocaleString()} reviews
                  </div>
                )}
              </div>
            )}
          </div>
        </div>

        {/* Source & Availability */}
        <div className="flex items-center justify-between text-sm pt-2">
          <div className="flex items-center gap-1">
            <span className="text-xs bg-gray-100 text-gray-700 px-2 py-1 rounded-full font-medium">
              📦 {wine.source}
            </span>
          </div>
          {wine.availability && (
            <span className={`text-xs font-semibold px-2 py-1 rounded-full ${isInStock ? 'bg-green-100 text-green-700' : 'bg-gray-100 text-gray-600'}`}>
              {isInStock ? '✓' : '○'} {wine.availability}
            </span>
          )}
        </div>

        {/* Price History Chart Toggle */}
        <button
          onClick={toggleChart}
          className="mt-3 w-full py-2 px-4 bg-gradient-to-r from-blue-500 to-indigo-500 text-white rounded-lg font-semibold text-sm hover:from-blue-600 hover:to-indigo-600 transition-all duration-300 flex items-center justify-center gap-2"
        >
          {showChart ? '📊 Hide' : '📈 Show'} Price History
          {loadingChart && <div className="animate-spin rounded-full h-4 w-4 border-2 border-white border-t-transparent"></div>}
        </button>

        {/* Price Chart */}
        {showChart && chartData && (
          <div className="mt-3 animate-fadeIn">
            {chartData.success && chartData.pricePoints && chartData.pricePoints.length > 0 ? (
              <PriceChart
                data={chartData.pricePoints}
                currentPrice={parseFloat(wine.price)}
                trend={chartData.stats?.trend || 'stable'}
                dealScore={chartData.stats?.dealScore || 50}
              />
            ) : (
              <div className="bg-gray-100 border border-gray-200 rounded-lg p-4 text-center">
                <div className="text-gray-600 mb-2">📊 No Price History Available</div>
                <div className="text-sm text-gray-500">
                  {chartData.error || 'Historical price data not yet available for this wine.'}
                </div>
                <div className="text-xs text-gray-400 mt-2">
                  Price tracking will begin once this wine is searched.
                </div>
              </div>
            )}
          </div>
        )}

        {/* CTA Button */}
        {wine.url && (
          <a
            href={wine.url}
            target="_blank"
            rel="noopener noreferrer"
            className="mt-4 block w-full text-center bg-gradient-to-r from-purple-600 to-pink-600 text-white py-3 px-4 rounded-lg font-bold hover:from-purple-700 hover:to-pink-700 transition-all duration-300 hover:shadow-xl transform hover:scale-105"
          >
            🛒 View Full Details →
          </a>
        )}
      </div>
    </div>
  )
}