← back to Handbag Auth Nextjs

src/components/BrandModelDropdowns.tsx

260 lines

'use client'

import { useState, useEffect, useRef } from 'react'
import { getAllBrands, getModelsByBrand, searchModels, HANDBAG_CATALOG } from '@/data/handbag-catalog'

interface BrandModelDropdownsProps {
  selectedBrand: string
  selectedModel: string
  onBrandChange: (brand: string) => void
  onModelChange: (model: string) => void
}

export function BrandModelDropdowns({
  selectedBrand,
  selectedModel,
  onBrandChange,
  onModelChange,
}: BrandModelDropdownsProps) {
  const [brandSearch, setBrandSearch] = useState('')
  const [modelSearch, setModelSearch] = useState('')
  const [showBrandDropdown, setShowBrandDropdown] = useState(false)
  const [showModelDropdown, setShowModelDropdown] = useState(false)
  const brandRef = useRef<HTMLDivElement>(null)
  const modelRef = useRef<HTMLDivElement>(null)

  const brands = getAllBrands()
  const models = selectedBrand ? getModelsByBrand(selectedBrand) : []

  // Filter brands based on search
  const filteredBrands = brandSearch
    ? brands.filter(b => b.toLowerCase().includes(brandSearch.toLowerCase()))
    : brands

  // Filter models based on search
  const filteredModels = modelSearch
    ? models.filter(m => m.toLowerCase().includes(modelSearch.toLowerCase()))
    : models

  // Close dropdowns when clicking outside
  useEffect(() => {
    const handleClickOutside = (event: MouseEvent) => {
      if (brandRef.current && !brandRef.current.contains(event.target as Node)) {
        setShowBrandDropdown(false)
      }
      if (modelRef.current && !modelRef.current.contains(event.target as Node)) {
        setShowModelDropdown(false)
      }
    }

    document.addEventListener('mousedown', handleClickOutside)
    return () => document.removeEventListener('mousedown', handleClickOutside)
  }, [])

  // Get brand tier badge
  const getBrandTierBadge = (brand: string) => {
    const brandData = HANDBAG_CATALOG.find(b => b.brand === brand)
    const tier = brandData?.tier || 'contemporary'

    const colors = {
      'ultra-luxury': 'bg-purple-100 text-purple-700',
      'luxury': 'bg-blue-100 text-blue-700',
      'contemporary': 'bg-gray-100 text-gray-700',
    }

    return (
      <span className={`ml-2 px-2 py-0.5 rounded text-xs font-medium ${colors[tier]}`}>
        {tier.replace('-', ' ')}
      </span>
    )
  }

  return (
    <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
      {/* Brand Dropdown */}
      <div ref={brandRef} className="relative">
        <label className="block text-sm font-medium text-gray-700 mb-1">
          Brand
        </label>
        <div className="relative">
          <input
            type="text"
            value={selectedBrand || brandSearch}
            onChange={(e) => {
              setBrandSearch(e.target.value)
              setShowBrandDropdown(true)
              if (!e.target.value) onBrandChange('')
            }}
            onFocus={() => setShowBrandDropdown(true)}
            placeholder="Select or search brand..."
            className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
            style={{ fontSize: '16px' }} // Prevent iOS zoom
          />
          <svg
            className="absolute right-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400 pointer-events-none"
            fill="none"
            stroke="currentColor"
            viewBox="0 0 24 24"
          >
            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
          </svg>
        </div>

        {/* Brand Dropdown Menu */}
        {showBrandDropdown && (
          <div className="absolute z-50 mt-1 w-full bg-white border border-gray-300 rounded-lg shadow-lg max-h-80 overflow-y-auto">
            {filteredBrands.length === 0 ? (
              <div className="px-4 py-3 text-sm text-gray-500">No brands found</div>
            ) : (
              <>
                {/* Clear option */}
                {selectedBrand && (
                  <button
                    onClick={() => {
                      onBrandChange('')
                      onModelChange('')
                      setBrandSearch('')
                      setShowBrandDropdown(false)
                    }}
                    className="w-full px-4 py-2 text-left text-sm text-red-600 hover:bg-red-50 border-b"
                  >
                    Clear selection
                  </button>
                )}

                {filteredBrands.map((brand) => (
                  <button
                    key={brand}
                    onClick={() => {
                      onBrandChange(brand)
                      onModelChange('') // Reset model when brand changes
                      setBrandSearch('')
                      setShowBrandDropdown(false)
                    }}
                    className={`w-full px-4 py-2 text-left text-sm hover:bg-blue-50 flex items-center justify-between ${
                      selectedBrand === brand ? 'bg-blue-100 font-semibold' : ''
                    }`}
                  >
                    <span>{brand}</span>
                    {getBrandTierBadge(brand)}
                  </button>
                ))}
              </>
            )}
          </div>
        )}
      </div>

      {/* Model Dropdown */}
      <div ref={modelRef} className="relative">
        <label className="block text-sm font-medium text-gray-700 mb-1">
          Model
        </label>
        <div className="relative">
          <input
            type="text"
            value={selectedModel || modelSearch}
            onChange={(e) => {
              setModelSearch(e.target.value)
              setShowModelDropdown(true)
              if (!e.target.value) onModelChange('')
            }}
            onFocus={() => setShowModelDropdown(true)}
            placeholder={selectedBrand ? 'Select or search model...' : 'Select a brand first'}
            disabled={!selectedBrand}
            className={`w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 ${
              !selectedBrand ? 'bg-gray-100 cursor-not-allowed' : ''
            }`}
            style={{ fontSize: '16px' }} // Prevent iOS zoom
          />
          <svg
            className="absolute right-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400 pointer-events-none"
            fill="none"
            stroke="currentColor"
            viewBox="0 0 24 24"
          >
            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
          </svg>
        </div>

        {/* Model Dropdown Menu */}
        {showModelDropdown && selectedBrand && (
          <div className="absolute z-50 mt-1 w-full bg-white border border-gray-300 rounded-lg shadow-lg max-h-80 overflow-y-auto">
            {filteredModels.length === 0 ? (
              <div className="px-4 py-3 text-sm text-gray-500">No models found</div>
            ) : (
              <>
                {/* Clear option */}
                {selectedModel && (
                  <button
                    onClick={() => {
                      onModelChange('')
                      setModelSearch('')
                      setShowModelDropdown(false)
                    }}
                    className="w-full px-4 py-2 text-left text-sm text-red-600 hover:bg-red-50 border-b"
                  >
                    Clear selection
                  </button>
                )}

                {/* Model count info */}
                <div className="px-4 py-2 text-xs text-gray-500 border-b bg-gray-50">
                  {filteredModels.length} models available for {selectedBrand}
                </div>

                {filteredModels.map((model) => (
                  <button
                    key={model}
                    onClick={() => {
                      onModelChange(model)
                      setModelSearch('')
                      setShowModelDropdown(false)
                    }}
                    className={`w-full px-4 py-2 text-left text-sm hover:bg-blue-50 ${
                      selectedModel === model ? 'bg-blue-100 font-semibold' : ''
                    }`}
                  >
                    {model}
                  </button>
                ))}
              </>
            )}
          </div>
        )}
      </div>

      {/* Selection Summary */}
      {(selectedBrand || selectedModel) && (
        <div className="md:col-span-2 mt-2">
          <div className="bg-blue-50 border border-blue-200 rounded-lg p-3 flex items-center justify-between">
            <div className="flex items-center gap-2 text-sm">
              <svg className="w-5 h-5 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
              </svg>
              <span className="text-blue-900">
                {selectedBrand && selectedModel
                  ? `Filtering: ${selectedBrand} ${selectedModel}`
                  : selectedBrand
                  ? `Showing all ${selectedBrand} bags`
                  : 'Filter active'}
              </span>
            </div>
            <button
              onClick={() => {
                onBrandChange('')
                onModelChange('')
                setBrandSearch('')
                setModelSearch('')
              }}
              className="text-blue-600 hover:text-blue-800 text-sm font-medium"
            >
              Clear filters
            </button>
          </div>
        </div>
      )}
    </div>
  )
}