Skip to content
Merged
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
88 changes: 68 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ Prosjektet er live på: [http://it2810-02.idi.ntnu.no/project1/](http://it2810-0

## Beskrivelse

_Skriv en beskrivelse her_
BetterBoxd er en webapp for å utforske filmer. Data hentes fortløpende fra The Movie Database (TMDB) sitt REST-API
Forsiden viser en hero-karusell med trending filmer, og seksjoner for populære og nye filmer. Søkefeltet i menyen søker mens du skriver. Søkeresultatene kan sorteres (popularitet, vurdering, utgivelsesdato, alfabetisk) og filtreres på en minimumsvurdering. Hvert filmkort kan åpnes i en detaljvisning, og markeres som favoritt med hjerteknappen. Favorittene samles på en egen side.

## Table of Contents

Expand Down Expand Up @@ -284,6 +285,18 @@ Grunnen til at den finnes er at MovieList eller har måttet håndtere lasting og

Overskriften rendres bare hvis title faktisk har innhold. Banner-seksjonen øverst sendes inn uten tittel, og uten den sjekken ville den laget en tom `<h2>`. Det er ikke bare stygt da tomme overskrifter havner i overskriftoversikten en skjermleser navigerer etter, og da står det bare "overskrifter" uten noe mer.

###### 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.

##### FavoriteButton.tsx + FavoriteButton.css

Hjerteknappen som markerer en film som favoritt. Eier ingen state selv, men får isFavorite og onToggleFavorite inn som props, slik at samme knapp kan brukes både på filmkortet og i detaljvisning.

###### MovieDetails.tsx + MovieDetails.css

Detaljvisningen som legger seg over siden når man åpner en film. Viser backdrop, tittel, utgivelsesdato, vurdering, sammendrag og skuespillere, og henter skuespillerne via `useMovieCredits` på samme måte som kortet — så cachen deles og det blir ikke et nytt kall.

#### hooks

###### useMovieCredits.ts
Expand All @@ -297,20 +310,40 @@ En generisk, gjenbrukbar hook som fungerer som `useState`, men som leser fra og
###### useMediaQuery.ts

Vil returnere true eller false for en media query, i mine tilfeller var dette ved bruk av (max-width:700px), som lar meg si at hvis noen åpner ned en brudde under 700px så rendre den riktige menyen. useState passer her på at riktig verdi settes før første render, slik at det ikke skal vises feil visning først. useEffect henger på via window.matchMedia, og return funksjonen fjerner lytteren igjen. uten det hoper lytterne seg opp for hver rendring.

Da desktop og mobil har ulik DOM struktur trenger vi dette både i JSX og CSS og ikke bar ei CSS. I desktop som sagt tidligere ligger undermenyen i HOME og på mobil ligger alle fire knappene flatt på bunnen ved siden av hverandre. Dette vil ikke CSS kunne gjøre.


##### useFavorites.ts

Holder lista over favoritt-id-er og lagrer den i localStorage under nøkkelen favorites-movies. Kun id-ene lagres og ikke hele filmobjektet. Dette er fordi at den skal ikke mellomlagre API-data og lagrede filmer kunne blitt utdatert. Lista leses ved første render og en `useEffect` skriver tilbake når den endrer seg.

###### useDebouncedValue.ts

En generisk hook som forsinker en verdi til den har vært uendret i et gitt antall millisekunder. Brukes på søketeksten med 400ms. Hvis denne ikke hadde blitt brukt hadde man sendt et API-kall for hver bokstav man trykker inn. Dette gjør at man kun sender et API-kall, ikke flere.

###### useMovies.ts

Samler alle filmspørringene mot TMDB.øke-spørringen har `enabled: query.trim().length > 0`, slik at et tomt felt ikke gir kall i det hele tatt.Hvert oppslag har sin egen `queryKey` (`['movies', 'detail', id]`), slik at cachen gjenbrukes når man bytter mellom visninger i stedet for at det hentes på nytt.

#### layout

#### types
Layout-komponentene setter sammen seksjoner og bestemmer hva som vises i hovedområdet. `App.tsx` velger mellom dem ut fra tilstand, slik at `App` slipper å inneholde tre ulike JSX-trær.

###### sortAndFilterMovies.ts
###### MainLayout.tsx
Forsiden: hero-karusell med trending filmer, og seksjoner for populære og nye filmer.

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.
###### SearchLayout.tsx
Vises så snart søkefeltet har innhold. Rendrer `SortFilterBar` over søkeresultatene og kjører `sortAndFilterMovies` på treffene før de sendes til `MovieList`.

###### SortFilterBar.tsx
###### FavoritesLayout.tsx
Favorittsiden. Får `favoriteIds` inn og henter filmene på nytt via
`useFavoriteMovies`. Viser "Du har ingen favoritter ennå." når lista er tom, i stedet for en blank side.

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.
#### 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.

# Vet ikke hvor dette bør stå

Expand Down Expand Up @@ -339,7 +372,7 @@ Kjente begrensninger/mulige forbedringer
- 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.

## Responsivt design og tilgjengelighet
## Responsivt design

Sidelayouten er flexbasert. Hovedinnholdet har flex: 2 1 0 og sidekolonnene har fast bredde, slik at innholdet får mest plass uten at menyen blir uleselig bred på store skjermer. min-width: 0 på hovedinnholdet er nødvendig fordi flex-elementer ellers nekter å bli smalere enn innholdet sitt, noe som ga horisontal scrolling ved lange filmtitler.

Expand All @@ -349,14 +382,26 @@ hjemindikatoren på nyere iPhone. Fordi position: fixed tar elementet ut av doku
Detaljvisningen bruker max-height i dvh og ikke vh på mobil. Vanlig vh
regner som om adresselinja i mobilnettleseren ikke finnes, så bunnen av kortet havner utenfor skjermen.

På tilgjengelighet...
## Tilgjengelighet

### Kjente begrensninger
Prinsippet gjennom appen er at alt som kan klikkes på også skal kunnes nå ved tastatur og gi mening for en nettleser. I praksis betyr det at interaktive elementer er
ekte `<button>`-elementer, ikke `<div>` med `onClick`

**Filmkortet** er en `<article>` med tittelen i en `<button>` inni `<h3>`. Knappen har en `::after {inset: 0 }` som gjør at treffområdet trekkes over hele filmkortet ved hjelp av mus. Fokusringen flyttes ut til kortkanten med `:has(...)`, siden en
ring rundt teksten alene ikke viser tydelig hvilket kort som er valgt.

I **Detaljvisningen** blir fokus flyttet inn i dialogen ved åpning, og Escape lukker den slik at den kan lukkes uten mus.
Fokus flyttes inn i dialogen ved åpning og tilbake til kortet den ble åpnet fra ved lukking, og en fokusfelle holder Tab inne i dialogen så lenge den er åpen. Escape lukker, slik at den kan forlates uten mus. `body.modal-open` låser scroll bak overlayet.
Ellers brukes semantiske elementer gjennomgående — `<main>` `<article>` per filmkort og `<h2>`/`<h3>` i riktig rekkefølge — slik at overskriftsnavigasjon i en skjermleser gir en meningsfull struktur.


## Kjente begrensninger

- Breakpointet 700px er definert to steder: som streng i useMediaQuery-kallet og i media queries i CSS. Endres det ene uten det andre, blir DOM-struktur og styling ute av synk.
- padding-bottom på innholdet er hardkodet til høyden på bunnlinja.
- Scroll til seksjon bruker setTimeout(..., 0) for å vente på at seksjonene er rendret etter et visningsbytte. Det fungerer, men er avhengig av timing – en useEffect som kjører når visningen faktisk har endret seg ville vært riktigere.
- Hvert MovieCard gjør sitt eget kall til /credits. Caching på én time gjør at samme film ikke hentes på nytt, men første lasting av forsiden gir ett kall per kort i tillegg til filmlista. En samlet henting ville vært bedre.
- `useFavorites` leser `localStorage` uten `try/catch`, i motsetning til `useSessionStorage`. Er lagret JSON korrupt, eller er storage utilgjengelig (privat nettlesing i enkelte nettlesere), kaster hooken ved første render og hele appen kræsjer. Bør pakkes inn på samme måte som `useSessionStorage`.

## Bruk av KI

Expand All @@ -379,6 +424,18 @@ KI ble også brukt til å:
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

#### Johannes

Jeg har hovedsakelig brukt Claude (Anthropic) gjennom hele prosjektet. Jeg har brukt KI som en støttepartner, i hovedsak til tre ting: å forstå React og tilgjengelighetsmønstre jeg ikke kunne fra før, å feilsøke, og å gå kritisk gjennom kode og dokumentasjon i forhold til kravene. Min bruk av KI så slik ut: Jeg kom med en spesifikk problemstilling som jeg ikke visste hvordan jeg skulle løse, KI kommer med eventuelle løsninger, jeg prøver å skrive koden og teste den før vi eventuelt går videre. Dette gjorde at jeg fikk kontroll over all kode som var lagt til, og dermed hadde jeg forståelse og kunne ta ansvar for hva som hadde blir lagt til.På de delene jeg har hatt hovedansvar for, søk, favoritter og tilgjengelighet, gikk det konkret ut på ting som dette:

- at søket burde ha en debounce slik at det ikke sendes ett API-kall per tastetrykk
- at favoritter hører hjemme i localStorage og ikke sessionStorage fordi de skal overleve at nettleseren lukkes
- at det ikke holdt med en `<div>` for å få fikse tilgjengelighetfunskjon, det måtte være en `<button>`

Erfaringer:

KI var definitivt mest nyttig når jeg hadde et konkret problem og kunne stille et presist spørsmål. Da fikk jeg hjelp til løsning og begrunnelsen på hvorfor, noe som hjalp meg med videre vurdering, da jeg fikk bedre forståelse for det selv. Jeg måtte være veldig tydelig på hvordan jeg ville jobbe. Det var et par ganger da Claude gikk inn og forandret kode selv, noe som jeg ga tilbakemelding på at den ikke skulle. Noe annet som er verdt å merke seg. KI tar seg ofte friheter og kommer med løsninger utover hva du faktisk har spurt den om. Dette kan være bra fordi da kan du vite hva neste steg er, men kan også være veldig irriterende hvis den ikke greier å løse det du egentlig spurte om. All kode er lest gjennom og forstått før den er tatt i bruk, og endringene er testet manuelt.

#### Clemens

Jeg har hovedsakling brukt Claude av Anthropic gjennom prosjektet. Claude har blitt brukt som en veileder og ikke til å generere all koden for meg.
Expand Down Expand Up @@ -406,7 +463,6 @@ Når jeg hadde problemer med min personlige kode, spurte jeg Claude også om å
Det å la KI hjelpe ved lagingen av testene hjalp oss også å finne ekte feil i koden. Vi merket da at MovieList manglet key og MovieCard sender en tom streng som src når en film ikke har plakat. Begge ga advarsler som var nyttige.



#### Albert

Oversikten under er generert av Claude basert på all chat-historikken min fra autust-september (17.09.2026). Utover det Claude har lagt inn i oversikten er KI generelt brukt til feilsøking, forklaring av teknologier vi bruker som react og typescript. I tillegg er KI brukt for å effektivisere enkelte oppgaver slik som å søke gjennom historikk i github, o.l.
Expand All @@ -431,12 +487,4 @@ Dette prosjektet har brukt Claude (Anthropic) som støtte gjennom utviklingspros
**Oppsummert:** KI er brukt til prosjektplanlegging, komponentarkitektur, feilsøking, API-sikkerhet, styling og CI/CD-oppsett. All kode er gjennomgått og forstått før den er tatt i bruk.

**Erfaringer:**
KI var nyttig gjennom hele prosjektet, spesielt til å effektivisere lesing av dokumentasjon — i stedet for å lese gjennom store mengder API- eller bibliotek-dokumentasjon selv, kunne KI raskt oppsummere det som var relevant. Den var også til hjelp for å finne kilder og eksempler på hvordan ting bør gjøres, både i form av beste praksis og alternative løsninger å vurdere. På den tekniske siden ga KI god generell støtte med TypeScript-syntaks (typing, generics, korrekt bruk av interfaces/types), og fungerte som en rask referanse for kommandoer man ellers måtte slått opp (git, npm/pnpm, deploy-relaterte kommandoer). Ved konkret feilsøking — som import-feil i React-komponenter, PATH-problemer i deploy-scriptet, var KI effektiv til å peke ut sannsynlig årsak og forslag til løsning, noe som sparte tid sammenlignet med å feilsøke fra bunnen selv. Samtidig var det nødvendig å alltid kvalitetssikre og teste forslagene selv, siden KI ikke alltid traff riktig på første forsøk og enkelte ganger krevde oppfølgingsspørsmål eller mer kontekst for å komme til en fungerende løsning.

## Template under i tilfelle andre vil ha samme oppsett for KI-bruk

#### [Navn]

| Dato | Oppgave | Hva KI bidro med |
| ---- | ------- | ---------------- |
| | | |
KI var nyttig gjennom hele prosjektet, spesielt til å effektivisere lesing av dokumentasjon — i stedet for å lese gjennom store mengder API- eller bibliotek-dokumentasjon selv, kunne KI raskt oppsummere det som var relevant. Den var også til hjelp for å finne kilder og eksempler på hvordan ting bør gjøres, både i form av beste praksis og alternative løsninger å vurdere. På den tekniske siden ga KI god generell støtte med TypeScript-syntaks (typing, generics, korrekt bruk av interfaces/types), og fungerte som en rask referanse for kommandoer man ellers måtte slått opp (git, npm/pnpm, deploy-relaterte kommandoer). Ved konkret feilsøking — som import-feil i React-komponenter, PATH-problemer i deploy-scriptet, var KI effektiv til å peke ut sannsynlig årsak og forslag til løsning, noe som sparte tid sammenlignet med å feilsøke fra bunnen selv. Samtidig var det nødvendig å alltid kvalitetssikre og teste forslagene selv, siden KI ikke alltid traff riktig på første forsøk og enkelte ganger krevde oppfølgingsspørsmål eller mer kontekst for å komme til en fungerende løsning.