From 3ae496afa343aea14971c0c90b69d3fe881e0542 Mon Sep 17 00:00:00 2001 From: Clemens Beese Date: Thu, 10 Sep 2026 14:14:53 +0200 Subject: [PATCH 1/3] Flyttet ting ut av App.tsx -> mer components --- src/App.tsx | 102 +++++++--------------------------- src/api/tmdb.ts | 62 ++++++++------------- src/components/MovieList.tsx | 15 +++++ src/components/PersonList.tsx | 15 +++++ src/components/Section.tsx | 22 ++++++++ src/types/tmdb.ts | 21 +++++++ 6 files changed, 117 insertions(+), 120 deletions(-) create mode 100644 src/components/MovieList.tsx create mode 100644 src/components/PersonList.tsx create mode 100644 src/components/Section.tsx create mode 100644 src/types/tmdb.ts diff --git a/src/App.tsx b/src/App.tsx index 22660f9..a642e3f 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,100 +1,40 @@ -// 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 [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

Laster filmer...

- } - - if (error) { - return

Noe gikk galt: {error.message}

- } - - return ( -
-

{title}

- -
- ) -} -*/ + const popular = usePopMovies(); + const current = useCurMovies(); + const people = usePopularPeople(); return (
+
+ {popular.data && } +
-
-

Populære filmer

- {popular.isLoading &&

Laster filmer...

} - {popular.error &&

Noe gikk galt: {popular.error.message}

} - {popular.data && ( -
    - {popular.data.results.map((movie: any) => ( -
  • {movie.title}
  • - ))} -
- )} -
+
+ {current.data && } +
-
-

Nye filmer

- {current.isLoading &&

Laster filmer...

} - {current.error &&

Noe gikk galt: {current.error.message}

} - {current.data && ( -
    - {current.data.results.map((movie: any) => ( -
  • {movie.title}
  • - ))} -
- )} -
- -
-

Skuespillere

- {people.isLoading &&

Laster skuespillere...

} - {people.error &&

Noe gikk galt: {people.error.message}

} - {people.data && ( -
    - {people.data.results.map((person: any) => ( -
  • {person.name}
  • - ))} -
- )} -
+
+ {people.data && } +
+
- ) + ); } -export default App \ No newline at end of file +export default App; \ No newline at end of file diff --git a/src/api/tmdb.ts b/src/api/tmdb.ts index c298826..91d1e69 100644 --- a/src/api/tmdb.ts +++ b/src/api/tmdb.ts @@ -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(path: string, errorMessage: string): Promise { + 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> { + 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> { + 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> { + return tmdbFetch('/person/popular?language=en-US&page=1', 'Klarte ikke hente skuespillere...'); } \ No newline at end of file diff --git a/src/components/MovieList.tsx b/src/components/MovieList.tsx new file mode 100644 index 0000000..5b5012e --- /dev/null +++ b/src/components/MovieList.tsx @@ -0,0 +1,15 @@ +import type { Movie } from '../types/tmdb'; + +type MovieListProps = { + movies: Movie[]; +}; + +export function MovieList({ movies }: MovieListProps) { + return ( +
    + {movies.map((movie) => ( +
  • {movie.title}
  • + ))} +
+ ); +} \ No newline at end of file diff --git a/src/components/PersonList.tsx b/src/components/PersonList.tsx new file mode 100644 index 0000000..bd732d1 --- /dev/null +++ b/src/components/PersonList.tsx @@ -0,0 +1,15 @@ +import type { Person } from '../types/tmdb'; + +type PersonListProps = { + people: Person[]; +}; + +export function PersonList({ people }: PersonListProps) { + return ( +
    + {people.map((person) => ( +
  • {person.name}
  • + ))} +
+ ); +} \ No newline at end of file diff --git a/src/components/Section.tsx b/src/components/Section.tsx new file mode 100644 index 0000000..f2f77ce --- /dev/null +++ b/src/components/Section.tsx @@ -0,0 +1,22 @@ +// denne filen eier overskrift + laster/feil-håndtering, tar innholdet som 'children': + +import type { ReactNode } from 'react'; + +type SectionProps = { + id: string; + title: string; + isLoading: boolean; + error: Error | null; + children: ReactNode; +}; + +export function Section({ id, title, isLoading, error, children }: SectionProps) { + return ( +
+

{title}

+ {isLoading &&

Laster...

} + {error &&

Noe gikk galt: {error.message}

} + {!isLoading && !error && children} +
+ ); +} \ No newline at end of file diff --git a/src/types/tmdb.ts b/src/types/tmdb.ts new file mode 100644 index 0000000..843b689 --- /dev/null +++ b/src/types/tmdb.ts @@ -0,0 +1,21 @@ +export type Movie = { + id: number; + title: string; + poster_path: string | null; + vote_average: number; + release_date: string; +}; + +export type Person = { + id: number; + name: string; + profile_path: string | null; +}; + +// TMDB pakker alltid svaret i samme struktur, uansett hva results inneholder +export type TmdbResponse = { + page: number; + results: T[]; + total_pages: number; + total_results: number; +}; \ No newline at end of file From b571dcac5e4966a4de59390bd72ac18136549bce Mon Sep 17 00:00:00 2001 From: Clemens Beese Date: Thu, 10 Sep 2026 14:38:42 +0200 Subject: [PATCH 2/3] Flyttet ting ut av App.tsx -> mer components --- src/App.tsx | 7 +-- src/App.txt | 122 -------------------------------------- src/hooks/usePopMovies.ts | 2 +- 3 files changed, 3 insertions(+), 128 deletions(-) delete mode 100644 src/App.txt diff --git a/src/App.tsx b/src/App.tsx index a642e3f..18decca 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,4 +1,3 @@ -import { useState } from 'react'; import { usePopMovies, useCurMovies } from './hooks/useMovies'; import { usePopularPeople } from './hooks/usePeople'; import { Sidebar } from './components/sidebar'; @@ -8,15 +7,13 @@ import { PersonList } from './components/PersonList'; import './App.css'; function App() { - const [searchQuery, setSearchQuery] = useState(''); - const popular = usePopMovies(); const current = useCurMovies(); const people = usePopularPeople(); return (
- +
@@ -37,4 +34,4 @@ function App() { ); } -export default App; \ No newline at end of file +export default App; diff --git a/src/App.txt b/src/App.txt deleted file mode 100644 index 9ca8e8d..0000000 --- a/src/App.txt +++ /dev/null @@ -1,122 +0,0 @@ -import { useState } from 'react' -import heroImg from './assets/hero.png' -import reactLogo from './assets/react.svg' -import viteLogo from './assets/vite.svg' -import './App.css' - -function App() { - const [count, setCount] = useState(0) - - return ( - <> -
-
- - React logo - Vite logo -
-
-

Get started

-

- Edit src/App.tsx and save to test HMR -

-
- -
- -
- -
-
- -

Documentation

-

Your questions, answered

- -
-
- -

Connect with us

-

Join the Vite community

- -
-
- -
-
- - ) -} - -export default App diff --git a/src/hooks/usePopMovies.ts b/src/hooks/usePopMovies.ts index 621df77..77e859f 100644 --- a/src/hooks/usePopMovies.ts +++ b/src/hooks/usePopMovies.ts @@ -1,6 +1,6 @@ // hooks/useMovies.ts import { useQuery } from '@tanstack/react-query' -import { fetchCurrentMovies, fetchPopularMovies } from '../api/tmdb' +import { fetchPopularMovies } from '../api/tmdb' export function useMovies() { return useQuery({ From 9f32a0a3228f9b1e6cf9c71e412f62011d04f54a Mon Sep 17 00:00:00 2001 From: Clemens Beese Date: Thu, 10 Sep 2026 15:06:37 +0200 Subject: [PATCH 3/3] Flyttet ting ut av App.tsx -> mer components --- src/components/MovieList.tsx | 66 ++++++++++++++++++++++++++++-------- src/hooks/usePopMovies.ts | 2 +- 2 files changed, 52 insertions(+), 16 deletions(-) diff --git a/src/components/MovieList.tsx b/src/components/MovieList.tsx index 5b5012e..2eede8d 100644 --- a/src/components/MovieList.tsx +++ b/src/components/MovieList.tsx @@ -1,15 +1,51 @@ -import type { Movie } from '../types/tmdb'; - -type MovieListProps = { - movies: Movie[]; -}; - -export function MovieList({ movies }: MovieListProps) { - return ( -
    - {movies.map((movie) => ( -
  • {movie.title}
  • - ))} -
- ); -} \ No newline at end of file +// 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"; + +// MovieList har ansvaret for å hente filmene og vise dem som en liste av MovieCard. +// 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

Laster filmer...

; +} + +// 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

Klarte ikke hente filmer akkurat nå.

; +} + +return ( +// Ytre container for hele filmlisten, kan style'es med CSS senere +
+{/* 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) => ( +// .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. + +))} +
+); +} + +// Eksporterer komponenten slik at App.tsx (eller en layout-komponent) kan bruke +export default MovieList; \ No newline at end of file diff --git a/src/hooks/usePopMovies.ts b/src/hooks/usePopMovies.ts index 77e859f..621df77 100644 --- a/src/hooks/usePopMovies.ts +++ b/src/hooks/usePopMovies.ts @@ -1,6 +1,6 @@ // hooks/useMovies.ts import { useQuery } from '@tanstack/react-query' -import { fetchPopularMovies } from '../api/tmdb' +import { fetchCurrentMovies, fetchPopularMovies } from '../api/tmdb' export function useMovies() { return useQuery({