import { useEffect, useState, useCallback } from 'react' import api from '../lib/api' import { Plus, Trash2, Search, X, Tv, Film, Clapperboard, Star } from 'lucide-react' import clsx from 'clsx' type CatType = 'live' | 'movie' | 'series' interface Category { id: number name: string type: CatType is_visible: boolean item_count: number } interface CategoryChannel { item_id: number channel_id: number name: string logo: string type: string } interface SearchChannel { id: number name: string logo: string type: string } const TYPE_LABELS: Record = { live: 'Directo', movie: 'Película', series: 'Serie' } const TYPE_ICONS: Record = { live: Tv, movie: Film, series: Clapperboard } const TYPE_COLORS: Record = { live: 'bg-blue-500/20 text-blue-400', movie: 'bg-purple-500/20 text-purple-400', series: 'bg-orange-500/20 text-orange-400', } export default function CustomCategories() { const [categories, setCategories] = useState([]) const [selected, setSelected] = useState(null) const [channels, setChannels] = useState([]) const [searchQ, setSearchQ] = useState('') const [searchType, setSearchType] = useState('') const [searchResults, setSearchResults] = useState([]) const [showSearch, setShowSearch] = useState(false) const [showCreate, setShowCreate] = useState(false) const [newName, setNewName] = useState('') const [newType, setNewType] = useState('live') const [loading, setLoading] = useState(false) const loadCategories = useCallback(async () => { const { data } = await api.get('/custom-categories') setCategories(data) }, []) const loadChannels = useCallback(async (cat: Category) => { const { data } = await api.get(`/custom-categories/${cat.id}/channels`) setChannels(data) }, []) useEffect(() => { loadCategories() }, [loadCategories]) useEffect(() => { if (selected) loadChannels(selected) }, [selected, loadChannels]) const selectCategory = (cat: Category) => { setSelected(cat) setShowSearch(false) setSearchQ('') setSearchResults([]) } const createCategory = async () => { if (!newName.trim()) return await api.post('/custom-categories', { name: newName.trim(), type: newType }) setNewName('') setShowCreate(false) await loadCategories() } const deleteCategory = async (cat: Category) => { if (!confirm(`¿Eliminar categoría "${cat.name}"?`)) return await api.delete(`/custom-categories/${cat.id}`) if (selected?.id === cat.id) setSelected(null) await loadCategories() } const toggleVisible = async (cat: Category) => { await api.patch(`/custom-categories/${cat.id}`, { is_visible: !cat.is_visible }) await loadCategories() if (selected?.id === cat.id) setSelected({ ...cat, is_visible: !cat.is_visible }) } const doSearch = useCallback(async (q: string, t: string) => { if (!q && !t) { setSearchResults([]); return } const { data } = await api.get('/custom-categories/channels/search', { params: { q, type: t } }) setSearchResults(data) }, []) useEffect(() => { const id = setTimeout(() => doSearch(searchQ, searchType), 300) return () => clearTimeout(id) }, [searchQ, searchType, doSearch]) const addChannel = async (ch: SearchChannel) => { if (!selected) return try { await api.post(`/custom-categories/${selected.id}/channels`, { channel_id: ch.id }) await loadChannels(selected) await loadCategories() } catch (e: any) { if (e.response?.status !== 409) alert('Error al añadir canal') } } const removeChannel = async (item: CategoryChannel) => { if (!selected) return await api.delete(`/custom-categories/${selected.id}/channels/${item.item_id}`) await loadChannels(selected) await loadCategories() } return (
{/* Left: Category list */} {/* Right: Channel list */}
{!selected ? (

Selecciona una categoría para gestionar sus canales

) : ( <> {/* Header */}

{(() => { const Icon = TYPE_ICONS[selected.type]; return })()} {selected.name} {TYPE_LABELS[selected.type]}

{channels.length} canales asignados

{/* Search panel */} {showSearch && (
setSearchQ(e.target.value)} placeholder="Buscar canal..." className="w-full bg-dark-700 border border-dark-600 rounded-lg pl-9 pr-3 py-2 text-sm focus:outline-none focus:border-primary-500" />
{searchResults.map(ch => { const already = channels.some(c => c.channel_id === ch.id) return ( ) })} {searchResults.length === 0 && (searchQ || searchType) && (

Sin resultados

)}
)} {/* Channel list */}
{channels.length === 0 ? (

Esta categoría está vacía.

Usa "Añadir canales" para añadir contenido.

) : (
{channels.map((ch, idx) => (
{idx + 1} {ch.logo ? ( (e.currentTarget.style.display = 'none')} /> ) : (
)} {ch.name} {TYPE_LABELS[ch.type as CatType] || ch.type}
))}
)}
)}
) }