Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 18 additions & 82 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,102 +1,38 @@
// App.tsx
import { useState } from 'react';
import { useCurMovies, usePopMovies } from './hooks/useMovies';

import { usePopMovies, useCurMovies } from './hooks/useMovies';
import { usePopularPeople } from './hooks/usePeople';
//import { Button } from './components/Button';
import { Sidebar} from './components/sidebar';
import { Sidebar } from './components/sidebar';
import { Section } from './components/Section';
import MovieList from './components/MovieList';
import { PersonList } from './components/PersonList';
import './App.css';

function App() {

const [searchQuery, setSearchQuery] = useState('')
//const [view, setView] = useState<'popular' | 'current'>('popular')

const popular = usePopMovies()
const current = useCurMovies()
const people = usePopularPeople()

const viewConfig = {
popular: { title: 'Populære filmer', query: popular },
current: { title: 'Nye filmer', query: current },
}
/*
const { title, query } = viewConfig[view]
const { data, isLoading, error } = query
if (isLoading) {
return <p>Laster filmer...</p>
}
if (error) {
return <p>Noe gikk galt: {error.message}</p>
}
return (
<div>
<h1>{title}</h1>
<ul>
{data.results.map((movie: any) => (
<li key={movie.id}>{movie.title}</li>
))}
</ul>
<Button text="Popular" onClick={() => setView('popular')} />
<Button text="Current" onClick={() => setView('current')} />
</div>
)
}
*/

return (
<div className="page">
<Sidebar onSearch={setSearchQuery} />
<Sidebar />

<main>
<Section id="populaere" title="Populære filmer" isLoading={popular.isLoading} error={popular.error}>
{popular.data && <MovieList movies={popular.data.results} />}
</Section>

<section id="populaere">
<h2>Populære filmer</h2>
{popular.isLoading && <p>Laster filmer...</p>}
{popular.error && <p>Noe gikk galt: {popular.error.message}</p>}
{popular.data && (
<ul>
{popular.data.results.map((movie: any) => (
<li key={movie.id}>{movie.title}</li>
))}
</ul>
)}
</section>

<section id="nye-filmer">
<h2>Nye filmer</h2>
{current.isLoading && <p>Laster filmer...</p>}
{current.error && <p>Noe gikk galt: {current.error.message}</p>}
{current.data && (
<ul>
{current.data.results.map((movie: any) => (
<li key={movie.id}>{movie.title}</li>
))}
</ul>
)}
</section>
<Section id="nye-filmer" title="Nye filmer" isLoading={current.isLoading} error={current.error}>
{current.data && <MovieList movies={current.data.results} />}
</Section>

<section id="skuespillere">
<h2>Skuespillere</h2>
{people.isLoading && <p>Laster skuespillere...</p>}
{people.error && <p>Noe gikk galt: {people.error.message}</p>}
{people.data && (
<ul>
{people.data.results.map((person: any) => (
<li key={person.id}>{person.name}</li>
))}
</ul>
)}
</section>
<Section id="skuespillere" title="Skuespillere" isLoading={people.isLoading} error={people.error}>
{people.data && <PersonList people={people.data.results} />}
</Section>
</main>

<div className="page-spacer" aria-hidden="true"></div>
</div>
)
);
}

export default App
export default App;
122 changes: 0 additions & 122 deletions src/App.txt

This file was deleted.

62 changes: 23 additions & 39 deletions src/api/tmdb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,48 +3,32 @@
// får satt den opp senere.

// BASE_URL er lenken vi bruker i en API request, her til TMDB
const TOKEN = import.meta.env.VITE_TMDB_TOKEN // v4 read access token
const BASE_URL = 'https://api.themoviedb.org/3'

export async function fetchPopularMovies() {
const res = await fetch(
`${BASE_URL}/movie/popular?language=en-US&page=1`,
{
headers: {
accept: 'application/json',
Authorization: `Bearer ${TOKEN}`,
},
}
)
if (!res.ok) throw new Error('Klarte ikke hente populære filmer...')
return res.json()
// TOKEN er lagret i .env.local, denne må alle legge til manuelt selv
import type { Movie, Person, TmdbResponse } from '../types/tmdb';

const TOKEN = import.meta.env.VITE_TMDB_TOKEN; // v4 read access token
const BASE_URL = 'https://api.themoviedb.org/3';

async function tmdbFetch<T>(path: string, errorMessage: string): Promise<T> {
const res = await fetch(`${BASE_URL}${path}`, {
headers: {
accept: 'application/json',
Authorization: `Bearer ${TOKEN}`,
},
});
if (!res.ok) throw new Error(errorMessage);
return res.json();
}

export function fetchPopularMovies(): Promise<TmdbResponse<Movie>> {
return tmdbFetch('/movie/popular?language=en-US&page=1', 'Klarte ikke hente populære filmer...');
}

export async function fetchCurrentMovies() {
const res = await fetch(
`${BASE_URL}/movie/now_playing?language=en-US&page=1`,
{
headers: {
accept: 'application/json',
Authorization: `Bearer ${TOKEN}`,
},
}
)
if (!res.ok) throw new Error('Klarte ikke hente aktuelle filmer...')
return res.json()
export function fetchCurrentMovies(): Promise<TmdbResponse<Movie>> {
return tmdbFetch('/movie/now_playing?language=en-US&page=1', 'Klarte ikke hente aktuelle filmer...');
}
//lagt til popular people

export async function fetchPopularPeople() {
const res = await fetch(
`${BASE_URL}/person/popular?language=en-US&page=1`,
{
headers: {
accept: 'application/json',
Authorization: `Bearer ${TOKEN}`,
},
}
)
if (!res.ok) throw new Error('Klarte ikke hente skuespillere...')
return res.json()
export function fetchPopularPeople(): Promise<TmdbResponse<Person>> {
return tmdbFetch('/person/popular?language=en-US&page=1', 'Klarte ikke hente skuespillere...');
}
44 changes: 19 additions & 25 deletions src/components/MovieList.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,35 @@
// Henter inn MovieCard-komponenten vår, slik at vi kan bruke den til å vise hver film.
import MovieCard from "./Movie_card";
// Henter inn hooken som henter populære filmer fra TMDB via TanStack Query.
import { usePopMovies } from "../hooks/usePopMovies";
// Typen for én film fra TMDB, så vi slipper any og får autocomplete på feltene.
import type { Movie } from "../types/tmdb";

// MovieList har ansvaret for å hente filmene og vise dem som en liste av MovieCard.
// MovieList tar imot ferdig hentede filmer som prop og viser dem som en liste av MovieCard.
// Selve hentingen skjer via hookene i App.tsx, og Section håndterer laster- og feilmelding,
// så denne komponenten slipper å gjøre det samme en gang til.
// MovieCard selv vet ingenting om TMDB eller fetching, den bare mottar props.
function MovieList() {
// useQuery (inni usePopMovies) returnerer et objekt med bl.a. data, isLoading og error.
// Vi destrukturerer ut akkurat de tre vi trenger her.
const { data, isLoading, error } = usePopMovies();

// Mens dataene fortsatt hentes fra API-et, viser vi en enkel lastetekst
// i stedet for en tom/ødelagt liste.
if (isLoading) {
return <p>Laster filmer...</p>;
}

// Hvis noe gikk galt med kallet (f.eks. nettverksfeil eller ugyldig token),
// viser vi en enkel feilmelding i stedet for å krasje siden.
if (error) {
return <p>Klarte ikke hente filmer akkurat nå.</p>;
}
type MovieListProps = {
movies: Movie[];
};

function MovieList({ movies }: MovieListProps) {
return (
// Ytre container for hele filmlisten, kan style'es med CSS senere
<div className="movie-list">
{/* data er svaret fra TMDB, som har en "results"-liste med filmobjekter.
?. brukes i tilfelle data enda ikke har kommet (undefined). */}
{data?.results.map((movie: any) => (
{movies.map((movie) => (
// .map() går gjennom hver film og returnerer én MovieCard per film.
// key={movie.id} er påkrevd av React for å holde styr på hvert element i lista.
<MovieCard
key={movie.id}
// TMDB sitt feltnavn er "title", som passer direkte med vår prop
title={movie.title}
// TMDB gir bare en delsti (poster_path), så vi setter sammen full bilde-URL selv
posterUrl={`https://image.tmdb.org/t/p/w200${movie.poster_path}`}
// TMDB gir bare en delsti (poster_path), så vi setter sammen full bilde-URL selv.
// Noen filmer mangler plakat (poster_path er null), da sender vi tom streng
// i stedet for å be om ".../w200null" og få et ødelagt bilde.
posterUrl={
movie.poster_path
? `https://image.tmdb.org/t/p/w200${movie.poster_path}`
: ""
}
// TMDB sin vote_average går fra 0-10, vi ganger med 10 for å få prosent (0-100)
rating={Math.round(movie.vote_average * 10)}
// Skuespillere ligger ikke i dette API-svaret (krever eget kall til /credits),
Expand All @@ -48,4 +42,4 @@ function MovieList() {
}

// Eksporterer komponenten slik at App.tsx (eller en layout-komponent) kan bruke <MovieList />
export default MovieList;
export default MovieList;
Loading