{"id":32439346,"url":"https://github.com/codebloodedmama/j.cc","last_synced_at":"2025-10-26T00:57:38.817Z","repository":{"id":314246013,"uuid":"1048360776","full_name":"CodeBloodedMama/J.CC","owner":"CodeBloodedMama","description":"jysk code case react typescript product chooser og viewer with sorting mekanisms","archived":false,"fork":false,"pushed_at":"2025-09-11T09:28:29.000Z","size":301,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-09-11T12:32:02.391Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/CodeBloodedMama.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-01T10:21:45.000Z","updated_at":"2025-09-11T09:28:32.000Z","dependencies_parsed_at":"2025-09-11T12:42:16.620Z","dependency_job_id":null,"html_url":"https://github.com/CodeBloodedMama/J.CC","commit_stats":null,"previous_names":["codebloodedmama/j.cc"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/CodeBloodedMama/J.CC","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CodeBloodedMama%2FJ.CC","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CodeBloodedMama%2FJ.CC/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CodeBloodedMama%2FJ.CC/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CodeBloodedMama%2FJ.CC/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/CodeBloodedMama","download_url":"https://codeload.github.com/CodeBloodedMama/J.CC/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CodeBloodedMama%2FJ.CC/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":281043398,"owners_count":26434444,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-25T02:00:06.499Z","response_time":81,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-10-26T00:56:41.588Z","updated_at":"2025-10-26T00:57:38.812Z","avatar_url":"https://github.com/CodeBloodedMama.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# JYSK Code Challenge – React + TypeScript\n\n## 🔑 KRAV:\n\nJeg fik til opgave at bygge en SPA, der viser en liste af produkter, giver mulighed for detaljevisning, samt sortering og filtrering.\n\nDenne 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**.\n\n## AGENDA:\n\n- intro\n- overordnet arkitektur ( 3 lag, Gof factory og gof strategy)\n- data håndtering og factory method / factory.ts makeProduct, normalisering af json, clamps, default mm\n- 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\n- sortinger med strategy og stabilesort: ProductStragegies ( nameAZ med local compare, da, numerisk)\n- UI og konsistens: productcard.tsx badges og a11y, status visning, pages mm\n\n## 🎯 Features\n\n- Produkter indlæses fra `public/products.json` (møbel- og boligvarer).\n- Liste + detaljevisning af produkter.\n- **Søgning + filtrering** (kategori, pris min–max, kun på lager).\n- **Strategy-baseret sortering** (pris ↑/↓, nyeste/ældste, navn A→Å/Å→A, rating).\n- **Factory Method** sikrer konsistente domæneobjekter (normalisering/validering).\n- **Separat .css** styling pr. komponent, responsivt grid, mobil-først.\n- CRUD-design via et repository-interface (C/U/D simuleret i localStorage).\n\n---\n\n## 🏗 Arkitektur\n\n### Tre-lags struktur: UI, logic(domain) og data(services)\n\n1. **Presentation (UI)**\n   - Komponenter: `ProductListPage`, `ProductDetailPage`, `ProductCard`, `Toolbar`.\n   - Ansvar: loader componenter, viser data og udsender events.\n   - CSS i egne `.css` filer, responsivt layout og a11y.\n\n2. **Application (use case)**\n   - `useProducts` hook: indlæser produkter, holder state (søgeord, filtre, sortering), håndterer UI-tilstande (_Loading/Ready/Empty/Error_).\n   - Orkestrerer flow uden at kende implementeringen af datalaget.\n\n3. **Data Access (Repository)**\n   - `ProductRepository` interface (Query/Command).\n   - `JsonProductRepository` implementering → læser `products.json` og simulerer CRUD via localStorage.\n   - Let at udskifte til REST/Firebase senere.\n\n---\n\n## ⚙️ Designprincipper\n\n### SOLID\n\n- **SRP**: UI viser, Application orkestrerer, Repository henter, Domain bestemmer regler.\n- **OCP**: Nye sorteringer/filtre tilføjes som strategier/specs uden at ændre eksisterende kode.\n- **LIP**: Repository-implementeringer kan udskiftes uden at ændre Application/UI.\n- **ISP**: Interface Segregation → Query og Command adskilt.\n- **DIP**: Application afhænger af abstraktioner (repo, strategier), ikke `fetch`.\n\n### GoF Patterns\n\n- **Factory Method** → `makeProduct` sikrer validerede, konsistente `Product` objekter fra rå JSON.\n- **Strategy** → `productSortStrategies` + `stableSort` giver fleksibel, stabil sortering.\n- **State (konceptuelt)** → UI-tilstande _Loading/Ready/Empty/Error_.\n\n---\n\n## ✅ Valg\n\n- **React + TypeScript** → krav og god type-sikkerhed.\n- **Tre-lags SPA** → lav kobling, høj samhørighed, let at teste.\n- **Strategy til sortering** → OCP, stabilitet og udvidelsesmuligheder.\n- **Factory Method** → data altid konsistente (pris ≥ 0, rating clamp, parse dato).\n- **.css pr. komponent** → enkelt, responsivt, uden at trække store styling-frameworks ind.\n- **Local state (ingen URL-sync)** → simpelt design, godt til code challenge scope.\n- **CRUD-interface** selvom casen kun kræver read → viser design for skalering.\n\n---\n\n## 🚫 Fravalg\n\n- **Ingen global state manager (Redux/Context)** → unødigt tungt til lille case.\n- **Ingen URL-sync** → lavere kompleksitet; trade-off: man kan ikke dele filtre via link.\n- **Ingen SSR (Next.js)** → overkill til 3–4 timers SPA og uden for boundary af krav\n- **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.\n\n---\n\n## 📈 Robusthed, performance \u0026 skalering\n\n- **Robusthed** → Factory validerer data, UI håndterer tom-/fejltilstande. Forhindre NaN og andre trælse pitfalls når JSON bliver product object\n- **Performance** → Debounce på søgning, memoiseret filtrering/sortering, stabil sort.\n- **Skalering** → Let at skifte datakilde (REST/Firebase) eller flytte sort/filtre server-side.\n- **Tilgængelighed** → kontrast, `:focus-visible`, labels/aria, tastaturnavigation.\n\n---\n\n## ⚠️ Pitfalls \u0026 løsninger\n\n- **Ustabil sortering** → løst med `stableSort` (DecorateSortUndecorate).\n- **Inkonsekvent JSON** → løst med `makeProduct` normalisering.\n- **God-komponenter** → undgået ved at lade UI være “dumt” og logik i Application.\n- **Interface-bloat** → delt repo i Query/Command.\n- **Manglende UI-tilstande** → Loading/Empty/Error altid synlige.\n\n---\n\n## 🚀 Kørsel\n\n```bash\nnpm install\nnpm run start\n```\n\n# åbner på port 5173 http://localhost:5173\n\n---\n\n## 🧪 Test\n\njeg har lavet unit og integrationstest og sat en pipeline op til CI/CD på github Actions.\nSe githubActions for test pipe.\n\n```bash\nnpm test\n```\n\n```bash\n-----------------------|---------|----------|---------|---------|----------------------\nFile                   | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s\n-----------------------|---------|----------|---------|---------|----------------------\nAll files              |   97.61 |    81.57 |   96.42 |   97.36 |\n application           |   96.29 |        0 |     100 |   96.15 |\n  useProducts.ts       |   96.29 |        0 |     100 |   96.15 | 29\n domain                |     100 |    86.95 |     100 |     100 |\n  factory.ts           |     100 |    78.57 |     100 |     100 | 20-21,23,29,34,44-63\n  filtering.ts         |     100 |      100 |     100 |     100 |\n domain/sorting        |      95 |    92.85 |   92.85 |   94.73 |\n  productStrategies.ts |   92.85 |    91.66 |      90 |    92.3 | 52\n  strategy.ts          |     100 |      100 |     100 |     100 |\n-----------------------|---------|----------|---------|---------|----------------------\n\nTest Suites: 5 passed, 5 total\nTests:       17 passed, 17 total\nSnapshots:   0 total\nTime:        30.938 s\n```\n\n- **integrationstest** ad useProducts.ts som simulerer hele ux: indlæsning af produkter, sortering og visning af kategori.\n- mocking aaf data som gør testen uafhængig af eksterne faktorer\n- **unit test** af filter, sort, strategi\n\n## 📎 Appendix: Kode-ankre (fil + linjer)\n\n- **useProducts.ts** – UI-tilstande **[8–11]** · load/fejl **[19–28]** · kategorier **[32–38]** · pipeline **[40–44]**\n- **ProductListPage.tsx** – status **[13–17]** · tom-tilstand **[15–25]** · grid/nav **[39–45]**\n- **ProductDetailPage.tsx** – load/fejl **[13–23]** · dato **[42]** · optionals **[43–49]**\n- **factory.ts** – normalisering **[8–16]** · helpers (nederst)\n- **types.ts** – `Product`/`SortKey`/`Filters` (hele filen)\n- **ProductRepository.ts** – interfaces (hele filen)\n- **JsonProductRepository.ts** – `loadOverrides()` **[8–12]** · `list()` **[15–26]** · `get()` (efter `list`)\n- **filtering.ts** – AND-logik + `q` (hele filen)\n- **productStrategies.ts** – `priceAsc/priceDesc`, `nameAZ/nameZA`, `newest/oldest`, `ratingDesc` (entries)\n- **strategy.ts** – `stableSort` (hele filen)\n- **Toolbar.tsx** – debounce **[27–38]** · manuel søgning **[41–48]** · “ryd filtre” **[124–133]**\n- **ProductCard.tsx** – a11y **[7–15]** · badges **[24–33]**\n\n---\n\n## 🧭 Videre arbejde\n\n- **URL-synk** af filtre/sort (shareable links)\n- **Web Worker** for søgning ved store datasæt; **server-side** filter/sort + pagination\n- **Virtuel liste** (react-window) ved mange elementer\n- **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.\n- **søge og sort strategier** kan tilføjes for yderligere ønsker.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodebloodedmama%2Fj.cc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcodebloodedmama%2Fj.cc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodebloodedmama%2Fj.cc/lists"}