From 27ecf6b01cded30201972eb21be6795ca92136e1 Mon Sep 17 00:00:00 2001 From: tordtst Date: Wed, 30 Sep 2026 09:39:49 +0200 Subject: [PATCH 1/3] feat(src): definer felles annonsetype og prisformat MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gi alle visninger samme datastruktur og samme visning av pris, kategori og tilstand. Pris er hele kroner per døgn, og 0 vises som «Gratis utlån». Refs #4 Co-Authored-By: birkjr --- src/types/listing.ts | 28 ++++++++++++++++++++++++++++ src/utils/listingFormat.ts | 28 ++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 src/types/listing.ts create mode 100644 src/utils/listingFormat.ts diff --git a/src/types/listing.ts b/src/types/listing.ts new file mode 100644 index 0000000..b8c5abb --- /dev/null +++ b/src/types/listing.ts @@ -0,0 +1,28 @@ +/** + * Felles datatype for en verktøyannonse. + * + * Kategori og tilstand er faste engelske nøkler slik at de senere kan bli + * GraphQL-enums. Norske visningsnavn ligger i utils/listingFormat.ts. + */ + +export type ToolCategory = + 'powerTools' | 'handTools' | 'garden' | 'painting' | 'measuring' | 'cleaning'; + +export type ToolCondition = 'likeNew' | 'good' | 'worn'; + +export interface Listing { + /** Stabil ID. Brukes i URL-er og som React-nøkkel. */ + id: string; + title: string; + category: ToolCategory; + description: string; + /** Bydel eller område i Trondheim, for eksempel «Moholt». */ + area: string; + /** Pris i hele kroner per døgn. 0 betyr gratis utlån. */ + dailyPrice: number; + condition: ToolCondition; + /** Tilbehør som følger med. Tom liste når ingenting følger med. */ + accessories: string[]; + /** Adresse til bilde av verktøyet, eller null når annonsen mangler bilde. */ + imageUrl: string | null; +} diff --git a/src/utils/listingFormat.ts b/src/utils/listingFormat.ts new file mode 100644 index 0000000..6150896 --- /dev/null +++ b/src/utils/listingFormat.ts @@ -0,0 +1,28 @@ +import type { ToolCategory, ToolCondition } from '../types/listing.ts'; + +// Record krever en etikett for hver nøkkel, så TypeScript sier fra hvis en +// ny kategori eller tilstand legges til uten visningsnavn. +export const categoryLabels: Record = { + powerTools: 'Elektroverktøy', + handTools: 'Håndverktøy', + garden: 'Hage', + painting: 'Maling og overflate', + measuring: 'Måleverktøy', + cleaning: 'Rengjøring', +}; + +export const conditionLabels: Record = { + likeNew: 'Som ny', + good: 'God stand', + worn: 'Godt brukt', +}; + +const priceFormatter = new Intl.NumberFormat('nb-NO'); + +/** Viser døgnpris som «150 kr/døgn», eller «Gratis utlån» når prisen er 0. */ +export function formatDailyPrice(dailyPrice: number): string { + if (dailyPrice === 0) { + return 'Gratis utlån'; + } + return `${priceFormatter.format(dailyPrice)} kr/døgn`; +} From 697a1824e683a5371315e82d961bfdd09e859617 Mon Sep 17 00:00:00 2001 From: tordtst Date: Wed, 30 Sep 2026 09:39:49 +0200 Subject: [PATCH 2/3] feat(src): legg til eksempelannonser med illustrasjoner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gi gruppen felles, oppdiktede data å bygge katalog, detaljvisning og skjema på. Dataene dekker gratis og betalt utlån, ulik tekstlengde og annonser uten bilde. Refs #4 Co-Authored-By: sebasti --- src/assets/listings/drill.svg | 11 ++ src/assets/listings/handsaw.svg | 7 ++ src/assets/listings/paint-roller.svg | 6 ++ src/assets/listings/spade.svg | 6 ++ src/data/mockListings.ts | 144 +++++++++++++++++++++++++++ 5 files changed, 174 insertions(+) create mode 100644 src/assets/listings/drill.svg create mode 100644 src/assets/listings/handsaw.svg create mode 100644 src/assets/listings/paint-roller.svg create mode 100644 src/assets/listings/spade.svg create mode 100644 src/data/mockListings.ts diff --git a/src/assets/listings/drill.svg b/src/assets/listings/drill.svg new file mode 100644 index 0000000..6441bbc --- /dev/null +++ b/src/assets/listings/drill.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/listings/handsaw.svg b/src/assets/listings/handsaw.svg new file mode 100644 index 0000000..23f0400 --- /dev/null +++ b/src/assets/listings/handsaw.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/assets/listings/paint-roller.svg b/src/assets/listings/paint-roller.svg new file mode 100644 index 0000000..6d78fe5 --- /dev/null +++ b/src/assets/listings/paint-roller.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/assets/listings/spade.svg b/src/assets/listings/spade.svg new file mode 100644 index 0000000..fe5cec8 --- /dev/null +++ b/src/assets/listings/spade.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/data/mockListings.ts b/src/data/mockListings.ts new file mode 100644 index 0000000..be58e37 --- /dev/null +++ b/src/data/mockListings.ts @@ -0,0 +1,144 @@ +/** + * Oppdiktede eksempelannonser for prototypen. Ingen av annonsene er ekte + * tilbud, og ingen personopplysninger er brukt. Illustrasjonene er laget for + * prosjektet. + * + * Dataene er valgt for å dekke ulike tilfeller i visningene: gratis og betalt + * utlån, korte og lange titler, tomt tilbehør og annonser uten bilde. + * + * Datakilden erstattes senere av GraphQL-backenden. Komponenter bør derfor få + * annonser gjennom props i stedet for å importere denne filen direkte. + */ + +import drillImage from '../assets/listings/drill.svg'; +import handsawImage from '../assets/listings/handsaw.svg'; +import paintRollerImage from '../assets/listings/paint-roller.svg'; +import spadeImage from '../assets/listings/spade.svg'; +import type { Listing } from '../types/listing.ts'; + +export const mockListings: Listing[] = [ + { + id: 'listing-001', + title: 'Drill', + category: 'powerTools', + description: + 'Batteridrill som passer til å skru opp hyller og montere møbler.', + area: 'Moholt', + dailyPrice: 100, + condition: 'good', + accessories: ['2 batterier', 'Lader', 'Bitssett'], + imageUrl: drillImage, + }, + { + id: 'listing-002', + title: 'Slagdrill med borsett for betong og murvegger', + category: 'powerTools', + description: + 'Kraftig slagdrill for boring i betong, mur og tegl. Egner seg til å henge opp tunge hyller, TV-braketter og kjøkkenskap. Borsett fra 6 til 12 mm følger med. Bruk hørselvern ved lengre arbeid.', + area: 'Lade', + dailyPrice: 150, + condition: 'likeNew', + accessories: ['Borsett for betong', 'Koffert', 'Dybdestopper'], + imageUrl: drillImage, + }, + { + id: 'listing-003', + title: 'Fogsvans', + category: 'handTools', + description: 'Vanlig håndsag for tre. Bladet er skarpt.', + area: 'Gløshaugen', + dailyPrice: 0, + condition: 'good', + accessories: [], + imageUrl: handsawImage, + }, + { + id: 'listing-004', + title: 'Verktøykasse med hammer, skrutrekkere og tenger', + category: 'handTools', + description: + 'Grunnleggende verktøy for småreparasjoner i hybelen. Kassen har hammer, flere skrutrekkere, nebbtang, kombinasjonstang og målebånd.', + area: 'Singsaker', + dailyPrice: 50, + condition: 'worn', + accessories: ['Målebånd', 'Unbrakonøkler'], + imageUrl: null, + }, + { + id: 'listing-005', + title: 'Spade', + category: 'garden', + description: 'Solid spade til hagearbeid og planting.', + area: 'Byåsen', + dailyPrice: 0, + condition: 'worn', + accessories: [], + imageUrl: spadeImage, + }, + { + id: 'listing-006', + title: 'Hagespade og rive', + category: 'garden', + description: + 'Spade og rive som lånes ut sammen. Fint til å gjøre klar et lite bed eller rake løv om høsten.', + area: 'Tiller', + dailyPrice: 40, + condition: 'good', + accessories: ['Rive', 'Arbeidshansker'], + imageUrl: spadeImage, + }, + { + id: 'listing-007', + title: 'Malerrulle og brett', + category: 'painting', + description: + 'Rulle og malebrett for vegger. Rullene er vasket og klare til bruk.', + area: 'Møllenberg', + dailyPrice: 0, + condition: 'likeNew', + accessories: ['2 ruller', 'Malebrett', 'Teleskopskaft'], + imageUrl: paintRollerImage, + }, + { + id: 'listing-008', + title: + 'Komplett malersett til en liten leilighet: ruller, pensler, dekkplast og tape', + category: 'painting', + description: + 'Alt du trenger for å male om en hybel eller en liten leilighet, bortsett fra maling. Settet har ruller i to størrelser, pensler til kanter, dekkplast til gulv og møbler og maskeringstape. Rengjør ruller og pensler før levering.', + area: 'Midtbyen', + dailyPrice: 120, + condition: 'good', + accessories: [ + 'Ruller i to størrelser', + '3 pensler', + 'Dekkplast', + 'Maskeringstape', + ], + imageUrl: paintRollerImage, + }, + { + id: 'listing-009', + title: 'Laservater', + category: 'measuring', + description: + 'Krysslaser for å henge bilder og hyller rett. Rekker omtrent 15 meter innendørs.', + area: 'Heimdal', + dailyPrice: 80, + condition: 'likeNew', + accessories: ['Stativ', 'Batterier'], + imageUrl: null, + }, + { + id: 'listing-010', + title: 'Tepperenser', + category: 'cleaning', + description: + 'Rensemaskin for tepper og møbeltrekk. Nyttig ved utflytting. Rensemiddel følger ikke med.', + area: 'Nardo', + dailyPrice: 250, + condition: 'good', + accessories: ['Slange', '2 munnstykker'], + imageUrl: null, + }, +]; From 58cb0a6f133bcbaf7d3c9fc66b7457576aa68c9f Mon Sep 17 00:00:00 2001 From: tordtst Date: Wed, 30 Sep 2026 09:39:49 +0200 Subject: [PATCH 3/3] docs(docs): dokumenter datamodell og mockdata MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Forklar feltene, prisens enhet og hvordan manglende bilde håndteres, slik at alle bruker dataene likt og datakilden senere kan byttes. Refs #4 Co-Authored-By: andretg --- README.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/README.md b/README.md index 6e5364a..f7286ca 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,38 @@ ESLint finner feil i koden, mens Prettier bestemmer formateringen. ESLint-regler som ellers ville kollidert med Prettier. Byggfiler, avhengigheter og `package-lock.json` formateres ikke. +## Datamodell og mockdata + +Alle annonser følger typen `Listing` i `src/types/listing.ts`: + +| Felt | Innhold | +| ------------- | ---------------------------------------------------------- | +| `id` | Stabil ID, for eksempel `listing-001` | +| `title` | Kort tittel | +| `category` | Fast nøkkel, for eksempel `powerTools` | +| `description` | Fritekst | +| `area` | Område i Trondheim, for eksempel «Moholt» | +| `dailyPrice` | Pris i hele kroner per døgn. `0` betyr gratis utlån | +| `condition` | `likeNew`, `good` eller `worn` | +| `accessories` | Liste med tilbehør. Tom liste når ingenting følger med | +| `imageUrl` | Adresse til bilde, eller `null` når annonsen mangler bilde | + +Kategori og tilstand lagres som engelske nøkler slik at de senere kan bli +GraphQL-enums. `src/utils/listingFormat.ts` gir de norske visningsnavnene og +`formatDailyPrice`, som viser `150 kr/døgn` eller `Gratis utlån`. Bruk disse i +stedet for å formatere på nytt i hver komponent. Når `imageUrl` er `null`, skal +visningen vise en nøytral plassholder. + +`src/data/mockListings.ts` har 10 oppdiktede eksempelannonser. De er ikke ekte +tilbud og inneholder ingen personopplysninger. Illustrasjonene i +`src/assets/listings/` er laget for prosjektet. Ekstern datakilde er ikke +valgt. + +Senere skal annonsene hentes fra en egen GraphQL-backend med database +(planlagt, ikke laget). Komponenter bør derfor få annonser gjennom props i +stedet for å importere mockdataene direkte. Da kan datakilden byttes uten at +visningene må skrives om. + ## Working in this repository `main` is protected — you cannot push to it directly. Work on a branch and