Ctrl K
ComunidadGuías…
frontend/src/App.tsxtypescript · @kibot
20/9/2026, 17:21:13
import React, { useState, useEffect } from 'react'
import VideoPlayer from './components/VideoPlayer'
import type { Movie, MovieDetailsResponse } from './types/api'

const API_BASE_URL = 'http://localhost:8000'

const App: React.FC = () => {
  const [selectedMovie, setSelectedMovie] = useState<Movie | null>(null)
  const [movies, setMovies] = useState<Movie[]>([])
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState<string | null>(null)

  // Cargar películas iniciales desde el backend
  useEffect(() => {
    fetchMovies()
  }, [])

  const fetchMovies = async () => {
    try {
      setLoading(true)
      setError(null)
      
      const response = await fetch(`${API_BASE_URL}/movies`)
      
      if (!response.ok) {
        throw new Error(`Error ${response.status}: ${response.statusText}`)
      }

      const data: Movie[] = await response.json()
      setMovies(data)
    } catch (err) {
      console.error('Error cargando películas:', err)
      setError('No se pudieron cargar las películas. Asegúrate de que el backend esté corriendo.')
    } finally {
      setLoading(false)
    }
  }

  const handleMovieSelect = async (movie: Movie) => {
    try {
      // Obtener detalles completos de la película
      const detailsResponse = await fetch(`${API_BASE_URL}/movies/${movie.id}`)
      
      if (!detailsResponse.ok) {
        throw new Error('Película no encontrada')
      }

      const movieDetails: MovieDetailsResponse = await detailsResponse.json()
      setSelectedMovie(movieDetails)
    } catch (err) {
      console.error('Error obteniendo detalles de la película:', err)
      setError('No se pudo obtener los detalles de la película')
    }
  }

  const handleRefresh = () => {
    fetchMovies()
  }

  return (
    <div style={{ padding: '20px', fontFamily: 'Arial, sans-serif', minHeight: '100vh', backgroundColor: '#141414' }}>
      <h1 style={{ color: '#e50914', marginBottom: '20px' }}>NetFlux - Tu propio Netflix Casero</h1>
      
      {error && (
        <div style={{
          backgroundColor: '#d32f2f',
          color: 'white',
          padding: '12px',
          borderRadius: '4px',
          marginBottom: '20px'
        }}>
          {error}
        </div>
      )}

      <button
        onClick={handleRefresh}
        style={{
          backgroundColor: '#333',
          color: 'white',
          border: 'none',
          padding: '8px 16px',
          borderRadius: '4px',
          cursor: 'pointer',
          marginBottom: '20px'
        }}
      >
        🔄 Recargar películas
      </button>

      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(200px, 1fr))', gap: '16px' }}>
        {loading ? (
          <div style={{ gridColumn: '1/-1', textAlign: 'center', padding: '40px' }}>
            Cargando películas...
          </div>
        ) : movies.length === 0 ? (
          <div style={{ gridColumn: '1/-1', textAlign: 'center', padding: '40px', color: '#888' }}>
            No hay películas disponibles. Asegúrate de que el backend esté corriendo.
          </div>
        ) : (
          movies.map(movie => (
            <div
              key={movie.id}
              onClick={() => handleMovieSelect(movie)}
              style={{
                cursor: 'pointer',
                padding: '12px',
                border: '1px solid #333',
                borderRadius: '8px',
                textAlign: 'center',
                backgroundColor: '#1f1f1f',
                transition: 'transform 0.2s, box-shadow 0.2s',
                transform: 'scale(1)',
                boxShadow: 'none'
              }}
              onMouseEnter={(e) => {
                e.currentTarget.style.transform = 'scale(1.05)'
                e.currentTarget.style.boxShadow = '0 4px 8px rgba(0,0,0,0.3)'
              }}
              onMouseLeave={(e) => {
                e.currentTarget.style.transform = 'scale(1)'
                e.currentTarget.style.boxShadow = 'none'
              }}
            >
              <img
                src={movie.poster_path || '/placeholder.jpg'}
                alt={movie.title}
                style={{ width: '100%', height: '300px', objectFit: 'cover', borderRadius: '4px' }}
              />
              <h3 style={{ margin: '8px 0 4px', color: '#fff' }}>{movie.title}</h3>
            </div>
          ))
        )}
      </div>

      {selectedMovie && (
        <div style={{ marginTop: '24px' }}>
          <VideoPlayer movie={selectedMovie} />
        </div>
      )}
    </div>
  )
}

export default App

Comentarios de código