An open API service indexing awesome lists of open source software.

https://github.com/codebloodedmama/j.cc

jysk code case react typescript product chooser og viewer with sorting mekanisms
https://github.com/codebloodedmama/j.cc

Last synced: 8 months ago
JSON representation

jysk code case react typescript product chooser og viewer with sorting mekanisms

Awesome Lists containing this project

README

          

# JYSK Code Challenge – React + TypeScript

## 🔑 KRAV:

Jeg fik til opgave at bygge en SPA, der viser en liste af produkter, giver mulighed for detaljevisning, samt sortering og filtrering.

Denne applikation er en **Single Page Application (SPA)** i **React + TypeScript**, der indlæser produkter fra en JSON-kilde, viser en **produktliste** og en **detaljevisning**, samt understøtter **søgning, filtrering og sortering**. Løsningen er designet med fokus på **arkitektur, kvalitet, robusthed, performance og skalerbarhed**.

## AGENDA:

- intro
- overordnet arkitektur ( 3 lag, Gof factory og gof strategy)
- data håndtering og factory method / factory.ts makeProduct, normalisering af json, clamps, default mm
- filtering og søgning ( applyFilters i filtering.ts), UI får valide data, q søgning substring på tværs af felter, debounce 250 ms
- sortinger med strategy og stabilesort: ProductStragegies ( nameAZ med local compare, da, numerisk)
- UI og konsistens: productcard.tsx badges og a11y, status visning, pages mm

## 🎯 Features

- Produkter indlæses fra `public/products.json` (møbel- og boligvarer).
- Liste + detaljevisning af produkter.
- **Søgning + filtrering** (kategori, pris min–max, kun på lager).
- **Strategy-baseret sortering** (pris ↑/↓, nyeste/ældste, navn A→Å/Å→A, rating).
- **Factory Method** sikrer konsistente domæneobjekter (normalisering/validering).
- **Separat .css** styling pr. komponent, responsivt grid, mobil-først.
- CRUD-design via et repository-interface (C/U/D simuleret i localStorage).

---

## 🏗 Arkitektur

### Tre-lags struktur: UI, logic(domain) og data(services)

1. **Presentation (UI)**
- Komponenter: `ProductListPage`, `ProductDetailPage`, `ProductCard`, `Toolbar`.
- Ansvar: loader componenter, viser data og udsender events.
- CSS i egne `.css` filer, responsivt layout og a11y.

2. **Application (use case)**
- `useProducts` hook: indlæser produkter, holder state (søgeord, filtre, sortering), håndterer UI-tilstande (_Loading/Ready/Empty/Error_).
- Orkestrerer flow uden at kende implementeringen af datalaget.

3. **Data Access (Repository)**
- `ProductRepository` interface (Query/Command).
- `JsonProductRepository` implementering → læser `products.json` og simulerer CRUD via localStorage.
- Let at udskifte til REST/Firebase senere.

---

## ⚙️ Designprincipper

### SOLID

- **SRP**: UI viser, Application orkestrerer, Repository henter, Domain bestemmer regler.
- **OCP**: Nye sorteringer/filtre tilføjes som strategier/specs uden at ændre eksisterende kode.
- **LIP**: Repository-implementeringer kan udskiftes uden at ændre Application/UI.
- **ISP**: Interface Segregation → Query og Command adskilt.
- **DIP**: Application afhænger af abstraktioner (repo, strategier), ikke `fetch`.

### GoF Patterns

- **Factory Method** → `makeProduct` sikrer validerede, konsistente `Product` objekter fra rå JSON.
- **Strategy** → `productSortStrategies` + `stableSort` giver fleksibel, stabil sortering.
- **State (konceptuelt)** → UI-tilstande _Loading/Ready/Empty/Error_.

---

## ✅ Valg

- **React + TypeScript** → krav og god type-sikkerhed.
- **Tre-lags SPA** → lav kobling, høj samhørighed, let at teste.
- **Strategy til sortering** → OCP, stabilitet og udvidelsesmuligheder.
- **Factory Method** → data altid konsistente (pris ≥ 0, rating clamp, parse dato).
- **.css pr. komponent** → enkelt, responsivt, uden at trække store styling-frameworks ind.
- **Local state (ingen URL-sync)** → simpelt design, godt til code challenge scope.
- **CRUD-interface** selvom casen kun kræver read → viser design for skalering.

---

## 🚫 Fravalg

- **Ingen global state manager (Redux/Context)** → unødigt tungt til lille case.
- **Ingen URL-sync** → lavere kompleksitet; trade-off: man kan ikke dele filtre via link.
- **Ingen SSR (Next.js)** → overkill til 3–4 timers SPA og uden for boundary af krav
- **Ingen styling frameworks (Tailwind, MUI)** → holder løsningen ren , fokus på arkitektur. Stylet i ren CSS og pages renderes grid hvori der bliver placeret UI komponenter i pages.

---

## 📈 Robusthed, performance & skalering

- **Robusthed** → Factory validerer data, UI håndterer tom-/fejltilstande. Forhindre NaN og andre trælse pitfalls når JSON bliver product object
- **Performance** → Debounce på søgning, memoiseret filtrering/sortering, stabil sort.
- **Skalering** → Let at skifte datakilde (REST/Firebase) eller flytte sort/filtre server-side.
- **Tilgængelighed** → kontrast, `:focus-visible`, labels/aria, tastaturnavigation.

---

## ⚠️ Pitfalls & løsninger

- **Ustabil sortering** → løst med `stableSort` (DecorateSortUndecorate).
- **Inkonsekvent JSON** → løst med `makeProduct` normalisering.
- **God-komponenter** → undgået ved at lade UI være “dumt” og logik i Application.
- **Interface-bloat** → delt repo i Query/Command.
- **Manglende UI-tilstande** → Loading/Empty/Error altid synlige.

---

## 🚀 Kørsel

```bash
npm install
npm run start
```

# åbner på port 5173 http://localhost:5173

---

## 🧪 Test

jeg har lavet unit og integrationstest og sat en pipeline op til CI/CD på github Actions.
Se githubActions for test pipe.

```bash
npm test
```

```bash
-----------------------|---------|----------|---------|---------|----------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
-----------------------|---------|----------|---------|---------|----------------------
All files | 97.61 | 81.57 | 96.42 | 97.36 |
application | 96.29 | 0 | 100 | 96.15 |
useProducts.ts | 96.29 | 0 | 100 | 96.15 | 29
domain | 100 | 86.95 | 100 | 100 |
factory.ts | 100 | 78.57 | 100 | 100 | 20-21,23,29,34,44-63
filtering.ts | 100 | 100 | 100 | 100 |
domain/sorting | 95 | 92.85 | 92.85 | 94.73 |
productStrategies.ts | 92.85 | 91.66 | 90 | 92.3 | 52
strategy.ts | 100 | 100 | 100 | 100 |
-----------------------|---------|----------|---------|---------|----------------------

Test Suites: 5 passed, 5 total
Tests: 17 passed, 17 total
Snapshots: 0 total
Time: 30.938 s
```

- **integrationstest** ad useProducts.ts som simulerer hele ux: indlæsning af produkter, sortering og visning af kategori.
- mocking aaf data som gør testen uafhængig af eksterne faktorer
- **unit test** af filter, sort, strategi

## 📎 Appendix: Kode-ankre (fil + linjer)

- **useProducts.ts** – UI-tilstande **[8–11]** · load/fejl **[19–28]** · kategorier **[32–38]** · pipeline **[40–44]**
- **ProductListPage.tsx** – status **[13–17]** · tom-tilstand **[15–25]** · grid/nav **[39–45]**
- **ProductDetailPage.tsx** – load/fejl **[13–23]** · dato **[42]** · optionals **[43–49]**
- **factory.ts** – normalisering **[8–16]** · helpers (nederst)
- **types.ts** – `Product`/`SortKey`/`Filters` (hele filen)
- **ProductRepository.ts** – interfaces (hele filen)
- **JsonProductRepository.ts** – `loadOverrides()` **[8–12]** · `list()` **[15–26]** · `get()` (efter `list`)
- **filtering.ts** – AND-logik + `q` (hele filen)
- **productStrategies.ts** – `priceAsc/priceDesc`, `nameAZ/nameZA`, `newest/oldest`, `ratingDesc` (entries)
- **strategy.ts** – `stableSort` (hele filen)
- **Toolbar.tsx** – debounce **[27–38]** · manuel søgning **[41–48]** · “ryd filtre” **[124–133]**
- **ProductCard.tsx** – a11y **[7–15]** · badges **[24–33]**

---

## 🧭 Videre arbejde

- **URL-synk** af filtre/sort (shareable links)
- **Web Worker** for søgning ved store datasæt; **server-side** filter/sort + pagination
- **Virtuel liste** (react-window) ved mange elementer
- **lazy Loading** lazy loading af unødvendige komponenter ved at wrappe dem i suspence så de først bliver loaded når de bliver kaldt.
- **søge og sort strategier** kan tilføjes for yderligere ønsker.