← back to Wine Finder Next

app/mobile-page.tsx

296 lines

'use client'

import { useState, useEffect } from 'react';
import { Wine } from '@/lib/types/wine';
import MobileWineCard from '@/components/mobile/MobileWineCard';
import MobileSearchBar from '@/components/mobile/MobileSearchBar';
import FilterSheet, { FilterState } from '@/components/mobile/FilterSheet';

export default function MobilePage() {
  const [wines, setWines] = useState<Wine[]>([]);
  const [filteredWines, setFilteredWines] = useState<Wine[]>([]);
  const [loading, setLoading] = useState(false);
  const [searching, setSearching] = useState(false);
  const [showFilters, setShowFilters] = useState(false);
  const [filters, setFilters] = useState<FilterState>({});
  const [searchQuery, setSearchQuery] = useState('');
  const [activeTab, setActiveTab] = useState<'search' | 'featured' | 'deals'>('featured');

  // Load featured wines on mount
  useEffect(() => {
    loadFeaturedWines();
  }, []);

  // Apply filters when they change
  useEffect(() => {
    applyFilters();
  }, [wines, filters]);

  const loadFeaturedWines = async () => {
    try {
      setLoading(true);
      const response = await fetch('/api/featured');
      const data = await response.json();

      const allWines = [
        ...(data.featured || []),
        ...(data.newVintages || []),
        ...(data.deals || [])
      ];

      setWines(allWines);
    } catch (error) {
      console.error('Error loading featured wines:', error);
    } finally {
      setLoading(false);
    }
  };

  const handleSearch = async (query: string) => {
    setSearchQuery(query);
    setSearching(true);
    setActiveTab('search');

    try {
      const response = await fetch(`/api/search?q=${encodeURIComponent(query)}`);
      const data = await response.json();

      setWines(data.wines || []);
    } catch (error) {
      console.error('Search error:', error);
    } finally {
      setSearching(false);
    }
  };

  const applyFilters = () => {
    let filtered = [...wines];

    // Price filter
    if (filters.priceMin !== undefined) {
      filtered = filtered.filter(w => {
        const price = typeof w.price === 'string' ? parseFloat(w.price) : w.price;
        return price >= filters.priceMin!;
      });
    }
    if (filters.priceMax !== undefined) {
      filtered = filtered.filter(w => {
        const price = typeof w.price === 'string' ? parseFloat(w.price) : w.price;
        return price <= filters.priceMax!;
      });
    }

    // Rating filter
    if (filters.ratingMin !== undefined) {
      filtered = filtered.filter(w => w.rating && w.rating >= filters.ratingMin!);
    }

    // Type filter
    if (filters.type && filters.type.length > 0) {
      filtered = filtered.filter(w => w.type && filters.type!.includes(w.type));
    }

    // Source filter
    if (filters.sources && filters.sources.length > 0) {
      filtered = filtered.filter(w => filters.sources!.includes(w.source));
    }

    // In stock filter
    if (filters.inStockOnly) {
      filtered = filtered.filter(w =>
        w.availability?.toLowerCase().includes('stock')
      );
    }

    // Sort
    if (filters.sortBy) {
      filtered.sort((a, b) => {
        const priceA = typeof a.price === 'string' ? parseFloat(a.price) : a.price;
        const priceB = typeof b.price === 'string' ? parseFloat(b.price) : b.price;

        switch (filters.sortBy) {
          case 'price-asc':
            return priceA - priceB;
          case 'price-desc':
            return priceB - priceA;
          case 'rating':
            return (b.rating || 0) - (a.rating || 0);
          case 'name':
            return a.name.localeCompare(b.name);
          default:
            return 0;
        }
      });
    }

    setFilteredWines(filtered);
  };

  const handlePullToRefresh = () => {
    if (activeTab === 'featured' || activeTab === 'deals') {
      loadFeaturedWines();
    } else if (searchQuery) {
      handleSearch(searchQuery);
    }
  };

  const displayWines = filteredWines.length > 0 ? filteredWines : wines;

  return (
    <div className="min-h-screen bg-gray-50">
      {/* Header */}
      <div className="sticky top-0 z-30 bg-gradient-to-r from-purple-900 via-burgundy-800 to-pink-900 text-white shadow-xl">
        <div className="px-4 py-4">
          {/* Logo & Title */}
          <div className="mb-4">
            <h1 className="text-2xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-yellow-200 via-pink-200 to-purple-200">
              Red Thunder Wine
            </h1>
            <p className="text-sm text-purple-200">
              500K+ wines • Best prices
            </p>
          </div>

          {/* Search Bar */}
          <MobileSearchBar
            onSearch={handleSearch}
            placeholder="Search wines, wineries, regions..."
          />

          {/* Filter Button */}
          <div className="flex gap-2 mt-3">
            <button
              onClick={() => setShowFilters(true)}
              className="flex-1 py-3 px-4 bg-white/10 backdrop-blur rounded-xl font-bold hover:bg-white/20 transition-all flex items-center justify-center gap-2"
            >
              <span>🔧 Filters</span>
              {Object.keys(filters).length > 0 && (
                <span className="bg-pink-500 text-white text-xs px-2 py-1 rounded-full">
                  {Object.keys(filters).length}
                </span>
              )}
            </button>
          </div>
        </div>

        {/* Tabs */}
        <div className="flex border-t border-white/10">
          <button
            onClick={() => {
              setActiveTab('featured');
              loadFeaturedWines();
            }}
            className={`flex-1 py-3 font-bold text-sm transition-all ${
              activeTab === 'featured'
                ? 'bg-white/20 text-white border-b-2 border-yellow-300'
                : 'text-purple-200'
            }`}
          >
            ⭐ Featured
          </button>
          <button
            onClick={() => setActiveTab('search')}
            className={`flex-1 py-3 font-bold text-sm transition-all ${
              activeTab === 'search'
                ? 'bg-white/20 text-white border-b-2 border-yellow-300'
                : 'text-purple-200'
            }`}
          >
            🔍 Search
          </button>
          <button
            onClick={() => {
              setActiveTab('deals');
              loadFeaturedWines();
            }}
            className={`flex-1 py-3 font-bold text-sm transition-all ${
              activeTab === 'deals'
                ? 'bg-white/20 text-white border-b-2 border-yellow-300'
                : 'text-purple-200'
            }`}
          >
            🔥 Deals
          </button>
        </div>
      </div>

      {/* Content */}
      <div className="px-4 py-4">
        {/* Results Count */}
        {displayWines.length > 0 && (
          <div className="mb-4 flex items-center justify-between">
            <p className="text-sm text-gray-600 font-medium">
              {displayWines.length} wine{displayWines.length !== 1 ? 's' : ''} found
            </p>
            {searchQuery && (
              <button
                onClick={() => {
                  setSearchQuery('');
                  setActiveTab('featured');
                  loadFeaturedWines();
                }}
                className="text-purple-600 text-sm font-bold"
              >
                Clear Search
              </button>
            )}
          </div>
        )}

        {/* Loading State */}
        {(loading || searching) && (
          <div className="text-center py-20">
            <div className="inline-block animate-spin rounded-full h-16 w-16 border-4 border-purple-600 border-t-transparent"></div>
            <p className="mt-4 text-gray-600 font-medium">
              {searching ? 'Searching...' : 'Loading wines...'}
            </p>
          </div>
        )}

        {/* Wine Grid */}
        {!loading && !searching && displayWines.length > 0 && (
          <div className="grid grid-cols-1 gap-4 pb-20">
            {displayWines.map((wine, index) => (
              <MobileWineCard key={index} wine={wine} />
            ))}
          </div>
        )}

        {/* Empty State */}
        {!loading && !searching && displayWines.length === 0 && (
          <div className="text-center py-20">
            <div className="text-6xl mb-4">🍷</div>
            <h3 className="text-xl font-bold text-gray-900 mb-2">
              No wines found
            </h3>
            <p className="text-gray-600 mb-6">
              Try adjusting your search or filters
            </p>
            <button
              onClick={handlePullToRefresh}
              className="px-6 py-3 bg-gradient-to-r from-purple-600 to-pink-600 text-white rounded-xl font-bold hover:from-purple-700 hover:to-pink-700 transition-all"
            >
              Browse Featured Wines
            </button>
          </div>
        )}
      </div>

      {/* Filter Sheet */}
      <FilterSheet
        isOpen={showFilters}
        onClose={() => setShowFilters(false)}
        onApply={(newFilters) => setFilters(newFilters)}
        initialFilters={filters}
      />

      {/* Affiliate Disclosure Footer */}
      <div className="fixed bottom-0 inset-x-0 bg-white border-t border-gray-200 px-4 py-2 z-20">
        <p className="text-xs text-gray-500 text-center">
          Affiliate Disclosure: We may earn a commission from purchases made through our links.
        </p>
      </div>
    </div>
  );
}