From b5414552fe0020e121f6b10a92f97b6a3a818261 Mon Sep 17 00:00:00 2001 From: albdert Date: Thu, 17 Sep 2026 14:08:38 +0200 Subject: [PATCH 1/3] endre readme med dokumentasjon --- README.md | 222 ++++++++++++------------------------------------------ 1 file changed, 47 insertions(+), 175 deletions(-) diff --git a/README.md b/README.md index 12b6918..26da1f1 100644 --- a/README.md +++ b/README.md @@ -1,201 +1,73 @@ -# React + TypeScript + Vite - -This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. - -Currently, two official plugins are available: -- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs) -- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) +# Dokumentasjon -## React Compiler +## API -The React Compiler is enabled on this template. See [this documentation](https://react.dev/learn/react-compiler) for more information. +## hooks -Note: This will impact Vite dev & build performances. -You can also try [the experimental native React Compiler support in plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md#rust-react-compiler) by using `compiler: true` in the plugin options instead of using the Babel plugin. +## layout -## Expanding the ESLint configuration +## components -If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules: +## types -```js -export default defineConfig([ - globalIgnores(['dist']), - { - files: ['**/*.{ts,tsx}'], - extends: [ - // Other configs... +## testing - // Remove tseslint.configs.recommended and replace with this - tseslint.configs.recommendedTypeChecked, - // Alternatively, use this for stricter rules - tseslint.configs.strictTypeChecked, - // Optionally, add this for stylistic rules - tseslint.configs.stylisticTypeChecked, +#### MovieCard.tsx + MovieCard.css +Viser ett enkelt filmkort med plakat, tittel, rating og skuespillere. Tar imot movieId, title, posterUrl og rating som props. Henter skuespillerne selv via useMovieCredits(movieId) og viser en "Laster skuespillere..."-tekst mens det henter. De tre første skuespillerne vises kommaseparert. Ratingen ligger som en badge øverst i høyre hjørne, plakaten til venstre og resten av infoen til høyre – med responsiv styling for mobil (@media max-width: 480px). - // Other configs... - ], - languageOptions: { - parserOptions: { - project: ['./tsconfig.node.json', './tsconfig.app.json'], - tsconfigRootDir: import.meta.dirname, - }, - // other options... - }, - }, -]); -``` +#### MovieList.tsx + MovieList.css +Tar imot en liste med filmer (movies: Movie[]) og rendrer ett MovieCard per film med .map(). Den vet ingenting om TMDB eller fetching – det ansvaret ligger i hookene og i Section-komponenten (laster/feilhåndtering). Bygger plakat-URL fra TMDB sin poster_path, med fallback til tom streng hvis filmen mangler plakat. Regner om TMDB sin vote_average (0–10) til prosent (0–100). Layouten er et responsivt grid (repeat(auto-fill, minmax(320px, 1fr))) som går til én kolonne på mobil. -You can also install [eslint-plugin-react-x](https://npmx.dev/package/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://npmx.dev/package/eslint-plugin-react-dom) for React-specific lint rules: +#### useMovieCredits.ts +En React Query-hook som henter skuespillerlisten for én bestemt film via fetchMovieCredits i api/tmdb.ts. Caches per movieId i én time (staleTime), slik at samme film ikke hentes på nytt unødvendig når flere kort viser samme data. -```js -// eslint.config.js -import reactX from 'eslint-plugin-react-x'; -import reactDom from 'eslint-plugin-react-dom'; +#### useSessionStorage.ts +En generisk, gjenbrukbar hook som fungerer som `useState`, men som leser fra og skriver til `sessionStorage` automatisk. Brukes til både sorteringsvalg og minimumsvurdering, og kan gjenbrukes til andre ting senere ved behov. Lesing og skriving er pakket inn i try/catch i tilfelle storage er utilgjengelig (f.eks. i privat nettlesing), og faller da tilbake til en gitt standardverdi. -export default defineConfig([ - globalIgnores(['dist']), - { - files: ['**/*.{ts,tsx}'], - extends: [ - // Other configs... - // Enable lint rules for React - reactX.configs['recommended-typescript'], - // Enable lint rules for React DOM - reactDom.configs.recommended, - ], - languageOptions: { - parserOptions: { - project: ['./tsconfig.node.json', './tsconfig.app.json'], - tsconfigRootDir: import.meta.dirname, - }, - // other options... - }, - }, -]); -``` +#### sortAndFilterMovies.ts +En ren funksjon uten side-effekter som tar inn en liste med filmer, sorteringsvalg og minimumsvurdering, og returnerer en ny, filtrert og sortert liste. Fordi funksjonen er ren (samme input gir alltid samme output, og den endrer ikke noe utenfor seg selv), er den enkel å enhetsteste isolert med Vitest, uten å måtte mocke React eller komponenter. -```Dokumentasjon av kode +#### SortFilterBar.tsx +En liten, selvutviklet komponent (ingen tredjepartsbibliotek for UI, i tråd med kravet) med en nedtrekksmeny for sortering og en range-slider for minimumsvurdering. Komponenten er "dum" — den mottar verdier og callbacks som props, og eier ingen egen state selv. -Leona: - Movie_card.tsx + Movie_card.css - Viser ett enkelt filmkort med plakat, tittel, rating og skuespillere. Tar imot movieId, title, posterUrl og rating som props. Henter skuespillerne selv via useMovieCredits(movieId) og viser en "Laster skuespillere..."-tekst mens det henter. De tre første skuespillerne vises kommaseparert. Ratingen ligger som en badge øverst i høyre hjørne, plakaten til venstre og resten av infoen til høyre – med responsiv styling for mobil (@media max-width: 480px). +#### Sortering og filtrering +Brukeren kan sortere filmlistene (populære, nye filmer og søkeresultater) etter: +- Popularitet (TMDB sin standardrekkefølge) +- Vurdering (høyest først) +- Nyeste utgivelsesdato først +- Alfabetisk (tittel) - MovieList.tsx + MovieList.css - Tar imot en liste med filmer (movies: Movie[]) og rendrer ett MovieCard per film med .map(). Den vet ingenting om TMDB eller fetching – det ansvaret ligger i hookene og i Section-komponenten (laster/feilhåndtering). Bygger plakat-URL fra TMDB sin poster_path, med fallback til tom streng hvis filmen mangler plakat. Regner om TMDB sin vote_average (0–10) til prosent (0–100). Layouten er et responsivt grid (repeat(auto-fill, minmax(320px, 1fr))) som går til én kolonne på mobil. +I tillegg kan brukeren sette en minimumsgrense for vurdering (0-10) som filtrerer bort filmer under denne terskelen. - useMovieCredits.ts - En React Query-hook som henter skuespillerlisten for én bestemt film via fetchMovieCredits i api/tmdb.ts. Caches per movieId i én time (staleTime), slik at samme film ikke hentes på nytt unødvendig når flere kort viser samme data. +sessionStorage og localStorage +- Filter-/sorteringsvalg skal huskes **selv om siden reloades +- Favoritter skal huskes **selv om nettleseren avsluttes og startes igjen - bruk av KI: - Movie_card.tsx + Movie_card.css - KI (Claude, Anthropic) ble brukt til å foreslå strukturen på filmkortet: hvilke props komponenten burde ta imot (movieId, title, posterUrl, rating) versus hva den burde hente selv. Forslaget var at kortet henter skuespillerne sine via useMovieCredits(movieId) internt, i stedet for at forelderen henter og sender ned skuespillerlisten som en egen prop. Dette holder MovieList enkel og fri for ansvar den ikke trenger. +Kobling i `App.tsx` +`App.tsx` holder sorterings- og filterverdiene via `useSessionStorage`, og sender dem videre til `SortFilterBar` for visning/endring, samt bruker `sortAndFilterMovies(...)` på filmlistene før de sendes videre til `MovieList`. Dermed gjelder valget uansett hvilken liste som vises (populære, nye filmer eller søk). - KI ble også brukt til å: +Kjente begrensninger/mulige forbedringer +- Sortering og filtrering kjøres på nytt ved hver rendring. Med dagens datamengde (10–20 filmer) er dette ubetydelig for ytelsen, men kunne vært optimalisert med `useMemo` dersom datamengden økte betydelig. +- Range-slideren for minimumsvurdering kunne fått `aria-valuetext` for bedre skjermleserstøtte (f.eks. "minst 7 av 10" i stedet for kun tallet). +- sessionStorage-nøklene (`sortBy`, `minRating`) er generiske. Ved videre utvikling av appen kan det være lurt å prefikse dem (f.eks. `movieApp:sortBy`) for å unngå navnekollisjon med annen bruk av sessionStorage. - - Foreslå lastetilstand ("Laster skuespillere...") mens useMovieCredits henter data, slik at brukeren får tilbakemelding i stedet for et tomt felt - - Generere responsiv styling i Movie_card.css, inkludert plassering av rating-badge, layout med plakat til venstre/info til høyre, og tilpasning under @media (max-width: 480px) - Koden ble gjennomgått og forstått av gruppen før den ble tatt i bruk, og tilpasset til resten av prosjektets struktur (bl.a. typene fra types/tmdb.ts). - MovieList.tsx + MovieList.css +#### Bruk av KI +KI (Claude, Anthropic) ble brukt til å foreslå strukturen på filmkortet: hvilke props komponenten burde ta imot (movieId, title, posterUrl, rating) versus hva den burde hente selv. Forslaget var at kortet henter skuespillerne sine via useMovieCredits(movieId) internt, i stedet for at forelderen henter og sender ned skuespillerlisten som en egen prop. Dette holder MovieList enkel og fri for ansvar den ikke trenger. - KI ble brukt til å foreslå ansvarsdelingen mellom MovieList og resten av appen: MovieList skal kun rendre en liste med MovieCard-komponenter ut fra en ferdig hentet movies-prop, og skal ikke vite noe om TMDB, fetching, lasting eller feilhåndtering — det ansvaret ligger i hookene (useMovies.ts m.fl.) og i Section-komponenten. Denne separasjonen ble foreslått av KI som god praksis for å holde komponentene testbare og gjenbrukbare hver for seg. +KI ble brukt til å foreslå ansvarsdelingen mellom MovieList og resten av appen: MovieList skal kun rendre en liste med MovieCard-komponenter ut fra en ferdig hentet movies-prop, og skal ikke vite noe om TMDB, fetching, lasting eller feilhåndtering — det ansvaret ligger i hookene (useMovies.ts m.fl.) og i Section-komponenten. Denne separasjonen ble foreslått av KI som god praksis for å holde komponentene testbare og gjenbrukbare hver for seg. - KI ble videre brukt til å: +KI foreslo også staleTime: 1000 * 60 * 60 (én time) som en fornuftig cache-varighet, med begrunnelsen at skuespillerlister for en film praktisk talt aldri endrer seg i løpet av en brukerøkt. Dette var spesielt viktig fordi hvert MovieCard gjør sitt eget kall til /credits-endepunktet — uten caching ville samme film blitt hentet på nytt hver gang kortet ble rendret på nytt, noe som kunne gått på bekostning av kravet om å unngå unødvendige API-kall. - - Generere logikken for å bygge full plakat-URL fra TMDB sin poster_path, inkludert fallback til tom streng når poster_path er null (for å unngå en ødelagt bilde-URL som .../w200null) - - Foreslå omregningen fra TMDB sin vote_average (skala 0–10) til prosent (0–100) som vises i UI - - Sette opp det responsive grid-oppsettet i MovieList.css (repeat(auto-fill, minmax(320px, 1fr))), som går til én kolonne på mobil +Løsningen (hook, ren funksjon for sortering/filtrering, UI-komponent og kobling i `App.tsx`) ble utviklet i samarbeid med Claude (Anthropic). KI ble brukt til å foreslå arkitektur (separasjon mellom persistens-hook, ren logikk-funksjon og presentasjonskomponent), generere startkode, og til å vurdere om løsningen faktisk dekket prosjektkravene til filtrering/sortering og bruk av Web Storage API. Koden er gjennomgått og forstått av gruppen før den ble tatt i bruk. - Alle forslag ble vurdert og tilpasset av gruppen, blant annet ved å sjekke at key={movie.id} var satt riktig på listeelementene slik React krever. - - useMovieCredits.ts - - KI ble brukt til å sette opp hooken som en TanStack Query-basert wrapper rundt fetchMovieCredits fra api/tmdb.ts, med movieId som en del av queryKey slik at hver film cacher skuespillerdataen sin uavhengig av andre filmer. - - KI foreslo også staleTime: 1000 * 60 * 60 (én time) som en fornuftig cache-varighet, med begrunnelsen at skuespillerlister for en film praktisk talt aldri endrer seg i løpet av en brukerøkt. Dette var spesielt viktig fordi hvert MovieCard gjør sitt eget kall til /credits-endepunktet — uten caching ville samme film blitt hentet på nytt hver gang kortet ble rendret på nytt, noe som kunne gått på bekostning av kravet om å unngå unødvendige API-kall. - - Gruppen vurderte selv om caching-strategien var riktig for prosjektets bruksmønster, og valgte å beholde forslaget som det var. - -Leona: - Sortering og filtrering av filmer - - Hva er implementert - - Brukeren kan sortere filmlistene (populære, nye filmer og søkeresultater) etter: - - Popularitet (TMDB sin standardrekkefølge) - - Vurdering (høyest først) - - Nyeste utgivelsesdato først - - Alfabetisk (tittel) - - I tillegg kan brukeren sette en minimumsgrense for vurdering (0-10) som filtrerer bort filmer under denne terskelen. - - Dette dekker det funksjonelle kravet om at brukeren skal kunne gjøre et valg (filtrering/sortering) som påvirker utvalget av det som presenteres og hvordan det presenteres. - - Hvorfor sessionStorage (og ikke localStorage) - - Prosjektbeskrivelsen skiller mellom to typer valg som skal huskes: - - - Filter-/sorteringsvalg skal huskes **selv om siden reloades - - Favoritter skal huskes **selv om nettleseren avsluttes og startes igjen - - Dette er to forskjellige persistens-behov, og vi har derfor valgt to forskjellige Web Storage-mekanismer med hensikt: - - - sessionStorage for sortering/filtrering - data overlever en reload av siden, men nullstilles når fanen/nettleseren lukkes. Dette er nøyaktig oppførselen kravet beskriver. - - localStorage for favoritter (implementeres separat) - data overlever at nettleseren lukkes helt. - - Ved å bruke begge mekanismene til det de faktisk passer til, dekker vi også det tekniske kravet om bruk av *både* localStorage og sessionStorage, i stedet for å bruke én av dem vilkårlig for alt. - - Hvordan det er bygget - - src/hooks/useSessionStorage.ts - En generisk, gjenbrukbar hook som fungerer som `useState`, men som leser fra og skriver til `sessionStorage` automatisk. Brukes til både sorteringsvalg og minimumsvurdering, og kan gjenbrukes til andre ting senere ved behov. Lesing og skriving er pakket inn i try/catch i tilfelle storage er utilgjengelig (f.eks. i privat nettlesing), og faller da tilbake til en gitt standardverdi. - - src/utils/sortAndFilterMovies.ts - En ren funksjon uten side-effekter som tar inn en liste med filmer, sorteringsvalg og minimumsvurdering, og returnerer en ny, filtrert og sortert liste. Fordi funksjonen er ren (samme input gir alltid samme output, og den endrer ikke noe utenfor seg selv), er den enkel å enhetsteste isolert med Vitest, uten å måtte mocke React eller komponenter. - - src/components/SortFilterBar.tsx - En liten, selvutviklet komponent (ingen tredjepartsbibliotek for UI, i tråd med kravet) med en nedtrekksmeny for sortering og en range-slider for minimumsvurdering. Komponenten er "dum" — den mottar verdier og callbacks som props, og eier ingen egen state selv. - - Kobling i `App.tsx` - `App.tsx` holder sorterings- og filterverdiene via `useSessionStorage`, og sender dem videre til `SortFilterBar` for visning/endring, samt bruker `sortAndFilterMovies(...)` på filmlistene før de sendes videre til `MovieList`. Dermed gjelder valget uansett hvilken liste som vises (populære, nye filmer eller søk). - - Kjente begrensninger/mulige forbedringer - - Sortering og filtrering kjøres på nytt ved hver rendring. Med dagens datamengde (10–20 filmer) er dette ubetydelig for ytelsen, men kunne vært optimalisert med `useMemo` dersom datamengden økte betydelig. - - Range-slideren for minimumsvurdering kunne fått `aria-valuetext` for bedre skjermleserstøtte (f.eks. "minst 7 av 10" i stedet for kun tallet). - - sessionStorage-nøklene (`sortBy`, `minRating`) er generiske. Ved videre utvikling av appen kan det være lurt å prefikse dem (f.eks. `movieApp:sortBy`) for å unngå navnekollisjon med annen bruk av sessionStorage. - - Bruk av KI - Løsningen (hook, ren funksjon for sortering/filtrering, UI-komponent og kobling i `App.tsx`) ble utviklet i samarbeid med Claude (Anthropic). KI ble brukt til å foreslå arkitektur (separasjon mellom persistens-hook, ren logikk-funksjon og presentasjonskomponent), generere startkode, og til å vurdere om løsningen faktisk dekket prosjektkravene til filtrering/sortering og bruk av Web Storage API. Koden er gjennomgått og forstått av gruppen før den ble tatt i bruk. - -Leona: - Oversikt: Fiks av filtrering/sortering - Problem: Filtrerings- og sorteringskontrollene (dropdown for sortering og slider for min. vurdering) i SortFilterBar oppdaterte state, men påvirket ingen filmlister. Ingenting skjedde når man endret dem. - - Årsak: Funksjonen sortAndFilterMovies (i src/utils/sortAndFilterMovies.ts) fantes, men ble aldri kalt noe sted. Importen av den i App.tsx var kommentert ut i en tidligere commit (f8a0241, "fikset vite.config.js og App.tsx slik at prosjektet bygges"), fordi TypeScript feilet på ubrukt import under bygg. I tillegg ble sortBy/minRating aldri sendt videre fra App.tsx til de tre layout-komponentene som faktisk viser filmlister. - - Løsning: - - Fjernet den utkommenterte importen i src/App.tsx. - sortBy og minRating sendes nå som props fra App.tsx til SearchLayout, MainLayout og FavoritesLayout. - Hver av disse tre komponentene kjører nå sortAndFilterMovies(...) på filmlisten sin før den rendres i MovieList. - Endrede filer: - - src/App.tsx - src/layout/SearchLayout.tsx - src/layout/MainLayout.tsx - src/layout/FavoritesLayout.tsx - Ikke endret: TrendingPreview-banneret i MainLayout (viser trending-filmer uavhengig av filter), samt selve sortAndFilterMovies-logikken (den var allerede korrekt, bare ubrukt). - - Bruk av KI - KI (Claude, Anthropic) ble brukt til å finne årsaken til at filtrerings-/sorteringskontrollene ikke hadde noen effekt: ved å spore koden fant KI at importen av sortAndFilterMovies i App.tsx var kommentert ut (fra en tidligere commit som fikset et build-problem forårsaket av at funksjonen på det tidspunktet var ubrukt), og at sortBy/minRating aldri ble sendt videre til layout-komponentene som faktisk viser filmlister. - - KI ble videre brukt til å implementere fiksen: gjenopprette importen, legge sortBy og minRating til som props på SearchLayout, MainLayout og FavoritesLayout, og kalle sortAndFilterMovies(...) på riktig filmliste i hver av disse komponentene før den sendes til MovieList. - - Løsningen ble verifisert med `tsc --noEmit` og `npm run build` (begge grønne), og gjennomgått og forstått av gruppen før den ble tatt i bruk. - - CSS: - Brukte også claude til å designe CSSen til filter-delen, slik at den matcher med resten av nettsiden. -``` +KI ble også brukt til å: +1. Foreslå lastetilstand ("Laster skuespillere...") mens useMovieCredits henter data, slik at brukeren får tilbakemelding i stedet for et tomt felt +2. Generere responsiv styling i Movie_card.css, inkludert plassering av rating-badge, layout med plakat til venstre/info til høyre, og tilpasning under @media (max-width: 480px) +3. Gjennomgå og forstått av gruppen før den ble tatt i bruk, og tilpasset til resten av prosjektets struktur (bl.a. typene fra types/tmdb.ts). +4. Generere logikken for å bygge full plakat-URL fra TMDB sin poster_path, inkludert fallback til tom streng når poster_path er null (for å unngå en ødelagt bilde-URL som .../w200null) +5. Foreslå omregningen fra TMDB sin vote_average (skala 0–10) til prosent (0–100) som vises i UI +6. Sette opp det responsive grid-oppsettet i MovieList.css (repeat(auto-fill, minmax(320px, 1fr))), som går til én kolonne på mobil \ No newline at end of file From b0ee08cdb9ec3c417273e0f91e561d9a0563035a Mon Sep 17 00:00:00 2001 From: albdert Date: Thu, 17 Sep 2026 15:34:48 +0200 Subject: [PATCH 2/3] ny readme med dokumentasjon --- README.md | 175 ++++++++++++++++++++++++++++++++++++++++++++++++++---- info.txt | 61 +++++++++++++++++++ 2 files changed, 223 insertions(+), 13 deletions(-) create mode 100644 info.txt diff --git a/README.md b/README.md index 26da1f1..b6339e2 100644 --- a/README.md +++ b/README.md @@ -1,37 +1,185 @@ # Dokumentasjon +Prosjektet er live på: [http://it2810-02.idi.ntnu.no/project1/](http://it2810-02.idi.ntnu.no/project1/) + +## Beskrivelse +_Skriv en beskrivelse her_ + +## oppsett +Vi bruker `fnm` med `pnpm`, og `Node.js` v24. + +Installasjon kan gjøres med følgende kommandoer (linux): +``` +# Download and install fnm: +curl -o- https://fnm.vercel.app/install | bash + +# Download and install Node.js: +fnm install 24 + +# Verify the Node.js version: +node -v # Should print "v24.21.0". + +# Download and install pnpm: +corepack enable pnpm + +# Verify pnpm version: +pnpm -v +``` + +#### Kjøre prosjektet lokalt for utvikling +1. Klone github repo til maskinen din +2. gå inn i prosjektmappen (default: T02-Project-1) +3. Kjør kommandoene + - `pnpm install` + - `pnpm run dev` + +#### Bygge prosjektet +Prosjektet kan bygges med kommandoen `pnpm run build`. Dette vil bygge prosjektet og legge det i `/dist` directory under prosjektmappen. + +#### Test prosjektet +Prosjektet kan testes med kommandoen `pnpm test:run`. + +> [!NOTE] +> Prosjektet forventer en api-token i en lokal `.env`-fil. Se _API_-seksjonen under. + +## vm +Prosjektet er hostet på VM hostet på NTNU sine servere. Oppsettet er gjort i henhold til veiledningen "Komme i gang med virtuell maskin (vm)" på [canvas.ntnu.no](canvas.ntnu.no). + +På serveren er det opprettet en `cron job` som kjører hvert minutt som kjører følgende deploy-script: +```bash +#!/bin/bash + +FNM_PATH="/home/albertpl/.local/share/fnm" +export PATH="$FNM_PATH:$PATH" +eval "$(fnm env --shell bash)" + +set -e + +cd /var/www/project + +BEFORE=$(git rev-parse HEAD) + +echo "[$(date)] Pulling latest changes..." +git pull origin main + +AFTER=$(git rev-parse HEAD) + +if [ "$BEFORE" = "$AFTER" ]; then + echo "[$(date)] No changes, skipping build." + exit 0 +fi + +echo "[$(date)] Changes detected ($BEFORE -> $AFTER). Installing dependencies..." +pnpm install + +echo "[$(date)] Building..." +pnpm run build + +echo "[$(date)] Deploy finished." +``` + +Prosjektet ligger lokalt i mappen `/var/www/project/`, og prosjektet som blir bygget ligger i `/var/www/project/dist/`. Webserveren hoster filene direkte fra `dist` directory gjennom en symlink i `/var/www/html/project1/` som peker til `dist` directory. + ## API +Vi bruker The Movie Database (TMDB) sin api i prosjektet vårt. Se tmdb sin egen dokumentasjonen [her](https://developer.themoviedb.org/docs/) -## hooks +#### VITE_TMDB_TOKEN +For autentisering av api-kall mot tmdb sin api kreves det en egen access token. Denne kan etterspørres på under profil-innstillinger på tmdb sin [hjemmeside](https://www.themoviedb.org). -## layout +Etter at man har fyllt ut api-skjema får man to forskjellige API nøkkler: en `API key`, og en `API Read Access Token`. Vi bruker `API Read Access Token`. Denne må kopieres og legges i en lokal `.env.local` fil som skal se slik ut: +``` +VITE_TMDB_TOKEN=[API Read Access Token] +``` -## components +Når man har lagt inn denne skal prosjektet kunne kjøre lokalt, og api-kall skal fungere. -## types +> [!NOTE] +> API token har kun lese-rettigheter, men bør fortsatt ikke være offentlig. +> Filen `.env.local` er derfor lagt til i `.gitignore`. ## testing - -#### MovieCard.tsx + MovieCard.css +_Clemens skriv om testing her_ +_Hva som er testet: hvilke nettlesere, hvilke enheter, og hva de automatiske testene dekker_ + +## prosjektstruktur, komponenter, hooks, layout, types + +`prosjekt/src`-directory structure: +./src +├── App.css +├── App.tsx +├── main.tsx +├── index.css +| +├── api +│   └── tmdb.ts +├── components +│   ├── FavoriteButton.css +│   ├── FavoriteButton.tsx +│   ├── MovieCard.css +│   ├── MovieCard.tsx +│   ├── MovieDetails.css +│   ├── MovieDetails.tsx +│   ├── MovieList.css +│   ├── MovieList.tsx +│   ├── PersonList.tsx +│   ├── SearchField.css +│   ├── SearchField.tsx +│   ├── Section.css +│   ├── Section.tsx +│   ├── Sidebar.css +│   ├── Sidebar.tsx +│   ├── SortFilterBar.css +│   ├── SortFilterBar.tsx +│   ├── TrendingPreview.css +│   └── TrendingPreview.tsx +├── hooks +│   ├── useDebouncedValue.ts +│   ├── useFavorites.ts +│   ├── useMediaQuery.ts +│   ├── useMovieCredits.ts +│   ├── useMovies.ts +│   ├── usePeople.ts +│   └── useSessionStorage.ts +├── layout +│   ├── FavoritesLayout.tsx +│   ├── MainLayout.tsx +│   └── SearchLayout.tsx +├── test +│   └── setup.ts +├── types +│   └── tmdb.ts +└── utils + ├── sortAndFilterMovies.test.ts + └── sortAndFilterMovies.ts + +#### components +###### MovieCard.tsx + MovieCard.css Viser ett enkelt filmkort med plakat, tittel, rating og skuespillere. Tar imot movieId, title, posterUrl og rating som props. Henter skuespillerne selv via useMovieCredits(movieId) og viser en "Laster skuespillere..."-tekst mens det henter. De tre første skuespillerne vises kommaseparert. Ratingen ligger som en badge øverst i høyre hjørne, plakaten til venstre og resten av infoen til høyre – med responsiv styling for mobil (@media max-width: 480px). -#### MovieList.tsx + MovieList.css +###### MovieList.tsx + MovieList.css Tar imot en liste med filmer (movies: Movie[]) og rendrer ett MovieCard per film med .map(). Den vet ingenting om TMDB eller fetching – det ansvaret ligger i hookene og i Section-komponenten (laster/feilhåndtering). Bygger plakat-URL fra TMDB sin poster_path, med fallback til tom streng hvis filmen mangler plakat. Regner om TMDB sin vote_average (0–10) til prosent (0–100). Layouten er et responsivt grid (repeat(auto-fill, minmax(320px, 1fr))) som går til én kolonne på mobil. -#### useMovieCredits.ts +#### hooks +###### useMovieCredits.ts En React Query-hook som henter skuespillerlisten for én bestemt film via fetchMovieCredits i api/tmdb.ts. Caches per movieId i én time (staleTime), slik at samme film ikke hentes på nytt unødvendig når flere kort viser samme data. -#### useSessionStorage.ts +###### useSessionStorage.ts En generisk, gjenbrukbar hook som fungerer som `useState`, men som leser fra og skriver til `sessionStorage` automatisk. Brukes til både sorteringsvalg og minimumsvurdering, og kan gjenbrukes til andre ting senere ved behov. Lesing og skriving er pakket inn i try/catch i tilfelle storage er utilgjengelig (f.eks. i privat nettlesing), og faller da tilbake til en gitt standardverdi. -#### sortAndFilterMovies.ts + +#### layout + +#### types + +###### sortAndFilterMovies.ts En ren funksjon uten side-effekter som tar inn en liste med filmer, sorteringsvalg og minimumsvurdering, og returnerer en ny, filtrert og sortert liste. Fordi funksjonen er ren (samme input gir alltid samme output, og den endrer ikke noe utenfor seg selv), er den enkel å enhetsteste isolert med Vitest, uten å måtte mocke React eller komponenter. -#### SortFilterBar.tsx +###### SortFilterBar.tsx En liten, selvutviklet komponent (ingen tredjepartsbibliotek for UI, i tråd med kravet) med en nedtrekksmeny for sortering og en range-slider for minimumsvurdering. Komponenten er "dum" — den mottar verdier og callbacks som props, og eier ingen egen state selv. -#### Sortering og filtrering +# Vet ikke hvor dette bør stå +## Sortering og filtrering Brukeren kan sortere filmlistene (populære, nye filmer og søkeresultater) etter: - Popularitet (TMDB sin standardrekkefølge) - Vurdering (høyest først) @@ -55,7 +203,8 @@ Kjente begrensninger/mulige forbedringer -#### Bruk av KI +## Bruk av KI +#### Leona KI (Claude, Anthropic) ble brukt til å foreslå strukturen på filmkortet: hvilke props komponenten burde ta imot (movieId, title, posterUrl, rating) versus hva den burde hente selv. Forslaget var at kortet henter skuespillerne sine via useMovieCredits(movieId) internt, i stedet for at forelderen henter og sender ned skuespillerlisten som en egen prop. Dette holder MovieList enkel og fri for ansvar den ikke trenger. KI ble brukt til å foreslå ansvarsdelingen mellom MovieList og resten av appen: MovieList skal kun rendre en liste med MovieCard-komponenter ut fra en ferdig hentet movies-prop, og skal ikke vite noe om TMDB, fetching, lasting eller feilhåndtering — det ansvaret ligger i hookene (useMovies.ts m.fl.) og i Section-komponenten. Denne separasjonen ble foreslått av KI som god praksis for å holde komponentene testbare og gjenbrukbare hver for seg. diff --git a/info.txt b/info.txt new file mode 100644 index 0000000..181feea --- /dev/null +++ b/info.txt @@ -0,0 +1,61 @@ +Kilden min er prosjektbeskrivelsen du limte inn fra Canvas, pluss dokumentasjonskravene du sendte senere. Jeg har ikke tilgang til Canvas selv, så finnes det en egen rubrikk der som ikke står i den teksten, kjenner jeg ikke til den. + +Eksplisitte krav, direkte sitert + +"Dokumentasjon i form av readme på GitHub som dokumenterer og forklarer valg, dokumenterer hva som er testet." +"Ta utgangspunkt i at dokumentasjonen skal være forklarende for medstudenter og nyttig info for den som skal evaluere." +"I starten av readme-fila skal dere legge inn en lenke til webappen som er installert på vm." +"Alle skal dokumentere bruk av KI enten dere har benyttet det eller ikke. Vi er ute etter hvordan dere har brukt KI, og gjerne en oppsummering av erfaringer." + +Vurderingskriterier som treffer README-en + +"Reproduserbarhet: prosjektet skal være dokumentert og enkelt å installere/kjøre for andre (eksempelvis faglærer)." +"God dokumentasjon som forklarer valg og løsninger, husk å dokumentere bruk av KI." + +Punkt 5 er det eneste kriteriet der README-en alene avgjør om dere består det. Får ikke faglærer kjørt prosjektet fra det som står der, er kriteriet ikke innfridd uansett hvor bra koden er. + +Hva det betyr konkret + +VM-lenke helt øverst, før alt annet +Hva appen gjør og hvilket API den bruker +Installasjon som faktisk fungerer for en som aldri har sett repoet: pnpm install, .env.local med VITE_TMDB_TOKEN, hvor man skaffer tokenet, at det må være v4 og ikke v3, pnpm dev +Kommandoene: dev, build, lint, test, format +Hva som er testet: hvilke nettlesere, hvilke enheter, og hva de automatiske testene dekker +Forklaring av valg og løsninger, ikke bare hva som finnes. "Vi bruker sessionStorage til sortering og localStorage til favoritter, fordi kravene beskriver to ulike varigheter" er en forklaring. "Vi bruker Web Storage" er det ikke. +KI-bruk per person, pluss en oppsummering av erfaringer + +Det som ikke er krav nå + +"Dokumentasjonen skal beskrive hva som er forbedret siden første innlevering" gjelder sluttvurderingen i desember, ikke i morgen. + +Alt dette har du tekst til fra tidligere i dag, bortsett fra VM-lenka og lista over nettlesere og enheter dere faktisk har testet påKilden min er prosjektbeskrivelsen du limte inn fra Canvas, pluss dokumentasjonskravene du sendte senere. Jeg har ikke tilgang til Canvas selv, så finnes det en egen rubrikk der som ikke står i den teksten, kjenner jeg ikke til den. + +Eksplisitte krav, direkte sitert + +"Dokumentasjon i form av readme på GitHub som dokumenterer og forklarer valg, dokumenterer hva som er testet." +"Ta utgangspunkt i at dokumentasjonen skal være forklarende for medstudenter og nyttig info for den som skal evaluere." +"I starten av readme-fila skal dere legge inn en lenke til webappen som er installert på vm." +"Alle skal dokumentere bruk av KI enten dere har benyttet det eller ikke. Vi er ute etter hvordan dere har brukt KI, og gjerne en oppsummering av erfaringer." + +Vurderingskriterier som treffer README-en + +"Reproduserbarhet: prosjektet skal være dokumentert og enkelt å installere/kjøre for andre (eksempelvis faglærer)." +"God dokumentasjon som forklarer valg og løsninger, husk å dokumentere bruk av KI." + +Punkt 5 er det eneste kriteriet der README-en alene avgjør om dere består det. Får ikke faglærer kjørt prosjektet fra det som står der, er kriteriet ikke innfridd uansett hvor bra koden er. + +Hva det betyr konkret + +VM-lenke helt øverst, før alt annet +Hva appen gjør og hvilket API den bruker +Installasjon som faktisk fungerer for en som aldri har sett repoet: pnpm install, .env.local med VITE_TMDB_TOKEN, hvor man skaffer tokenet, at det må være v4 og ikke v3, pnpm dev +Kommandoene: dev, build, lint, test, format +Hva som er testet: hvilke nettlesere, hvilke enheter, og hva de automatiske testene dekker +Forklaring av valg og løsninger, ikke bare hva som finnes. "Vi bruker sessionStorage til sortering og localStorage til favoritter, fordi kravene beskriver to ulike varigheter" er en forklaring. "Vi bruker Web Storage" er det ikke. +KI-bruk per person, pluss en oppsummering av erfaringer + +Det som ikke er krav nå + +"Dokumentasjonen skal beskrive hva som er forbedret siden første innlevering" gjelder sluttvurderingen i desember, ikke i morgen. + +Alt dette har du tekst til fra tidligere i dag, bortsett fra VM-lenka og lista over nettlesere og enheter dere faktisk har testet på.. From 78ad41747b2947172faca03428e637a7e85fab9b Mon Sep 17 00:00:00 2001 From: albdert Date: Thu, 17 Sep 2026 15:36:17 +0200 Subject: [PATCH 3/3] fix tree structure --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index b6339e2..9eb7d37 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,7 @@ _Hva som er testet: hvilke nettlesere, hvilke enheter, og hva de automatiske tes ## prosjektstruktur, komponenter, hooks, layout, types `prosjekt/src`-directory structure: +``` ./src ├── App.css ├── App.tsx @@ -152,6 +153,7 @@ _Hva som er testet: hvilke nettlesere, hvilke enheter, og hva de automatiske tes └── utils ├── sortAndFilterMovies.test.ts └── sortAndFilterMovies.ts +``` #### components ###### MovieCard.tsx + MovieCard.css