import React, { useState, useEffect } from 'react' import { Plus, Music, X } from 'lucide-react' import { soundEffects } from '@/lib/lofi_data' import { SoundEffect, CustomSoundEffect } from '@/types/lofi' import dynamic from 'next/dynamic' const ReactPlayer = dynamic(() => import('react-player/youtube'), { ssr: false, }) as any interface SoundEffectsControlsProps { activeEffects: Set toggleEffect: (effectId: string) => void effectsVolume: number setEffectsVolume: (vol: number) => void effectVolumes: { [key: string]: number } setEffectVolumes: (volumes: { [key: string]: number }) => void currentTheme: string customEffects: CustomSoundEffect[] setCustomEffects: (effects: CustomSoundEffect[]) => void loadingEffects: Set } const SoundEffectsControls: React.FC = ({ activeEffects, toggleEffect, effectsVolume, setEffectsVolume, effectVolumes, setEffectVolumes, currentTheme, customEffects, setCustomEffects, loadingEffects, }) => { const [isAddingEffect, setIsAddingEffect] = useState(false) const [newEffect, setNewEffect] = useState({ id: '', name: '', file: '', isYoutube: true, }) const [urlError, setUrlError] = useState('') const allEffects = [ ...soundEffects.map((effect) => ({ ...effect, isYoutube: false, })), ...customEffects.map((effect) => ({ ...effect, icon: Music, isCustom: true, })), ] const validateYoutubeUrl = (url: string): boolean => { try { const urlObj = new URL(url) return ( urlObj.hostname === 'www.youtube.com' || urlObj.hostname === 'youtube.com' || urlObj.hostname === 'youtu.be' ) } catch { return false } } const handleAddEffect = async () => { if (!newEffect.name || !newEffect.file) { alert('Please provide both name and YouTube URL') return } if (!validateYoutubeUrl(newEffect.file)) { alert('Please provide a valid YouTube URL') return } const effectId = `custom_${Date.now()}` const newCustomEffect: CustomSoundEffect = { id: effectId, name: newEffect.name, file: newEffect.file, isYoutube: true, } setCustomEffects([...customEffects, newCustomEffect]) const defaultVolume = 0.5 setEffectVolumes({ ...effectVolumes, [effectId]: defaultVolume, }) setIsAddingEffect(false) setNewEffect({ id: '', name: '', file: '', isYoutube: true }) } const handleDeleteEffect = (effectId: string) => { setCustomEffects(customEffects.filter((effect) => effect.id !== effectId)) const newVolumes = { ...effectVolumes } delete newVolumes[effectId] setEffectVolumes(newVolumes) if (activeEffects.has(effectId)) { toggleEffect(effectId) } } const renderSoundEffect = (effect: SoundEffect) => { const isActive = activeEffects.has(effect.id) const isLoading = loadingEffects.has(effect.id) return (
{effect.isYoutube && isActive && (
)}
{effect.name}
{Math.round(effectVolumes[effect.id] * 100)}% {effect.isCustom && ( )}
{ if (!isActive && !isLoading) { toggleEffect(effect.id) } setEffectVolumes({ ...effectVolumes, [effect.id]: parseFloat(e.target.value), }) }} className="w-full cursor-pointer focus:outline-none [&::-moz-range-thumb]:bg-[var(--lofi-accent)] [&::-webkit-slider-thumb]:bg-[var(--lofi-accent)]" style={{ accentColor: 'var(--lofi-accent)', }} />
) } useEffect(() => { const defaultVolume = 0.5 const newVolumes = { ...effectVolumes } let hasChanges = false allEffects.forEach((effect) => { if (effectVolumes[effect.id] === undefined) { newVolumes[effect.id] = defaultVolume hasChanges = true } }) if (hasChanges) { setEffectVolumes(newVolumes) } }, [allEffects, effectVolumes]) return (

Effects

Master Volume setEffectsVolume(parseFloat(e.target.value))} className="w-32 focus:outline-none sm:w-20 [&::-moz-range-thumb]:bg-[var(--lofi-accent)] [&::-webkit-slider-thumb]:bg-[var(--lofi-accent)]" style={{ accentColor: 'var(--lofi-accent)', }} />
{allEffects.map((effect) => renderSoundEffect(effect))}
{isAddingEffect && (

Add Sound Effect

setNewEffect({ ...newEffect, name: e.target.value }) } className="w-full rounded-[var(--lofi-button-radius)] bg-[var(--lofi-card-hover)] px-3 py-2 text-sm text-[var(--lofi-text-primary)] placeholder:text-[var(--lofi-text-secondary)] focus:outline-none" />
{ setNewEffect({ ...newEffect, file: e.target.value }) setUrlError('') }} className={`w-full rounded-[var(--lofi-button-radius)] bg-[var(--lofi-card-hover)] px-3 py-2 text-sm text-[var(--lofi-text-primary)] placeholder:text-[var(--lofi-text-secondary)] focus:outline-none ${ urlError ? 'border border-red-500' : '' }`} /> {urlError &&

{urlError}

}
)}
) } export default SoundEffectsControls