← back to Wine Finder Next

components/mobile/PriceComparisonSheet.tsx

179 lines

'use client'

import { useState, useEffect } from 'react';
import { Wine } from '@/lib/types/wine';
import { getEnabledPartners } from '@/lib/affiliates/partners';
import { buildAffiliateUrl } from '@/lib/affiliates/urlBuilder';
import { trackAffiliateClick } from '@/lib/affiliates/tracker';
import AffiliateButton from './AffiliateButton';

interface PriceComparisonSheetProps {
  wine: Wine;
  isOpen: boolean;
  onClose: () => void;
}

export default function PriceComparisonSheet({
  wine,
  isOpen,
  onClose
}: PriceComparisonSheetProps) {
  const [prices, setPrices] = useState<any[]>([]);
  const [loading, setLoading] = useState(false);
  const partners = getEnabledPartners().slice(0, 5); // Top 5 partners

  useEffect(() => {
    if (isOpen) {
      loadPrices();
    }
  }, [isOpen]);

  const loadPrices = async () => {
    setLoading(true);
    try {
      // In a real app, fetch prices from multiple sources
      // For now, show the wine's source and simulate others
      const mockPrices = partners.map((partner, index) => ({
        partnerId: partner.id,
        partnerName: partner.name,
        price: parseFloat(wine.price.toString()) + (index * 2.99),
        inStock: index < 3,
        shipping: index === 0 ? 'Free' : '$9.99'
      }));

      setPrices(mockPrices);
    } catch (error) {
      console.error('Failed to load prices:', error);
    } finally {
      setLoading(false);
    }
  };

  if (!isOpen) return null;

  const lowestPrice = Math.min(...prices.map(p => p.price));

  return (
    <>
      {/* Backdrop */}
      <div
        className="fixed inset-0 bg-black/50 z-40 animate-fadeIn"
        onClick={onClose}
      />

      {/* Bottom Sheet */}
      <div
        className="fixed inset-x-0 bottom-0 z-50 bg-white rounded-t-3xl shadow-2xl max-h-[80vh] overflow-hidden animate-slideUp"
        style={{
          animation: 'slideUp 0.3s ease-out'
        }}
      >
        {/* Handle */}
        <div className="flex justify-center pt-3 pb-2">
          <div className="w-12 h-1 bg-gray-300 rounded-full" />
        </div>

        {/* Header */}
        <div className="px-6 py-4 border-b border-gray-200">
          <h3 className="text-xl font-bold text-gray-900 mb-1">
            Compare Prices
          </h3>
          <p className="text-sm text-gray-600 line-clamp-2">
            {wine.name}
          </p>
        </div>

        {/* Price List */}
        <div className="overflow-y-auto max-h-[60vh] pb-6">
          {loading ? (
            <div className="flex justify-center items-center py-12">
              <div className="animate-spin rounded-full h-12 w-12 border-4 border-purple-600 border-t-transparent"></div>
            </div>
          ) : (
            <div className="space-y-3 px-6 pt-4">
              {prices.map((price, index) => (
                <div
                  key={price.partnerId}
                  className={`
                    p-4 rounded-xl border-2 transition-all
                    ${price.price === lowestPrice
                      ? 'border-green-500 bg-green-50'
                      : 'border-gray-200 bg-white'
                    }
                  `}
                >
                  <div className="flex items-start justify-between mb-3">
                    <div className="flex-1">
                      <div className="flex items-center gap-2 mb-1">
                        <h4 className="font-bold text-gray-900">
                          {price.partnerName}
                        </h4>
                        {price.price === lowestPrice && (
                          <span className="bg-green-500 text-white text-xs px-2 py-1 rounded-full font-bold">
                            Best Deal
                          </span>
                        )}
                      </div>
                      <div className="flex items-center gap-2 text-sm">
                        <span className={`
                          ${price.inStock ? 'text-green-600' : 'text-red-600'}
                          font-medium
                        `}>
                          {price.inStock ? '✓ In Stock' : '○ Out of Stock'}
                        </span>
                        <span className="text-gray-500">•</span>
                        <span className="text-gray-600">
                          Shipping: {price.shipping}
                        </span>
                      </div>
                    </div>
                    <div className="text-right">
                      <div className="text-2xl font-bold text-purple-700">
                        ${price.price.toFixed(2)}
                      </div>
                    </div>
                  </div>

                  <AffiliateButton
                    wine={wine}
                    partnerId={price.partnerId}
                    partnerName={price.partnerName}
                    variant={price.price === lowestPrice ? 'primary' : 'outline'}
                    fullWidth
                  />
                </div>
              ))}
            </div>
          )}
        </div>

        {/* Footer */}
        <div className="px-6 py-4 border-t border-gray-200 bg-gray-50">
          <p className="text-xs text-gray-500 text-center">
            Affiliate Disclosure: We may earn a commission from purchases made through these links.
          </p>
        </div>
      </div>

      <style jsx>{`
        @keyframes slideUp {
          from {
            transform: translateY(100%);
          }
          to {
            transform: translateY(0);
          }
        }
        @keyframes fadeIn {
          from {
            opacity: 0;
          }
          to {
            opacity: 1;
          }
        }
      `}</style>
    </>
  );
}