mirror of
https://github.com/myronblair/kino-app
synced 2026-07-29 05:54:01 -05:00
84 lines
2.9 KiB
React
84 lines
2.9 KiB
React
import { useEffect, useState, useCallback } from "react";
|
|
import { useNavigate } from "react-router-dom";
|
|
import api from "../lib/api";
|
|
import Hero from "../components/Hero";
|
|
import Row from "../components/Row";
|
|
import MovieDetailModal from "../components/MovieDetailModal";
|
|
|
|
export default function Browse() {
|
|
const nav = useNavigate();
|
|
const [featured, setFeatured] = useState(null);
|
|
const [movies, setMovies] = useState([]);
|
|
const [genres, setGenres] = useState([]);
|
|
const [continueWatching, setContinueWatching] = useState([]);
|
|
const [watchlist, setWatchlist] = useState([]);
|
|
const [selected, setSelected] = useState(null);
|
|
const [progressMap, setProgressMap] = useState({});
|
|
|
|
const load = useCallback(async () => {
|
|
const [{ data: f }, { data: ms }, { data: gs }, { data: cw }, { data: wl }] = await Promise.all([
|
|
api.get("/movies/featured").catch(() => ({ data: null })),
|
|
api.get("/movies"),
|
|
api.get("/movies/genres"),
|
|
api.get("/progress/continue").catch(() => ({ data: [] })),
|
|
api.get("/watchlist").catch(() => ({ data: [] })),
|
|
]);
|
|
setFeatured(f);
|
|
setMovies(ms);
|
|
setGenres(gs);
|
|
setContinueWatching(cw);
|
|
setWatchlist(wl);
|
|
const map = {};
|
|
for (const m of cw) map[m.id] = m.progress;
|
|
setProgressMap(map);
|
|
}, []);
|
|
|
|
useEffect(() => { load(); }, [load]);
|
|
|
|
const handlePlay = (m) => nav(`/watch/${m.id}`);
|
|
const handleMore = (m) => setSelected(m);
|
|
const handleAddList = async (m) => {
|
|
try { await api.post(`/watchlist/${m.id}`); load(); } catch {}
|
|
};
|
|
|
|
const byGenre = (g) => movies.filter((m) => m.genres?.includes(g));
|
|
const trending = movies.slice(0, 10);
|
|
const newReleases = [...movies].sort((a, b) => b.year - a.year).slice(0, 12);
|
|
|
|
return (
|
|
<div className="min-h-screen bg-[#050505]" data-testid="browse-page">
|
|
{featured && (
|
|
<Hero
|
|
movie={featured}
|
|
onPlay={handlePlay}
|
|
onMore={handleMore}
|
|
onAddList={handleAddList}
|
|
/>
|
|
)}
|
|
|
|
<div className="-mt-20 relative z-10 pb-24">
|
|
{continueWatching.length > 0 && (
|
|
<Row title="Resume" movies={continueWatching} onCardClick={handleMore} progressMap={progressMap} />
|
|
)}
|
|
<Row title="Popular" movies={trending} onCardClick={handleMore} progressMap={progressMap} />
|
|
<Row title="Fresh Arrivals" movies={newReleases} onCardClick={handleMore} progressMap={progressMap} />
|
|
{watchlist.length > 0 && (
|
|
<Row title="Your Shelf" movies={watchlist} onCardClick={handleMore} progressMap={progressMap} />
|
|
)}
|
|
{genres.slice(0, 6).map((g) => {
|
|
const list = byGenre(g);
|
|
if (!list.length) return null;
|
|
return <Row key={g} title={g} movies={list} onCardClick={handleMore} progressMap={progressMap} />;
|
|
})}
|
|
</div>
|
|
|
|
<MovieDetailModal
|
|
movie={selected}
|
|
open={!!selected}
|
|
onClose={() => setSelected(null)}
|
|
onWatchlistChange={load}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|