'use client'; import { useState, useRef, useEffect, useCallback } from 'react'; import { useRouter, useSearchParams } from 'next/navigation'; import Image from 'next/image'; import { appConfig } from '../config/app'; import { SkinId } from '../types'; import { useLocalizedSkinName } from '../hooks/useLocalizedSkinName'; import { usePrices } from '../hooks/usePrices'; import { useFeature } from '../providers/FeatureProvider'; import { ChevronDownIcon, LockClosedIcon } from '@heroicons/react/24/outline'; import { PremiumCheckout } from './PremiumCheckout'; interface SkinOption { id: SkinId; name: string; image: string; } export function SkinSelector() { const router = useRouter(); const searchParams = useSearchParams(); const getLocalizedSkinName = useLocalizedSkinName(); const paymentsEnabled = useFeature('paymentsEnabled'); const { getPrice, loading: pricesLoading } = usePrices(); const [isOpen, setIsOpen] = useState(false); const [showCheckout, setShowCheckout] = useState(null); const dropdownRef = useRef(null); // When payments are disabled, filter out premium skins entirely const skinOptions: SkinOption[] = Object.entries(appConfig.skins) .filter(([, skin]) => paymentsEnabled || !skin.isPremium) .map(([id, skin]) => ({ id: id as SkinId, name: getLocalizedSkinName(id), image: skin.normal })); const skinParam = searchParams.get('skin'); // Validate that the skin exists in our config const isValidSkin = skinParam && Object.keys(appConfig.skins).includes(skinParam); // Use the skin from URL if valid, otherwise use default skin const currentSkin = (isValidSkin ? skinParam : appConfig.defaultSkin) as SkinId; const currentSkinOption = skinOptions.find(skin => skin.id === currentSkin) || skinOptions[0]; const handleSkinChange = useCallback((newSkin: SkinId) => { const skin = appConfig.skins[newSkin]; // If it's a premium skin, show checkout modal if (skin.isPremium) { setShowCheckout(newSkin); setIsOpen(false); return; } // For free skins, change immediately const params = new URLSearchParams(searchParams.toString()); if (newSkin === appConfig.defaultSkin) { params.delete('skin'); } else { params.set('skin', newSkin); } const newUrl = `${window.location.pathname}${params.toString() ? '?' + params.toString() : ''}`; router.push(newUrl); setIsOpen(false); }, [router, searchParams]); const handleCheckoutClose = useCallback(() => { setShowCheckout(null); }, []); // Handle clicking outside to close dropdown useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { setIsOpen(false); } }; if (isOpen) { document.addEventListener('mousedown', handleClickOutside); } return () => { document.removeEventListener('mousedown', handleClickOutside); }; }, [isOpen]); // Handle escape key to close dropdown useEffect(() => { const handleEscape = (event: KeyboardEvent) => { if (event.key === 'Escape') { setIsOpen(false); } }; if (isOpen) { document.addEventListener('keydown', handleEscape); } return () => { document.removeEventListener('keydown', handleEscape); }; }, [isOpen]); const toggleDropdown = () => { setIsOpen(!isOpen); }; return (
{/* Main toggle button */} {/* Dropdown menu */} {isOpen && (
{skinOptions.map((option) => { const skin = appConfig.skins[option.id]; const isPremium = skin.isPremium; return ( ); })}
)} {/* Premium Checkout Modal */} {showCheckout && ( )}
); }