From fe69452fa3eb57b9b60aa6402cc75fb74c090b3d Mon Sep 17 00:00:00 2001 From: ellawaal Date: Fri, 18 Sep 2026 14:59:34 +0200 Subject: [PATCH 1/6] Skrevet README med installasjonsinstruksjoner, designvalg, bruk av KI og testdokumentasjon --- README.md | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ece3648..562e31d 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,94 @@ # Prosjekt 1 - Sangtekster -## +**Webapp:** _[Lenke legges til når appen er deployet på VM]_ + +En React-applikasjon for å utforske sanger og sangtekster fra Bonnie Tyler. Brukeren kan filtrere sanger etter album, sortere dem alfabetisk, favorittmerke sanger, og lese sangtekster hentet live fra et eksternt API. + +## Installasjon og kjøring + +### Krav + +- Node.js >= 24.6.0 +- npm >= 11.0.0 + +### Steg + +1. Klon repoet: + + ```bash + git clone git@git.ntnu.no:IT2810-H26/T28-Project-1.git + cd T28-Project-1 + ``` + +2. Installer avhengigheter: + + ```bash + npm install + ``` + +3. Start utviklingsserveren: + + ```bash + npm run dev + ``` + + Appen kjører deretter på `http://localhost:5173`. + +### Andre kommandoer + +| Kommando | Beskrivelse | +| ------------------------ | ------------------------------------------------- | +| `npm run build` | Bygger appen for produksjon (kjører TypeScript-sjekk + Vite build) | +| `npm run preview` | Forhåndsviser produksjonsbygget lokalt | +| `npm run lint` | Kjører ESLint på kodebasen | +| `npm run format` | Formaterer koden med Prettier | +| `npm run format:check` | Sjekker at koden er formatert riktig, uten å endre | +| `npm run test` | Kjører testene med Vitest | + +## Valgt API og designvalg + +### API + +Sangtekster hentes fra [lyrics.ovh](https://lyrics.ovh) sitt gratis, nøkkelfrie API (`https://api.lyrics.ovh/v1/{artist}/{title}`). Det ble valgt fordi det er enkelt å bruke uten autentisering, og dekker sangtekster for de fleste av Bonnie Tylers kjente sanger. Ikke alle sanger finnes i API-et, så appen håndterer dette eksplisitt (se under). + +Kallet gjøres i den egendefinerte hooken `useLyrics` (`src/hooks/useLyrics.ts`), som bruker **TanStack Query** (`useQuery`) til å hente, cache og holde styr på lasting/feiltilstand for hvert API-kall. Sangdataene selv (tittel, artist, album) ligger statisk i `src/data/songs.ts`, siden dette er informasjon som ikke endrer seg og ikke trenger å hentes fra et eksternt API. + +### Designvalg + +- **State løftet opp til `App.tsx`**: All state som flere komponenter er avhengig av (valgt sang, filter, sortering, favoritter) eies av `App.tsx` og sendes ned som props. Dette følger Reacts anbefalte mønster for "lifting state up", og gjør datastrømmen i appen enveis og forutsigbar. +- **Egendefinerte hooks for lagring**: `useLocalStorage` og `useSessionStorage` (`src/hooks/`) er generiske hooks som speiler `useState`s API (`[verdi, settefunksjon]`), men synkroniserer verdien mot nettleserens Web Storage. Favoritter lagres i `localStorage` (skal bestå over tid), mens filter/sortering lagres i `sessionStorage` (skal nullstilles ved ny nettleserøkt). +- **Kontrollerte komponenter**: Filter- og sorteringsvelgerne i `FilterSortBar` er kontrollerte (`value` + `onChange` styrt av state i `App.tsx`), slik at UI alltid reflekterer den faktiske state, ikke DOM-ens interne tilstand. +- **Tydelig separasjon av ansvar**: Presentasjonskomponenter (`SongCard`, `SongList`, `FavoriteButton`, `Navigation`, `FilterSortBar`, `LyricsDisplay`) mottar alt de trenger via props, mens all logikk (filtrering, sortering, favoritt-toggling, API-henting) ligger i `App.tsx` eller i egne hooks/utils. +- **Lasting og feilhåndtering**: `SongCard` viser en lasteindikator mens sangteksten hentes, og en tydelig feilmelding dersom kallet feiler eller sangen ikke finnes i API-et (API-et kan svare med `{ error: ... }` i stedet for tekst). + +## Testing + +Testene kjøres med **Vitest** og **React Testing Library**, og ligger ved siden av filen de tester. + +- `src/test/setup.test.tsx` verifiserer at testoppsettet (Vitest + Testing Library + jsdom) fungerer, ved å rendre en enkel komponent og sjekke at innholdet vises. +- `src/utils/formatLyrics.test.ts` tester `parseLyrics`-funksjonen, som formaterer rå sangtekst fra API-et til strofer/avsnitt. Testen bekrefter at funksjonen korrekt deler opp en sangtekst i flere strofer selv når API-teksten ikke inneholder tomme linjer mellom vers og refreng. + +I tillegg til automatiserte tester er følgende funksjonalitet manuelt testet gjennom utvikling av hvert issue: + +- Filtrering av sanger etter album, og at valget nullstiller riktig sang-indeks +- Sortering av sanger alfabetisk på tittel +- Favorittmerking av sanger, og at valget består ved sideoppdatering (`localStorage`) +- At filter- og sorteringsvalg består ved sideoppdatering, men nullstilles i en ny nettleserøkt (`sessionStorage`) +- Lasteindikator og feilmelding ved henting av sangtekst, inkludert for sanger uten tekst i API-et +- Responsivt layout på mindre skjermstørrelser + +Kjør testene med: + +```bash +npm run test +``` + +## Bruk av KI + +Vi har brukt Claude Code gjennom utviklingen av prosjektet, hovedsakelig som et hjelpemiddel for de gruppemedlemmene uten særlig erfaring med React. + +Vanlig arbeidsflyt har vært at gruppemedlemmet selv skriver kode for en gitt issue, og at KI-en forklarer relevante React-/TypeScript-konsepter, peker på feil og foreslår rettelser, i stedet for å skrive løsningen direkte. Eksempler på dette er implementasjon av filtrering, sortering, favorittfunksjonalitet, `useLocalStorage`/`useSessionStorage`-hooks og håndtering av lasting/feiltilstand ved henting av sangtekster. + +KI er også brukt direkte til enkelte oppgaver som hjelp til løsing av merge-konflikter og oppsett av README.md-filen. + +**Erfaring:** Å bruke KI-en til å forklare og gi tilbakemelding på egenskrevet kode, fremfor å generere den, har gjort det lettere å faktisk forstå konseptene, i stedet for å kopiere en ferdig løsning. KI har også vært nyttig for å raskt diagnostisere problemer som ellers ville tatt lang tid å feilsøke manuelt. From d5967c1f65b1861521015df99e94bc3f0ad7a4cc Mon Sep 17 00:00:00 2001 From: ellawaal Date: Fri, 18 Sep 2026 18:22:20 +0200 Subject: [PATCH 2/6] =?UTF-8?q?husk=20=C3=A5=20legge=20til=20link?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 562e31d..ba59b51 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Prosjekt 1 - Sangtekster -**Webapp:** _[Lenke legges til når appen er deployet på VM]_ +**Webapp:** _[Lenke legges til når appen er deployet på VM!!]_ En React-applikasjon for å utforske sanger og sangtekster fra Bonnie Tyler. Brukeren kan filtrere sanger etter album, sortere dem alfabetisk, favorittmerke sanger, og lese sangtekster hentet live fra et eksternt API. From fa6a9cd3fc7ef18f9d2f835f40f995e8eb6c3681 Mon Sep 17 00:00:00 2001 From: ellawaal Date: Fri, 18 Sep 2026 18:24:58 +0200 Subject: [PATCH 3/6] Fikset build-feil fra merget snapshot-test og lagt til manglende snapshot-fil Fjernet ubrukt React-import i SongCard.test.tsx (stoppet npm run build), og committet den genererte snapshot-filen som manglet fra PR #51. --- src/components/SongCard.test.tsx | 1 - .../__snapshots__/SongCard.test.tsx.snap | 65 +++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 src/components/__snapshots__/SongCard.test.tsx.snap diff --git a/src/components/SongCard.test.tsx b/src/components/SongCard.test.tsx index b04e6f9..e465b83 100644 --- a/src/components/SongCard.test.tsx +++ b/src/components/SongCard.test.tsx @@ -1,4 +1,3 @@ -import React from 'react' import { render } from '@testing-library/react' import { vi, describe, it, expect } from 'vitest' import { SongCard } from './SongCard' diff --git a/src/components/__snapshots__/SongCard.test.tsx.snap b/src/components/__snapshots__/SongCard.test.tsx.snap new file mode 100644 index 0000000..54052fe --- /dev/null +++ b/src/components/__snapshots__/SongCard.test.tsx.snap @@ -0,0 +1,65 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`SongCard > matches snapshot 1`] = ` + +
+

+ Test Title +

+
+
+

+ + Artist + + + Test Artist + +

+

+ + Album + + + Test Album + +

+
+
+
+

+ Tekst +

+
+

+ + Lyrics for Test Artist - Test Title. + +

+
+
+
+
+`; From 7c097fc8f613ed507108b6d373a8d46e510d5cc1 Mon Sep 17 00:00:00 2001 From: ellawaal Date: Fri, 18 Sep 2026 18:25:32 +0200 Subject: [PATCH 4/6] =?UTF-8?q?Fikset=20siste=20ESLint-feil=20(un=C3=B8dve?= =?UTF-8?q?ndig=20escape-tegn=20i=20regex)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/formatLyrics.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/formatLyrics.ts b/src/utils/formatLyrics.ts index 0f6571a..019b904 100644 --- a/src/utils/formatLyrics.ts +++ b/src/utils/formatLyrics.ts @@ -10,7 +10,7 @@ function normalizeLine(line: string): string { return line.toLowerCase().trim() } -const sectionMarker = /^\s*[\[(](?:verse|chorus|bridge|intro|outro|pre-chorus)/i +const sectionMarker = /^\s*[[(](?:verse|chorus|bridge|intro|outro|pre-chorus)/i function stanzasFromBreaks(lines: string[], breaks: Set): LyricsStanza[] { const starts = [...breaks] From d2a426445e7c22e0f482c63a176db26cf513ee51 Mon Sep 17 00:00:00 2001 From: ellawaal Date: Fri, 18 Sep 2026 18:27:10 +0200 Subject: [PATCH 5/6] =?UTF-8?q?Revert=20"Fikset=20siste=20ESLint-feil=20(u?= =?UTF-8?q?n=C3=B8dvendig=20escape-tegn=20i=20regex)"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 7c097fc8f613ed507108b6d373a8d46e510d5cc1. --- src/utils/formatLyrics.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/formatLyrics.ts b/src/utils/formatLyrics.ts index 019b904..0f6571a 100644 --- a/src/utils/formatLyrics.ts +++ b/src/utils/formatLyrics.ts @@ -10,7 +10,7 @@ function normalizeLine(line: string): string { return line.toLowerCase().trim() } -const sectionMarker = /^\s*[[(](?:verse|chorus|bridge|intro|outro|pre-chorus)/i +const sectionMarker = /^\s*[\[(](?:verse|chorus|bridge|intro|outro|pre-chorus)/i function stanzasFromBreaks(lines: string[], breaks: Set): LyricsStanza[] { const starts = [...breaks] From 07b4f71a965e7a6f15295fd90ace6a2557b0d256 Mon Sep 17 00:00:00 2001 From: ellawaal Date: Fri, 18 Sep 2026 18:27:10 +0200 Subject: [PATCH 6/6] Revert "Fikset build-feil fra merget snapshot-test og lagt til manglende snapshot-fil" This reverts commit fa6a9cd3fc7ef18f9d2f835f40f995e8eb6c3681. --- src/components/SongCard.test.tsx | 1 + .../__snapshots__/SongCard.test.tsx.snap | 65 ------------------- 2 files changed, 1 insertion(+), 65 deletions(-) delete mode 100644 src/components/__snapshots__/SongCard.test.tsx.snap diff --git a/src/components/SongCard.test.tsx b/src/components/SongCard.test.tsx index e465b83..b04e6f9 100644 --- a/src/components/SongCard.test.tsx +++ b/src/components/SongCard.test.tsx @@ -1,3 +1,4 @@ +import React from 'react' import { render } from '@testing-library/react' import { vi, describe, it, expect } from 'vitest' import { SongCard } from './SongCard' diff --git a/src/components/__snapshots__/SongCard.test.tsx.snap b/src/components/__snapshots__/SongCard.test.tsx.snap deleted file mode 100644 index 54052fe..0000000 --- a/src/components/__snapshots__/SongCard.test.tsx.snap +++ /dev/null @@ -1,65 +0,0 @@ -// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html - -exports[`SongCard > matches snapshot 1`] = ` - -
-

- Test Title -

-
-
-

- - Artist - - - Test Artist - -

-

- - Album - - - Test Album - -

-
-
-
-

- Tekst -

-
-

- - Lyrics for Test Artist - Test Title. - -

-
-
-
-
-`;