abcd / src /components /ChannelList.tsx
docs4you's picture
Upload 41 files
84121fd verified
import React, { useState, useMemo } from 'react'
import { useChannels } from '../contexts/ChannelContext'
import { useKeyboard } from '../hooks/useKeyboard'
import { Search, Heart, Tv, RefreshCw } from 'lucide-react'
import { Channel } from '../types/channel'
interface ChannelListProps {
onChannelSelect?: () => void
}
export default function ChannelList({ onChannelSelect }: ChannelListProps) {
const {
channels,
categories,
currentChannel,
favorites,
searchTerm,
selectedCategory,
setCurrentChannel,
setSearchTerm,
setSelectedCategory,
toggleFavorite,
refreshChannels,
isLoading
} = useChannels()
const [selectedIndex, setSelectedIndex] = useState(0)
const filteredChannels = useMemo(() => {
let filtered = channels
// Filtrar por categoría
if (selectedCategory === 'favorites') {
filtered = filtered.filter(channel => favorites.includes(channel.id))
} else if (selectedCategory !== 'all') {
filtered = filtered.filter(channel => channel.category === selectedCategory)
}
// Filtrar por búsqueda
if (searchTerm) {
filtered = filtered.filter(channel =>
channel.name.toLowerCase().includes(searchTerm.toLowerCase())
)
}
return filtered
}, [channels, selectedCategory, favorites, searchTerm])
useKeyboard({
onArrowUp: () => setSelectedIndex(prev => Math.max(0, prev - 1)),
onArrowDown: () => setSelectedIndex(prev => Math.min(filteredChannels.length - 1, prev + 1)),
onEnter: () => {
if (filteredChannels[selectedIndex]) {
handleChannelSelect(filteredChannels[selectedIndex])
}
}
})
const handleChannelSelect = (channel: Channel) => {
setCurrentChannel(channel)
onChannelSelect?.()
}
const handleCategoryChange = (category: string) => {
setSelectedCategory(category)
setSelectedIndex(0)
}
return (
<div className="h-full flex flex-col bg-gray-800">
{/* Búsqueda */}
<div className="p-4 border-b border-gray-700">
<div className="relative">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-gray-400" />
<input
type="text"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
placeholder="Buscar canales..."
className="input-field w-full pl-10 text-sm"
/>
</div>
</div>
{/* Categorías */}
<div className="p-4 border-b border-gray-700">
<div className="flex items-center justify-between mb-2">
<h3 className="text-sm font-medium text-gray-300">Categorías</h3>
<button
onClick={refreshChannels}
disabled={isLoading}
className="p-1 hover:bg-gray-700 rounded transition-colors"
title="Actualizar canales"
>
<RefreshCw className={`h-4 w-4 text-gray-400 ${isLoading ? 'animate-spin' : ''}`} />
</button>
</div>
<div className="space-y-1">
<button
onClick={() => handleCategoryChange('all')}
className={`w-full text-left px-2 py-1 rounded text-sm transition-colors ${
selectedCategory === 'all'
? 'bg-primary-600 text-white'
: 'text-gray-300 hover:bg-gray-700'
}`}
>
Todos ({channels.length})
</button>
<button
onClick={() => handleCategoryChange('favorites')}
className={`w-full text-left px-2 py-1 rounded text-sm transition-colors flex items-center space-x-2 ${
selectedCategory === 'favorites'
? 'bg-primary-600 text-white'
: 'text-gray-300 hover:bg-gray-700'
}`}
>
<Heart className="h-3 w-3" />
<span>Favoritos ({favorites.length})</span>
</button>
{categories.map(category => (
<button
key={category.name}
onClick={() => handleCategoryChange(category.name)}
className={`w-full text-left px-2 py-1 rounded text-sm transition-colors ${
selectedCategory === category.name
? 'bg-primary-600 text-white'
: 'text-gray-300 hover:bg-gray-700'
}`}
>
{category.name} ({category.count})
</button>
))}
</div>
</div>
{/* Lista de canales */}
<div className="flex-1 overflow-y-auto">
{filteredChannels.length === 0 ? (
<div className="p-4 text-center text-gray-400">
<Tv className="h-8 w-8 mx-auto mb-2 opacity-50" />
<p className="text-sm">No se encontraron canales</p>
</div>
) : (
<div className="p-2 space-y-1">
{filteredChannels.map((channel, index) => (
<div
key={channel.id}
onClick={() => handleChannelSelect(channel)}
className={`channel-item ${
currentChannel?.id === channel.id ? 'active' : ''
} ${index === selectedIndex ? 'ring-2 ring-primary-500' : ''}`}
>
<div className="flex-1 min-w-0">
<div className="flex items-center space-x-2">
{channel.logo && (
<img
src={channel.logo}
alt={channel.name}
className="w-8 h-8 rounded object-cover flex-shrink-0"
onError={(e) => {
e.currentTarget.style.display = 'none'
}}
/>
)}
<div className="flex-1 min-w-0">
<p className="text-sm font-medium text-white truncate">
{channel.name}
</p>
<p className="text-xs text-gray-400 truncate">
{channel.category}
</p>
</div>
</div>
</div>
<button
onClick={(e) => {
e.stopPropagation()
toggleFavorite(channel.id)
}}
className="p-1 hover:bg-gray-600 rounded transition-colors"
>
<Heart
className={`h-4 w-4 ${
favorites.includes(channel.id)
? 'text-red-500 fill-current'
: 'text-gray-400'
}`}
/>
</button>
</div>
))}
</div>
)}
</div>
</div>
)
}