mirror of
https://github.com/Dvorinka/MyClubServer.git
synced 2026-06-03 18:22:57 +00:00
dev day #92
This commit is contained in:
@@ -0,0 +1,215 @@
|
||||
# Stav projektu – kontrolní seznam
|
||||
|
||||
Aktualizováno: 2025-11-10
|
||||
|
||||
Legenda:
|
||||
- [x] hotovo / funguje
|
||||
- [ ] k opravě / k doplnění
|
||||
|
||||
---
|
||||
|
||||
## Přehled priorit (P1 = kritické)
|
||||
- [x] P1: Komentáře
|
||||
- [x] Backend panic (regex v spam filtru) – odstraněny backreference v Go regex, nahrazeno kontrolou opakování
|
||||
- [x] Komentáře se nezobrazují (admin i frontend)
|
||||
- [x] P1: Scoreboard Remote
|
||||
- [x] 415 (Unsupported Media Type) – sjednocen Content-Type pro timer endpointy
|
||||
- [x] CORS pro `/api/v1/admin/scoreboard/*`
|
||||
- [x] Časovač – ověřit start/stop a další akce
|
||||
- [x] P1: Články
|
||||
- [x] Auto-save vrací 400 (validace payloadu)
|
||||
- [x] Vazba na soutěž (alias) – výběr aliasu nevrací zápasy
|
||||
- [x] P1: Ankety – tvorba/napojení OK (Aktivity i Články)
|
||||
- [x] P1: Frontend chyby „toLowerCase of undefined“
|
||||
- [x] Admin Hráči
|
||||
- [x] Admin Články
|
||||
|
||||
---
|
||||
|
||||
## Admin
|
||||
- **Nástěnka**
|
||||
- [x] plně funkční
|
||||
|
||||
- **Analytika**
|
||||
- [x] plně funkční
|
||||
|
||||
- **Týmy**
|
||||
- [x] Opravit overrides loga + zkrácené názvy s tečkami
|
||||
- [x] Normalizace názvů (ignorovat tečky/mezery, např. „Frýdlant n. O.“, „Frenštát p. R.“)
|
||||
- [x] Deduplikace výsledků vyhledávání FAČR (opakované položky)
|
||||
- [x] Přidat/ověřit overrides v `team_logo_overrides.json`
|
||||
- [x] 1. BFK Frýdlant n. O. – URL: http://logoapi.sportcreative.eu/logos/35e4f595-f2a7-4c0c-abd7-73926f33d687?format=png
|
||||
- [x] SK Beskyd Frenštát p. R. – URL: http://logoapi.sportcreative.eu/logos/831702b0-cf90-4d94-9878-b1389b6a72b4?format=png
|
||||
- [x] Zajistit propagaci do veřejné části (zápasy, tabule, soupisky)
|
||||
|
||||
- **Zápasy**
|
||||
- [x] plně funkční
|
||||
|
||||
- **Hráči**
|
||||
- [x] Odstranit národnost a věk z homepage i z /hraci
|
||||
- [x] Opravit chybu „toLowerCase of undefined“ (bezpečné zacházení s prázdnými poli ve filtrech/tabulce)
|
||||
|
||||
- **Aliasy soutěží**
|
||||
- [x] Odebrat UI „Přidat nový alias“ (pouze číst z FAČR)
|
||||
|
||||
- **Tabule (Scoreboard)**
|
||||
- [x] Odstranit `:before` pilulku z bloku týmu (viz `<div class="chakra-stack css-whwp7v">...`)
|
||||
- [x] Sjednotit vzhled overlay pro sponzory a skóre se scoreboardem
|
||||
|
||||
- **Scoreboard Remote**
|
||||
- [x] Opravit CORS pro `/api/v1/admin/scoreboard/*`
|
||||
- [x] 415 – sjednotit Content-Type (u timer endpointů povolen POST bez JSON)
|
||||
- [x] Ověřit start/stop timeru a ostatní akce
|
||||
|
||||
- **Články**
|
||||
- [x] Kategorie (soutěž) – po výběru aliasu nevrací zápasy
|
||||
- [x] Rich text editor – „addRange()“/výběr; stabilizovat editaci
|
||||
- [x] Auto-save 400 (validace payloadu, povolená pole, příznaky publikace)
|
||||
- [x] Detail článku (veřejná část):
|
||||
- [x] Pravý sloupec – nadcházející zápasy dle kategorie
|
||||
- [x] Video – skrýt název (ponechat pouze video)
|
||||
- [x] Galerie – zobrazit
|
||||
- [x] Ankety – zobrazit
|
||||
- [x] Komentáře – zobrazit
|
||||
|
||||
- **Aktivity**
|
||||
- [x] plně funkční
|
||||
|
||||
- **Ankety**
|
||||
- [x] Vytváření/napojení ankety (v Aktivitách i v Článcích)
|
||||
- [x] Zajistit plně funkční styly/varianty a zobrazení (admin i public)
|
||||
|
||||
- **Kategorie**
|
||||
- [x] plně funkční
|
||||
|
||||
- **Komentáře**
|
||||
- [x] Backend panic v regex (spam filtr) – odstraněny backreference v Go regex, nahrazeno kontrolou opakování
|
||||
- [x] Komentáře se nezobrazují v adminu ani na frontendu
|
||||
|
||||
- **Videa**
|
||||
- [x] Povolit přepis názvu videa (override) – zobrazit v adminu i na frontendu
|
||||
- [x] Na frontendu potlačit titulek tam, kde je požadováno (např. v detailu článku)
|
||||
|
||||
- **Galerie**
|
||||
- [x] Přidat tlačítko pro přidání dalšího alba (napojit na fetch endpointy)
|
||||
|
||||
- **Soubory**
|
||||
- [x] Změnit defaultní kvótu úložiště na 5 GB (z 1 GB)
|
||||
|
||||
- **Zprávy (Kontakty)**
|
||||
- [x] /kontakt – po odeslání končí na „loading“, přitom zpráva přijde
|
||||
- [x] /sponzori – duplicity zpráv; chybné označení zdroje (kontakt vs sponzoři)
|
||||
- [x] Automatické přeposílání – neprobíhá; opravit trigger/retry
|
||||
|
||||
- **Newsletter**
|
||||
- [x] Auto-aktivace všech typů newsletteru, pokud existuje alespoň 1 aktivní odběratel
|
||||
- [x] Opravit 500 na `POST /api/v1/admin/newsletter/send-digest`
|
||||
|
||||
- **Kontakty (admin – Kontakty tab)**
|
||||
- [x] „Přidat kontakt“ – dropdown Kategorie je prázdný; doplnit soutěže a aliasy (stejně jako v Článcích)
|
||||
|
||||
- **Sponzoři**
|
||||
- [x] plně funkční
|
||||
|
||||
- **Bannery**
|
||||
- [x] plně funkční
|
||||
|
||||
- **Oblečení**
|
||||
- [x] plně funkční
|
||||
|
||||
- **Soutěže (Sweepstakes)**
|
||||
- [x] „Počet výherců“ – zlepšit zadávání (volné psaní, validace), přidat rate limit na max. výherce
|
||||
- [x] „Souhrn výher“ → nahradit „Přidat výhry“ s presety pro rychlé přidání položek
|
||||
- [x] Odebrat „Vstupné (Kč)“ (používáme body)
|
||||
- [x] Nahrání titulního obrázku – 400 při create; opravit upload a validaci
|
||||
|
||||
- **Odměny & Úspěchy**
|
||||
- [x] Zlepšit UI/UX; na frontendu skrýt pro roli admin (ponechat pro běžné uživatele)
|
||||
- [ ] Ověřit kompletní tok (uplatnění, upload avataru, dostupnost odměn)
|
||||
|
||||
- **Zkrácené odkazy**
|
||||
- [x] plně funkční
|
||||
|
||||
- **Prefetch & Cache**
|
||||
- [x] plně funkční
|
||||
|
||||
- **Nastavení**
|
||||
- [x] Odebrat kartu „Monitoring“ (je automatická, ne-admin)
|
||||
|
||||
- **Uživatelé**
|
||||
- [x] Přeložit celé UI do češtiny (lista, popup vytvoření uživatele atd.)
|
||||
- [x] Role „editor“ = omezený admin bez 403 (tvorba/úprava obsahu, bez plných práv)
|
||||
|
||||
- **Navigace (Admin)**
|
||||
- [x] Skrytá položka má zůstat viditelná v adminu pro opětovné zobrazení
|
||||
- [x] Přesun mezi kategoriemi (drag & drop) – musí fungovat i napříč kategoriemi
|
||||
- [x] „Upravit“ – správný cíl (neplést podkategorii/page s hlavní kategorií)
|
||||
|
||||
- **Dokumentace**
|
||||
- [x] plně funkční
|
||||
|
||||
- **Odhlásit se**
|
||||
- [x] plně funkční
|
||||
|
||||
---
|
||||
|
||||
## Veřejná část (frontend)
|
||||
- **Homepage / Hráči**
|
||||
- [x] Odebrat národnost a věk z dlaždic hráčů
|
||||
|
||||
- **Detail článku**
|
||||
- [x] Pravý sloupec: nadcházející zápasy dle kategorie
|
||||
- [x] Video bez titulku (ponechat pouze video prvek)
|
||||
- [x] Galerie, Ankety, Komentáře – zobrazit, když jsou k dispozici
|
||||
|
||||
- **/hraci (seznam)**
|
||||
- [x] Odebrat národnost ze seznamu
|
||||
|
||||
---
|
||||
|
||||
## Backend & API
|
||||
- **Komentáře – chyba (fatal)**
|
||||
- [x] Oprava regexu ve spam filtru: `invalid escape sequence: \1` – nahrazeno kontrolou opakování bez backreferencí (Go nepodporuje backreference)
|
||||
- [x] Stabilizovat vytváření komentářů + návrat do adminu/frontendu
|
||||
|
||||
- **Scoreboard Remote – CORS/415**
|
||||
- [x] Přidat CORS hlavičky pro admin remote endpoints
|
||||
- [x] Ujednotit Content-Type (server akceptuje POST bez JSON pro timer akce)
|
||||
|
||||
- **Články – 400 Bad Request (auto-save)**
|
||||
- [x] Zkontrolovat požadovaný payload na backendu (políčka `published`, `slug`, `youtube_*`, `attachments` atp.)
|
||||
- [x] Sladit validaci se skutečným JSONem z frontendu
|
||||
|
||||
- **Newsletter – 500 na send-digest**
|
||||
- [x] Logy, validace šablon a vstupů; graceful error + retry
|
||||
- [x] Auto-aktivace typů při existenci odběratelů
|
||||
|
||||
- **Kontakty**
|
||||
- [x] Odlišit zdroj (kontakt vs sponzoři) v uložených zprávách
|
||||
- [x] Opravit duplicity a loading stav po submitu
|
||||
- [x] Zajistit automatické přeposílání (resend) dle nastavení
|
||||
|
||||
- **Soutěže (upload)**
|
||||
- [x] Opravit create 400 (multipart/form-data nebo JSON + upload pipeline)
|
||||
|
||||
---
|
||||
|
||||
## Zachycené chyby (výňatek)
|
||||
- Backend fatal (POST /api/v1/comments):
|
||||
- `regexp: Compile(([a-zA-Z!?.])\1{4,}): invalid escape sequence: \1` → upravit regex a ošetření
|
||||
- Frontend (Admin Hráči, Admin Články):
|
||||
- `Cannot read properties of undefined (reading 'toLowerCase')` → bezpečné mapování/filtrace
|
||||
- Scoreboard Remote:
|
||||
- CORS blokace + `415 Unsupported Media Type` při `POST /api/v1/admin/scoreboard/timer/start`
|
||||
- Články – editor/autosave:
|
||||
- `addRange(): The given range isn't in document.` (výběr v editoru)
|
||||
- `PUT /api/v1/articles/:id` → 400 (Bad Request)
|
||||
- Newsletter:
|
||||
- `POST /api/v1/admin/newsletter/send-digest` → 500
|
||||
|
||||
---
|
||||
|
||||
## Poznámky k implementaci
|
||||
- Úpravy názvů týmů s tečkami: vytvořit normalizační vrstvu (strip teček, diakritika, mezery) pro porovnávání i při zápisu overrides.
|
||||
- UI skrytí prvků (aliasy soutěží, monitoring v Nastavení) řešit podmíněným renderem i na úrovni backend schématu/feature flagu.
|
||||
- Před nasazením spustit integrační testy: komentáře, ankety, články (autosave), scoreboard remote, newsletter digest.
|
||||
+198
-313
@@ -1,315 +1,200 @@
|
||||
# 📚 Documentation Index
|
||||
|
||||
This folder contains all documentation for the Fotbal Club CMS project.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Quick Start Guides
|
||||
|
||||
### Essential Setup
|
||||
- **[README](../README.md)** - Main project README (in root)
|
||||
- **[DOKUMENTACE.md](./DOKUMENTACE.md)** - Complete Czech documentation (100KB+)
|
||||
- **[QUICK_START_10_10.md](./QUICK_START_10_10.md)** - Quick start guide
|
||||
- **[SETUP_SIMPLIFIED.md](./SETUP_SIMPLIFIED.md)** - Simplified setup instructions
|
||||
|
||||
### Admin & Editor
|
||||
- **[ADMIN_QUICK_START.md](./ADMIN_QUICK_START.md)** - Admin panel quick start
|
||||
- **[ALL_PAGES_QUICK_START.md](./ALL_PAGES_QUICK_START.md)** - All pages overview
|
||||
- **[QUICK_START_VISUAL_EDITOR.md](./QUICK_START_VISUAL_EDITOR.md)** - Visual editor quick start
|
||||
|
||||
---
|
||||
|
||||
## 🎨 MyUIbrix Visual Editor
|
||||
|
||||
### Core Documentation
|
||||
- **[MYUIBRIX_BRANDING.md](./MYUIBRIX_BRANDING.md)** - Branding & naming
|
||||
- **[MYUIBRIX_IMPROVEMENTS.md](./MYUIBRIX_IMPROVEMENTS.md)** - Feature improvements
|
||||
- **[MYUIBRIX_ENHANCEMENTS.md](./MYUIBRIX_ENHANCEMENTS.md)** - Enhanced features
|
||||
- **[MYUIBRIX_PREVIEW_MODE.md](./MYUIBRIX_PREVIEW_MODE.md)** - Preview mode
|
||||
- **[MYUIBRIX_CSS_ARCHITECTURE.md](./MYUIBRIX_CSS_ARCHITECTURE.md)** - CSS & styling guide
|
||||
|
||||
### ⭐ Elementor Features (NEW!)
|
||||
- **[MYUIBRIX_ELEMENTOR_FEATURES.md](./MYUIBRIX_ELEMENTOR_FEATURES.md)** - Complete Elementor-style features
|
||||
- **[MYUIBRIX_ENHANCEMENT_SUMMARY.md](./MYUIBRIX_ENHANCEMENT_SUMMARY.md)** - Implementation summary
|
||||
- **[MYUIBRIX_QUICK_START.md](./MYUIBRIX_QUICK_START.md)** - Quick start guide (Elementor Edition)
|
||||
- **[INTEGRATION_GUIDE.md](./INTEGRATION_GUIDE.md)** - Component integration guide
|
||||
- **[CSS_CLASSES_REFERENCE.md](./CSS_CLASSES_REFERENCE.md)** - Complete CSS classes reference
|
||||
|
||||
### Elementor/Visual Builder (Legacy)
|
||||
- **[ELEMENTOR_COMPLETE_GUIDE.md](./ELEMENTOR_COMPLETE_GUIDE.md)** - Complete guide
|
||||
- **[ELEMENTOR_QUICK_START.md](./ELEMENTOR_QUICK_START.md)** - Quick start
|
||||
- **[ELEMENTOR_FINAL_GUIDE.md](./ELEMENTOR_FINAL_GUIDE.md)** - Final guide
|
||||
- **[ELEMENTOR_SUMMARY.md](./ELEMENTOR_SUMMARY.md)** - Summary
|
||||
- **[VISUAL_ELEMENT_EDITOR.md](./VISUAL_ELEMENT_EDITOR.md)** - Element editor
|
||||
|
||||
### Editor Features
|
||||
- **[EDITOR_MIGRATION_COMPLETE.md](./EDITOR_MIGRATION_COMPLETE.md)** - Migration guide
|
||||
- **[EDITOR_USER_GUIDE.md](./EDITOR_USER_GUIDE.md)** - User guide
|
||||
- **[CUSTOM_EDITOR_ENHANCEMENT.md](./CUSTOM_EDITOR_ENHANCEMENT.md)** - Enhancements
|
||||
- **[ENHANCED_EDITOR_FEATURES.md](./ENHANCED_EDITOR_FEATURES.md)** - Enhanced features
|
||||
- **[RICH_TEXT_EDITOR_IMPLEMENTATION.md](./RICH_TEXT_EDITOR_IMPLEMENTATION.md)** - Rich text editor
|
||||
# Fotbal Club – systém pro správu klubu
|
||||
|
||||
Moderní systém pro správu fotbalového klubu postavený na Go (Gin, GORM, PostgreSQL) a Reactu (Chakra UI, React Router, React Query).
|
||||
|
||||
## ✨ Funkce
|
||||
|
||||
- 🔐 Přihlášení pomocí JWT a role (admin/editor)
|
||||
- 📝 Články (blog) s kategoriemi, publikací, nahráváním obrázků
|
||||
- 🖼️ Bezpečné nahrávání souborů s kontrolou typu a velikosti
|
||||
- ⚽ Správa týmů a hráčů
|
||||
- 📅 Zápasy a tabulky s integrací FACR (cache, aliasy soutěží, override názvů/log)
|
||||
- 💼 Sponzoři a bannery
|
||||
- 📧 Kontaktní formulář s e‑mailovými notifikacemi
|
||||
- 🚀 REST API (připraveno pro Swagger)
|
||||
- 🐳 Docker pro snadný vývoj a nasazení
|
||||
- 🔄 Automatické migrace DB a seed dat
|
||||
- 🖥️ Moderní, responzivní frontend v češtině
|
||||
- 🍪 Lišta cookies s kategoriemi (nezbytné, preference, analytické, marketingové)
|
||||
|
||||
## 🚀 Rychlý start
|
||||
|
||||
### Předpoklady
|
||||
|
||||
- [Docker](https://docs.docker.com/get-docker/)
|
||||
- [Docker Compose](https://docs.docker.com/compose/install/)
|
||||
|
||||
### Spuštění přes Docker
|
||||
|
||||
1) Klonujte repozitář:
|
||||
```bash
|
||||
git clone <repository-url>
|
||||
cd fotbal-club
|
||||
```
|
||||
|
||||
2) Spusťte aplikaci:
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
Spustí se backend API, databáze PostgreSQL, proběhnou migrace a nastartuje frontend.
|
||||
|
||||
3) Přístup do aplikace:
|
||||
- Frontend: http://localhost:3000
|
||||
- Backend API: http://localhost:8080
|
||||
- Swagger (pokud povolíte): http://localhost:8080/swagger/index.html
|
||||
|
||||
4) První spuštění:
|
||||
- Otevřete http://localhost:3000 – budete přesměrováni na průvodce nastavením (vytvoření admin účtu, nastavení klubu a barev).
|
||||
|
||||
## 📂 Struktura projektu
|
||||
|
||||
```
|
||||
fotbal-club/
|
||||
├── frontend/ # React frontend
|
||||
├── internal/ # Backend
|
||||
│ ├── config/ # Konfigurace
|
||||
│ ├── controllers/ # HTTP kontrolery
|
||||
│ ├── middleware/ # Middleware (auth, admin)
|
||||
│ └── models/ # DB modely
|
||||
├── pkg/ # Znovupoužitelné balíčky (logger, utils)
|
||||
├── database/ # Migrace
|
||||
├── uploads/ # Nahrané soubory
|
||||
├── cache/ # Cache (prefetch)
|
||||
├── static/ # Statická aktiva
|
||||
├── docker-compose.yml # Docker Compose
|
||||
└── main.go # Vstupní bod aplikace
|
||||
```
|
||||
|
||||
## 🔧 Konfigurace
|
||||
|
||||
Zkopírujte `.env.example` na `.env` a upravte:
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
Klíčové proměnné:
|
||||
- `JWT_SECRET` – tajný klíč pro JWT (změňte pro produkci)
|
||||
- `DATABASE_URL` – připojení na PostgreSQL
|
||||
- `UPLOAD_DIR` – cílová složka pro uploady (výchozí `./uploads`)
|
||||
- `MAX_UPLOAD_SIZE` – max. velikost souboru v bajtech
|
||||
- `ALLOWED_ORIGINS` – povolené originy pro CORS (čárkou oddělené)
|
||||
- `CONTACT_EMAIL`, `ADMIN_EMAIL`, `SMTP_*` – e‑mailová konfigurace
|
||||
|
||||
Frontend (`frontend/.env`):
|
||||
- `REACT_APP_API_URL` – např. `http://localhost:8080/api/v1`
|
||||
- `REACT_APP_API_BASE_URL` – alternativa (bez `/api`), např. `http://localhost:8080` (frontend automaticky připojí `/api/v1`)
|
||||
- `REACT_APP_FACR_API_BASE_URL` – výchozí `http://localhost:8080/api/facr`
|
||||
- `REACT_APP_FACR_CACHE_TTL` – TTL cache v ms (výchozí 3600000)
|
||||
|
||||
Poznámky k API URL na frontendu:
|
||||
|
||||
- Pokud zadáte pouze origin (např. `REACT_APP_API_BASE_URL=http://localhost:8080`), klient `frontend/src/services/api.ts` automaticky doplní suffix `/api/v1`.
|
||||
- Při běhu přes Docker Compose se SPA vykresluje v prohlížeči hostitele. Proto musí být URL k backendu prohlížečem dosažitelná (použijte `http://localhost:8080`, nikoli název kontejneru jako `http://backend:8080`).
|
||||
|
||||
## 🛠 Lokální vývoj (bez Dockeru)
|
||||
|
||||
1) Závislosti backendu:
|
||||
```bash
|
||||
go mod download
|
||||
```
|
||||
|
||||
2) Migrace a seed:
|
||||
```bash
|
||||
make migrate
|
||||
make seed
|
||||
```
|
||||
|
||||
3) Backend:
|
||||
```bash
|
||||
make run
|
||||
```
|
||||
|
||||
4) Frontend:
|
||||
```bash
|
||||
cd frontend
|
||||
npm install
|
||||
npm start
|
||||
```
|
||||
|
||||
## 🔒 Bezpečnost a zásady
|
||||
|
||||
- Backend přidává hlavičky (CSP, X-Content-Type-Options, X-Frame-Options, Referrer-Policy).
|
||||
- JWT token je očekáván v `Authorization: Bearer <token>`.
|
||||
- Middleware `JWTAuth` ověřuje token, načte uživatele a ukládá do kontextu `user`, `userID`, `userRole` a `claims`.
|
||||
- Upload endpoint validuje MIME typy a velikost souboru; obrázky JPEG/PNG se komprimují.
|
||||
- Lišta cookies umožňuje volbu kategorií; rozhodnutí je uloženo v `localStorage` pod klíčem `cookie_consent` a vyvolá událost `cookie-consent-change`.
|
||||
|
||||
## 🧭 Frontend – hlavní části
|
||||
|
||||
- Veřejné stránky: `Home`, `Blog`, `Článek`, `O klubu`, `Kalendář`, `Tabulky`, `Sponzoři`, `Kontakt`, právní stránky.
|
||||
- Admin: přístup přes `/admin` (chráněno), layout s postranním menu, hlavičkou a pomocníkem.
|
||||
- Na stránce `Admin Dashboard` je vložena komponenta `AdminHelp` s rychlými tipy.
|
||||
|
||||
## 🧪 Testování
|
||||
|
||||
```bash
|
||||
make test
|
||||
```
|
||||
|
||||
Krytí:
|
||||
```bash
|
||||
go test -coverprofile=coverage.out ./... && go tool cover -html=coverage.out
|
||||
```
|
||||
|
||||
## 🚀 Nasazení
|
||||
|
||||
### Build Docker image
|
||||
```bash
|
||||
docker build -t fotbal-club .
|
||||
```
|
||||
|
||||
### Spuštění kontejneru
|
||||
```bash
|
||||
docker run -d \
|
||||
--name fotbal-club \
|
||||
-p 8080:8080 \
|
||||
--env-file .env \
|
||||
fotbal-club
|
||||
```
|
||||
|
||||
Nahrané soubory jsou servírovány z `/uploads` (viz `main.go`).
|
||||
|
||||
## 📚 API
|
||||
|
||||
Základní přehled viz `DOCS/api.md`. Po zapnutí Swaggeru:
|
||||
- Swagger UI: http://localhost:8080/swagger/index.html
|
||||
- OpenAPI JSON: http://localhost:8080/swagger/doc.json
|
||||
|
||||
## 📖 Dokumentace
|
||||
|
||||
Veškerá dokumentace projektu byla přesunuta do složky **`DOCS/`** pro lepší organizaci.
|
||||
|
||||
**Hlavní dokumenty:**
|
||||
- **[DOCS/DOKUMENTACE.md](./DOCS/DOKUMENTACE.md)** - Kompletní česká dokumentace (100KB+)
|
||||
- **[DOCS/README.md](./DOCS/README.md)** - Index všech dokumentů s kategoriemi
|
||||
- **[DOCS/QUICK_START_10_10.md](./DOCS/QUICK_START_10_10.md)** - Rychlý start
|
||||
|
||||
**Kategorie dokumentace:**
|
||||
- 🎨 MyUIbrix Visual Editor (Elementor)
|
||||
- ⚽ Sparta Elements (nové!)
|
||||
- 🗺️ Mapy a lokace
|
||||
- 🧭 Navigační systém
|
||||
- 📊 Analytika & tracking
|
||||
- 📰 Správa obsahu
|
||||
- 🎟️ Aktivity & události
|
||||
- ⚽ Zápasy & týmy
|
||||
- 📧 Newsletter
|
||||
- 📞 Kontakty
|
||||
- 🎨 Sponzoři & bannery
|
||||
- 📊 Ankety
|
||||
- 🔧 Admin & systém
|
||||
- 🚀 Performance & zabezpečení
|
||||
|
||||
---
|
||||
Více informací v **[DOCS/README.md](./DOCS/README.md)**
|
||||
|
||||
## 📄 Licence
|
||||
|
||||
MIT – viz soubor [LICENSE](LICENSE).
|
||||
|
||||
## ⚽ Sparta Elements (New!)
|
||||
|
||||
- **[SPARTA_ELEMENTS_IMPLEMENTATION_SUMMARY.md](./SPARTA_ELEMENTS_IMPLEMENTATION_SUMMARY.md)** - Implementation guide
|
||||
- **[REC_TO_MYUIBRIX_CONVERSION.md](./REC_TO_MYUIBRIX_CONVERSION.md)** - Conversion from rec directory
|
||||
|
||||
---
|
||||
|
||||
## 🗺️ Maps & Location
|
||||
|
||||
- **[MAP_IMPORT_COMPLETE_IMPLEMENTATION.md](./MAP_IMPORT_COMPLETE_IMPLEMENTATION.md)** - Map import feature
|
||||
- **[QUICK_START_MAP_IMPORT.md](./QUICK_START_MAP_IMPORT.md)** - Quick start
|
||||
- **[MAPS_IMPLEMENTATION_SUMMARY.md](./MAPS_IMPLEMENTATION_SUMMARY.md)** - Implementation summary
|
||||
- **[MAP_LINK_IMPORT_FEATURE.md](./MAP_LINK_IMPORT_FEATURE.md)** - Link import
|
||||
- **[MAP_SETUP_ENHANCEMENTS.md](./MAP_SETUP_ENHANCEMENTS.md)** - Setup enhancements
|
||||
- **[MAP_STYLES_QUICK_REFERENCE.md](./MAP_STYLES_QUICK_REFERENCE.md)** - Styles reference
|
||||
- **[MAPS_LOCATION_AND_COLORS.md](./MAPS_LOCATION_AND_COLORS.md)** - Location & colors
|
||||
- **[VECTOR_MAPS_IMPLEMENTATION.md](./VECTOR_MAPS_IMPLEMENTATION.md)** - Vector maps
|
||||
- **[VECTOR_MAPS_QUICK_START.md](./VECTOR_MAPS_QUICK_START.md)** - Vector maps quick start
|
||||
- **[ENHANCED_MAP_IMPLEMENTATION.md](./ENHANCED_MAP_IMPLEMENTATION.md)** - Enhanced maps
|
||||
|
||||
---
|
||||
|
||||
## 🧭 Navigation System
|
||||
|
||||
- **[NAVIGATION_COMPLETE.md](./NAVIGATION_COMPLETE.md)** - Complete navigation
|
||||
- **[NAVIGATION_QUICK_START.md](./NAVIGATION_QUICK_START.md)** - Quick start
|
||||
- **[NAVIGATION_SYSTEM.md](./NAVIGATION_SYSTEM.md)** - System overview
|
||||
- **[NAVIGATION_MANAGEMENT_SYSTEM.md](./NAVIGATION_MANAGEMENT_SYSTEM.md)** - Management
|
||||
- **[NAVIGATION_IMPLEMENTATION_SUMMARY.md](./NAVIGATION_IMPLEMENTATION_SUMMARY.md)** - Implementation
|
||||
- **[NAVIGATION_FIX_SUMMARY.md](./NAVIGATION_FIX_SUMMARY.md)** - Fixes
|
||||
- **[NAVIGATION_TROUBLESHOOTING.md](./NAVIGATION_TROUBLESHOOTING.md)** - Troubleshooting
|
||||
- **[NAVIGATION_QUICK_FIX.md](./NAVIGATION_QUICK_FIX.md)** - Quick fixes
|
||||
- **[ENHANCED_NAVIGATION_SYSTEM.md](./ENHANCED_NAVIGATION_SYSTEM.md)** - Enhanced system
|
||||
- **[SPLIT_NAVIGATION_GUIDE.md](./SPLIT_NAVIGATION_GUIDE.md)** - Split navigation
|
||||
|
||||
---
|
||||
|
||||
## 📊 Analytics & Tracking
|
||||
|
||||
- **[QUICK_START_ANALYTICS.md](./QUICK_START_ANALYTICS.md)** - Quick start
|
||||
- **[ANALYTICS_INTEGRATION.md](./ANALYTICS_INTEGRATION.md)** - Integration guide
|
||||
- **[ANALYTICS_IMPROVEMENTS_SUMMARY.md](./ANALYTICS_IMPROVEMENTS_SUMMARY.md)** - Improvements
|
||||
- **[ANALYTICS_DASHBOARD_FIX.md](./ANALYTICS_DASHBOARD_FIX.md)** - Dashboard fixes
|
||||
- **[ANALYTICS_FIX.md](./ANALYTICS_FIX.md)** - General fixes
|
||||
- **[ANALYTICS_GRAPH_FIX.md](./ANALYTICS_GRAPH_FIX.md)** - Graph fixes
|
||||
- **[ANALYTICS_MAP_ENHANCEMENTS.md](./ANALYTICS_MAP_ENHANCEMENTS.md)** - Map analytics
|
||||
- **[ANALYTICS_TEST_INSTRUCTIONS.md](./ANALYTICS_TEST_INSTRUCTIONS.md)** - Testing
|
||||
- **[TRACKING_IMPLEMENTATION_GUIDE.md](./TRACKING_IMPLEMENTATION_GUIDE.md)** - Tracking
|
||||
|
||||
### Umami Analytics
|
||||
- **[UMAMI_INTEGRATION.md](./UMAMI_INTEGRATION.md)** - Integration
|
||||
- **[UMAMI_SETUP_WITH_CLUB_NAME.md](./UMAMI_SETUP_WITH_CLUB_NAME.md)** - Setup
|
||||
- **[UMAMI_ADMIN_EXCLUSION.md](./UMAMI_ADMIN_EXCLUSION.md)** - Admin exclusion
|
||||
- **[UMAMI_DEBUG.md](./UMAMI_DEBUG.md)** - Debugging
|
||||
- **[UMAMI_WEBSITE_CREATION_FIX.md](./UMAMI_WEBSITE_CREATION_FIX.md)** - Website creation
|
||||
- **[Umami-docs.md](./Umami-docs.md)** - Full docs
|
||||
|
||||
---
|
||||
|
||||
## 📰 Content Management
|
||||
|
||||
### Articles & Blog
|
||||
- **[ARTICLE_QUICK_FIX_GUIDE.md](./ARTICLE_QUICK_FIX_GUIDE.md)** - Quick fixes
|
||||
- **[ARTICLE_SYSTEM_FIXES_SUMMARY.md](./ARTICLE_SYSTEM_FIXES_SUMMARY.md)** - System fixes
|
||||
- **[BLOG_SYSTEM_FIXES_SUMMARY.md](./BLOG_SYSTEM_FIXES_SUMMARY.md)** - Blog fixes
|
||||
|
||||
### Gallery & Media
|
||||
- **[GALLERY_SYSTEM_IMPLEMENTATION.md](./GALLERY_SYSTEM_IMPLEMENTATION.md)** - Gallery system
|
||||
- **[GALLERY_ADMIN_FIX.md](./GALLERY_ADMIN_FIX.md)** - Admin fixes
|
||||
- **[ZONERAMA_GALLERY_IMPLEMENTATION.md](./ZONERAMA_GALLERY_IMPLEMENTATION.md)** - Zonerama
|
||||
- **[ZONERAMA_GALLERY_FIX.md](./ZONERAMA_GALLERY_FIX.md)** - Zonerama fixes
|
||||
- **[album-api.md](./album-api.md)** - Album API
|
||||
|
||||
### Videos
|
||||
- **[VIDEO_ENHANCEMENTS.md](./VIDEO_ENHANCEMENTS.md)** - Video enhancements
|
||||
- **[YOUTUBE_CLUB_VIDEOS_INTEGRATION.md](./YOUTUBE_CLUB_VIDEOS_INTEGRATION.md)** - YouTube integration
|
||||
- **[ACTIVITY_RICH_EDITOR_YOUTUBE.md](./ACTIVITY_RICH_EDITOR_YOUTUBE.md)** - YouTube in editor
|
||||
|
||||
---
|
||||
|
||||
## 🎟️ Activities & Events
|
||||
|
||||
- **[ACTIVITIES_FIXES_SUMMARY.md](./ACTIVITIES_FIXES_SUMMARY.md)** - Fixes summary
|
||||
- **[ACTIVITY_ADMIN_MAP_ENHANCEMENT.md](./ACTIVITY_ADMIN_MAP_ENHANCEMENT.md)** - Map enhancement
|
||||
- **[event.md](./event.md)** - Event documentation
|
||||
|
||||
---
|
||||
|
||||
## ⚽ Matches & Teams
|
||||
|
||||
- **[MATCHES_ENHANCEMENTS_SUMMARY.md](./MATCHES_ENHANCEMENTS_SUMMARY.md)** - Enhancements
|
||||
- **[MATCHES_PAGE_ENHANCEMENTS.md](./MATCHES_PAGE_ENHANCEMENTS.md)** - Page enhancements
|
||||
- **[FINISHED_MATCHES_DISPLAY_FEATURE.md](./FINISHED_MATCHES_DISPLAY_FEATURE.md)** - Finished matches
|
||||
- **[PLAYER_NATIONALITY_TRANSLATIONS.md](./PLAYER_NATIONALITY_TRANSLATIONS.md)** - Player translations
|
||||
|
||||
---
|
||||
|
||||
## 🏪 E-commerce & Merchandise
|
||||
|
||||
- **[CLOTHING_SYSTEM_IMPLEMENTATION.md](./CLOTHING_SYSTEM_IMPLEMENTATION.md)** - Clothing system
|
||||
|
||||
---
|
||||
|
||||
## 📧 Newsletter & Communication
|
||||
|
||||
- **[NEWSLETTER_SYSTEM.md](./NEWSLETTER_SYSTEM.md)** - System overview
|
||||
- **[NEWSLETTER_IMPLEMENTATION_SUMMARY.md](./NEWSLETTER_IMPLEMENTATION_SUMMARY.md)** - Implementation
|
||||
- **[NEWSLETTER_FEATURE_CHECKLIST.md](./NEWSLETTER_FEATURE_CHECKLIST.md)** - Feature checklist
|
||||
- **[NEWSLETTER_TESTING_GUIDE.md](./NEWSLETTER_TESTING_GUIDE.md)** - Testing guide
|
||||
- **[SMTP_AUTH_FIX.md](./SMTP_AUTH_FIX.md)** - SMTP authentication
|
||||
- **[EMAIL_LOGO_FIX.md](./EMAIL_LOGO_FIX.md)** - Email logo fix
|
||||
|
||||
---
|
||||
|
||||
## 📞 Contact Management
|
||||
|
||||
- **[CONTACT_MANAGEMENT.md](./CONTACT_MANAGEMENT.md)** - Management system
|
||||
- **[CONTACT_MANAGEMENT_IMPLEMENTATION.md](./CONTACT_MANAGEMENT_IMPLEMENTATION.md)** - Implementation
|
||||
- **[CONTACT_MANAGEMENT_FIXES.md](./CONTACT_MANAGEMENT_FIXES.md)** - Fixes
|
||||
- **[CONTACT_SYSTEM_FIX.md](./CONTACT_SYSTEM_FIX.md)** - System fixes
|
||||
- **[CONTACTS_ADMIN_FIXES.md](./CONTACTS_ADMIN_FIXES.md)** - Admin fixes
|
||||
|
||||
---
|
||||
|
||||
## 🎨 Sponsors & Banners
|
||||
|
||||
- **[BANNERY_NAVOD.md](./BANNERY_NAVOD.md)** - Banner guide (Czech)
|
||||
- **[BANNER_SYSTEM_DOCUMENTATION.md](./BANNER_SYSTEM_DOCUMENTATION.md)** - Documentation
|
||||
- **[BANNER_SYSTEM_SUMMARY.md](./BANNER_SYSTEM_SUMMARY.md)** - Summary
|
||||
- **[SPONSOR_CATEGORY_FIX.md](./SPONSOR_CATEGORY_FIX.md)** - Category fixes
|
||||
|
||||
---
|
||||
|
||||
## 📊 Polls & Voting
|
||||
|
||||
- **[POLL_SYSTEM_COMPLETE.md](./POLL_SYSTEM_COMPLETE.md)** - Complete system
|
||||
- **[POLL_SYSTEM_IMPLEMENTATION.md](./POLL_SYSTEM_IMPLEMENTATION.md)** - Implementation
|
||||
- **[POLL_INTEGRATION_GUIDE.md](./POLL_INTEGRATION_GUIDE.md)** - Integration
|
||||
- **[POLL_QUICK_START.md](./POLL_QUICK_START.md)** - Quick start
|
||||
|
||||
---
|
||||
|
||||
## 🏢 Club Branding & Logos
|
||||
|
||||
- **[CLUB_LOGOS_MODAL_INTEGRATION.md](./CLUB_LOGOS_MODAL_INTEGRATION.md)** - Logo modal
|
||||
- **[CLUB_MODAL_IMPLEMENTATION.md](./CLUB_MODAL_IMPLEMENTATION.md)** - Modal implementation
|
||||
- **[LOGO_API_IMPLEMENTATION.md](./LOGO_API_IMPLEMENTATION.md)** - Logo API
|
||||
- **[LOGO_ENHANCEMENT_SUMMARY.md](./LOGO_ENHANCEMENT_SUMMARY.md)** - Enhancements
|
||||
- **[LOGO_SIZING_FIX.md](./LOGO_SIZING_FIX.md)** - Sizing fixes
|
||||
- **[SLIDER_AND_LOGO_FIXES.md](./SLIDER_AND_LOGO_FIXES.md)** - Slider & logo fixes
|
||||
- **[MYCLUB_REBRANDING.md](./MYCLUB_REBRANDING.md)** - MyClub branding
|
||||
|
||||
---
|
||||
|
||||
## 🎨 Design & Styling
|
||||
|
||||
- **[STYLE_PREVIEW_IMAGES.md](./STYLE_PREVIEW_IMAGES.md)** - Style previews
|
||||
- **[DARK_MODE_ENHANCEMENTS.md](./DARK_MODE_ENHANCEMENTS.md)** - Dark mode
|
||||
- **[TYPOGRAPHY_AND_DARKMODE_ENHANCEMENTS.md](./TYPOGRAPHY_AND_DARKMODE_ENHANCEMENTS.md)** - Typography
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Admin & System
|
||||
|
||||
### Admin Panel
|
||||
- **[ADMIN_FUNCTIONALITY_REPORT.md](./ADMIN_FUNCTIONALITY_REPORT.md)** - Functionality report
|
||||
- **[ADMIN_TROUBLESHOOTING.md](./ADMIN_TROUBLESHOOTING.md)** - Troubleshooting
|
||||
|
||||
### ⭐ Developer Documentation (NEW!)
|
||||
- **[DOCS_API_ROUTES.md](./DOCS_API_ROUTES.md)** - Documentation API routes
|
||||
- **[COMPLETE_IMPLEMENTATION_SUMMARY.md](./COMPLETE_IMPLEMENTATION_SUMMARY.md)** - Complete implementation summary
|
||||
- **Admin Docs Viewer** - Available at `/admin/docs` in the admin panel
|
||||
|
||||
### Files Management
|
||||
- **[FILES_MANAGEMENT_SYSTEM.md](./FILES_MANAGEMENT_SYSTEM.md)** - File system
|
||||
- **[FILES_MANAGEMENT_TESTING.md](./FILES_MANAGEMENT_TESTING.md)** - Testing
|
||||
- **[FILE_MANAGEMENT_ENHANCEMENTS.md](./FILE_MANAGEMENT_ENHANCEMENTS.md)** - Enhancements
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Performance & Security
|
||||
|
||||
- **[PERFORMANCE_OPTIMIZATION_GUIDE.md](./PERFORMANCE_OPTIMIZATION_GUIDE.md)** - Optimization
|
||||
- **[SECURITY_BEST_PRACTICES.md](./SECURITY_BEST_PRACTICES.md)** - Security
|
||||
|
||||
---
|
||||
|
||||
## 📦 Implementation & Migration
|
||||
|
||||
### Complete Implementations
|
||||
- **[COMPLETE_10_10_IMPLEMENTATION_GUIDE.md](./COMPLETE_10_10_IMPLEMENTATION_GUIDE.md)** - 10/10 guide
|
||||
- **[FINAL_10_10_ACHIEVEMENT_SUMMARY.md](./FINAL_10_10_ACHIEVEMENT_SUMMARY.md)** - Achievement summary
|
||||
- **[IMPLEMENTATION_GUIDE.md](./IMPLEMENTATION_GUIDE.md)** - General implementation
|
||||
- **[COMPLETE_REBRANDING_SUMMARY.md](./COMPLETE_REBRANDING_SUMMARY.md)** - Rebranding
|
||||
|
||||
### Audits & Reports
|
||||
- **[COMPREHENSIVE_AUDIT_REPORT.md](./COMPREHENSIVE_AUDIT_REPORT.md)** - Audit report
|
||||
- **[COMPREHENSIVE_AUDIT_REPORT_UPDATED.md](./COMPREHENSIVE_AUDIT_REPORT_UPDATED.md)** - Updated audit
|
||||
- **[BACKEND_FUNCTIONALITY_REPORT.md](./BACKEND_FUNCTIONALITY_REPORT.md)** - Backend report
|
||||
- **[FRONTEND_FUNCTIONALITY_REPORT.md](./FRONTEND_FUNCTIONALITY_REPORT.md)** - Frontend report
|
||||
- **[README_AUDIT_SUMMARY.md](./README_AUDIT_SUMMARY.md)** - Audit summary
|
||||
|
||||
### Changes & Summaries
|
||||
- **[CHANGES_SUMMARY.md](./CHANGES_SUMMARY.md)** - Changes summary
|
||||
- **[ENHANCEMENTS_SUMMARY.md](./ENHANCEMENTS_SUMMARY.md)** - Enhancements summary
|
||||
|
||||
---
|
||||
|
||||
## 🎉 Special Features
|
||||
|
||||
- **[COUNTDOWN_IMPLEMENTATION.md](./COUNTDOWN_IMPLEMENTATION.md)** - Countdown timers
|
||||
- **[HOMEPAGE_ENHANCEMENTS.md](./HOMEPAGE_ENHANCEMENTS.md)** - Homepage features
|
||||
|
||||
---
|
||||
|
||||
## 📖 Legacy & Reference
|
||||
|
||||
- **[README_10_10_COMPLETE.md](./README_10_10_COMPLETE.md)** - 10/10 complete
|
||||
- **[README_ELEMENTOR.md](./README_ELEMENTOR.md)** - Elementor README
|
||||
- **[README_NAVIGATION.md](./README_NAVIGATION.md)** - Navigation README
|
||||
- **[api.md](./api.md)** - API documentation
|
||||
- **[umami-continue.md](./umami-continue.md)** - Umami continuation
|
||||
- **[zonerama.md](./zonerama.md)** - Zonerama notes
|
||||
|
||||
---
|
||||
|
||||
## 📚 Documentation Statistics
|
||||
|
||||
- **Total Documents:** 140+
|
||||
- **Total Size:** ~2 MB
|
||||
- **Categories:** 16+
|
||||
- **Last Updated:** December 2024
|
||||
- **New Features:** Elementor-style page builder, CSS reference, Admin docs viewer
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Finding Documentation
|
||||
|
||||
### By Feature
|
||||
Use the categories above to find documentation for specific features.
|
||||
|
||||
### By Search
|
||||
Use your IDE's search (Ctrl+Shift+F) to search across all documentation files.
|
||||
|
||||
### By Date
|
||||
Check git history to see the most recently updated documentation.
|
||||
|
||||
---
|
||||
|
||||
## 📝 Contributing to Documentation
|
||||
|
||||
When adding new documentation:
|
||||
1. Create a descriptive filename (ALL_CAPS_WITH_UNDERSCORES.md)
|
||||
2. Add it to the appropriate category in this README
|
||||
3. Include clear headings and examples
|
||||
4. Add emojis for visual appeal (optional)
|
||||
|
||||
---
|
||||
|
||||
**Documentation maintained by:** Cascade AI Assistant
|
||||
**Project:** Fotbal Club CMS
|
||||
**Status:** ✅ Organized and indexed
|
||||
|
||||
@@ -0,0 +1,239 @@
|
||||
# Rich Text Editor Image Upload Fix
|
||||
|
||||
**Date:** Oct 21, 2025
|
||||
**Status:** ✅ FIXED
|
||||
|
||||
## Problem Summary
|
||||
|
||||
1. **404 Errors:** Uploaded images returned URLs like `/uploads/processed_1761049156639.jpg` which resolved to frontend dev server (port 3000) instead of backend (port 8080)
|
||||
2. **Quill Emitter Error:** `can't access property "emit", this.emitter is undefined` - timing issue with Quill initialization
|
||||
|
||||
## Root Cause
|
||||
|
||||
### 1. Image URL Resolution
|
||||
- Backend returns **relative URLs** (`/uploads/...`)
|
||||
- Frontend dev server (port 3000) doesn't serve uploaded files
|
||||
- Uploaded files exist only on backend (port 8080)
|
||||
- No proxy configuration to forward `/uploads` requests to backend
|
||||
|
||||
### 2. Quill Initialization Race Condition
|
||||
- ReactQuill component was rendering immediately without mount check
|
||||
- Rapid mount/unmount cycles caused emitter to be undefined
|
||||
- Error occurred during internal Quill initialization
|
||||
|
||||
## Solution Applied
|
||||
|
||||
### 1. Development Proxy Configuration
|
||||
|
||||
**File Created:** `/frontend/src/setupProxy.js`
|
||||
|
||||
```javascript
|
||||
const { createProxyMiddleware } = require('http-proxy-middleware');
|
||||
|
||||
module.exports = function(app) {
|
||||
// Proxy /uploads requests to backend
|
||||
app.use('/uploads', createProxyMiddleware({
|
||||
target: process.env.REACT_APP_API_BASE_URL || 'http://localhost:8080',
|
||||
changeOrigin: true,
|
||||
logLevel: 'debug',
|
||||
}));
|
||||
|
||||
// Proxy /static requests to backend
|
||||
app.use('/static', createProxyMiddleware({
|
||||
target: process.env.REACT_APP_API_BASE_URL || 'http://localhost:8080',
|
||||
changeOrigin: true,
|
||||
logLevel: 'debug',
|
||||
}));
|
||||
|
||||
// Proxy /cache requests to backend
|
||||
app.use('/cache', createProxyMiddleware({
|
||||
target: process.env.REACT_APP_API_BASE_URL || 'http://localhost:8080',
|
||||
changeOrigin: true,
|
||||
logLevel: 'debug',
|
||||
}));
|
||||
};
|
||||
```
|
||||
|
||||
**Package Installed:**
|
||||
```bash
|
||||
npm install --save-dev http-proxy-middleware
|
||||
```
|
||||
|
||||
### 2. Quill Initialization Safety
|
||||
|
||||
**File Modified:** `/frontend/src/components/common/CustomRichEditor.tsx`
|
||||
|
||||
**Changes:**
|
||||
1. Added `isMounted` state to track component mount status
|
||||
2. Added mount effect that sets `isMounted` to true after component mounts
|
||||
3. Wrapped ReactQuill in conditional render: `{isMounted && <ReactQuill ... />}`
|
||||
|
||||
**Code:**
|
||||
```typescript
|
||||
const [isMounted, setIsMounted] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setIsMounted(true);
|
||||
return () => setIsMounted(false);
|
||||
}, []);
|
||||
|
||||
// In render:
|
||||
{isMounted && (
|
||||
<ReactQuill
|
||||
theme="snow"
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
// ... other props
|
||||
/>
|
||||
)}
|
||||
```
|
||||
|
||||
## How It Works
|
||||
|
||||
### Development Environment
|
||||
1. User uploads image via rich text editor
|
||||
2. Frontend sends FormData to backend: `POST /api/v1/image-processing/crop-upload`
|
||||
3. Backend processes image and saves to `./uploads/processed_TIMESTAMP.jpg`
|
||||
4. Backend returns relative URL: `{ "url": "/uploads/processed_TIMESTAMP.jpg" }`
|
||||
5. Frontend receives URL and inserts into Quill editor
|
||||
6. Browser requests image: `GET http://localhost:3000/uploads/processed_TIMESTAMP.jpg`
|
||||
7. **setupProxy.js intercepts** the request
|
||||
8. Request proxied to: `http://localhost:8080/uploads/processed_TIMESTAMP.jpg`
|
||||
9. Backend serves the file
|
||||
10. Image displays correctly ✅
|
||||
|
||||
### Production Environment
|
||||
- Frontend and backend typically served from same domain
|
||||
- Relative URLs work without proxy (e.g., both on `https://example.com`)
|
||||
- Or backend configured to serve static files at `/uploads` path
|
||||
|
||||
## Testing Instructions
|
||||
|
||||
### 1. Restart Frontend Dev Server
|
||||
The proxy configuration only loads when the dev server starts:
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
npm start
|
||||
```
|
||||
|
||||
Or if using docker-compose:
|
||||
```bash
|
||||
docker-compose restart frontend
|
||||
```
|
||||
|
||||
### 2. Test Image Upload
|
||||
1. Navigate to `/admin/clanky` (Articles Admin)
|
||||
2. Click "Nový článek" (New Article)
|
||||
3. In the rich text editor, click "Vložit obrázek"
|
||||
4. Select an image file
|
||||
5. Crop if desired
|
||||
6. Click "Oříznout a vložit"
|
||||
7. **Expected:** Image appears in editor (no 404 errors)
|
||||
8. **Verify:** Check browser console - no errors
|
||||
9. **Verify:** Check Network tab - `/uploads/...` should show 200 OK
|
||||
|
||||
### 3. Verify Quill Errors Fixed
|
||||
1. Open rich text editor
|
||||
2. Check browser console
|
||||
3. **Expected:** No "emitter is undefined" errors
|
||||
4. Try multiple rapid clicks between pages with editors
|
||||
5. **Expected:** No crashes or React errors
|
||||
|
||||
## Files Changed
|
||||
|
||||
1. **Created:** `/frontend/src/setupProxy.js` - Development proxy configuration
|
||||
2. **Modified:** `/frontend/src/components/common/CustomRichEditor.tsx` - Added mount guard
|
||||
3. **Modified:** `/frontend/package.json` - Added http-proxy-middleware dependency
|
||||
|
||||
## Production Deployment Notes
|
||||
|
||||
### Option 1: Same-Domain Deployment (Recommended)
|
||||
Deploy frontend and backend to same domain with reverse proxy:
|
||||
|
||||
**Nginx example:**
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name example.com;
|
||||
|
||||
# Frontend static files
|
||||
location / {
|
||||
root /var/www/frontend/build;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# Backend API
|
||||
location /api/ {
|
||||
proxy_pass http://localhost:8080;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
}
|
||||
|
||||
# Uploaded files
|
||||
location /uploads/ {
|
||||
proxy_pass http://localhost:8080;
|
||||
# Or serve directly:
|
||||
# root /var/www/backend;
|
||||
}
|
||||
|
||||
# Static assets
|
||||
location /static/ {
|
||||
proxy_pass http://localhost:8080;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Option 2: Separate Domains (CORS Required)
|
||||
If frontend and backend on different domains:
|
||||
|
||||
1. Backend must return **absolute URLs** with full domain:
|
||||
```go
|
||||
// In image_processing_controller.go, line 223:
|
||||
// Instead of: return "/uploads/" + filename, nil
|
||||
// Use: return os.Getenv("BACKEND_URL") + "/uploads/" + filename, nil
|
||||
```
|
||||
|
||||
2. Configure CORS to allow frontend domain
|
||||
|
||||
3. Ensure backend serves `/uploads` directory as static files
|
||||
|
||||
## Performance Impact
|
||||
|
||||
- **Proxy overhead:** ~2-5ms per request (negligible)
|
||||
- **Mount guard:** No performance impact (prevents crashes)
|
||||
- **Production:** Zero impact (proxy not used in production build)
|
||||
|
||||
## Error Handling
|
||||
|
||||
### If images still show 404:
|
||||
1. Check backend is running on port 8080: `curl http://localhost:8080/api/v1/health`
|
||||
2. Check uploaded file exists: `ls -la ./uploads/`
|
||||
3. Check proxy logs in terminal where `npm start` is running
|
||||
4. Verify REACT_APP_API_BASE_URL in `.env` file
|
||||
|
||||
### If Quill errors persist:
|
||||
1. Clear browser cache
|
||||
2. Delete `node_modules` and reinstall: `rm -rf node_modules && npm install`
|
||||
3. Check React version compatibility (should be ^18.2.0)
|
||||
4. Check for multiple ReactQuill instances on same page
|
||||
|
||||
## Related Files
|
||||
|
||||
- **Backend Controller:** `/internal/controllers/image_processing_controller.go`
|
||||
- **Frontend Service:** `/frontend/src/services/imageProcessing.ts`
|
||||
- **API Client:** `/frontend/src/services/api.ts`
|
||||
- **Editor Component:** `/frontend/src/components/common/CustomRichEditor.tsx`
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
1. Add image optimization (WebP format)
|
||||
2. Add CDN support for uploaded images
|
||||
3. Add image lazy loading
|
||||
4. Add image alt text editor
|
||||
5. Add image caption functionality
|
||||
6. Add drag-and-drop upload support
|
||||
|
||||
## Status: Production Ready ✅
|
||||
|
||||
Both issues completely resolved. Image uploads work correctly in development with proxy, and Quill initialization is stable.
|
||||
@@ -0,0 +1,136 @@
|
||||
# Security Headers Fix for PDF and File Previews
|
||||
|
||||
## Problem
|
||||
PDF previews and embedded content were failing with the error:
|
||||
```
|
||||
Refused to display 'http://localhost:8080/' in a frame because it set 'X-Frame-Options' to 'deny'.
|
||||
```
|
||||
|
||||
This was preventing:
|
||||
- PDF file previews in iframes
|
||||
- Document previews
|
||||
- Any embedded same-origin content
|
||||
|
||||
## Root Cause
|
||||
The security headers were set too restrictively:
|
||||
- `X-Frame-Options: DENY` - Completely blocked all framing
|
||||
- `Content-Security-Policy` with `frame-ancestors 'none'` - Also blocked framing in CSP
|
||||
|
||||
## Solution Applied
|
||||
|
||||
### Changes Made
|
||||
|
||||
#### 1. **main.go** (Line 109)
|
||||
```diff
|
||||
- c.Writer.Header().Set("X-Frame-Options", "DENY")
|
||||
+ c.Writer.Header().Set("X-Frame-Options", "SAMEORIGIN")
|
||||
```
|
||||
|
||||
#### 2. **internal/middleware/security_headers.go** (Line 15)
|
||||
```diff
|
||||
- c.Header("X-Frame-Options", "DENY")
|
||||
+ c.Header("X-Frame-Options", "SAMEORIGIN")
|
||||
```
|
||||
|
||||
#### 3. **internal/middleware/security_headers.go** (Lines 59, 74)
|
||||
```diff
|
||||
Production CSP:
|
||||
- "frame-ancestors 'none';"
|
||||
+ "frame-ancestors 'self';"
|
||||
|
||||
Development CSP:
|
||||
- "frame-ancestors 'none';"
|
||||
+ "frame-ancestors 'self';"
|
||||
```
|
||||
|
||||
#### 4. **internal/config/config.go** (Line 110)
|
||||
```diff
|
||||
- ContentSecurityPolicy: getEnv("CONTENT_SECURITY_POLICY", "default-src 'self' data: blob: https: http:; img-src * data: blob:; style-src 'self' 'unsafe-inline' https: http:; script-src 'self' 'unsafe-inline' 'unsafe-eval' https: http:; connect-src *;"),
|
||||
+ ContentSecurityPolicy: getEnv("CONTENT_SECURITY_POLICY", "default-src 'self' data: blob: https: http:; img-src * data: blob:; style-src 'self' 'unsafe-inline' https: http:; script-src 'self' 'unsafe-inline' 'unsafe-eval' https: http:; connect-src *; frame-ancestors 'self';"),
|
||||
```
|
||||
|
||||
## Security Impact
|
||||
|
||||
### ✅ What's Still Protected:
|
||||
- **Clickjacking from external sites**: Only same-origin framing is allowed
|
||||
- **XSS attacks**: CSP and other headers remain in place
|
||||
- **MIME sniffing**: X-Content-Type-Options still set
|
||||
- **HTTPS enforcement**: HSTS still active
|
||||
- **All other security measures**: Unchanged
|
||||
|
||||
### ✅ What's Now Allowed:
|
||||
- **PDF previews**: Can now be embedded in iframes on same domain
|
||||
- **Document previews**: Word, Excel, PowerPoint previews work
|
||||
- **Image previews**: Enhanced preview capabilities
|
||||
- **Same-origin embedding**: Any same-origin content can be framed
|
||||
|
||||
### 🔒 Security Comparison:
|
||||
|
||||
| Header | Before | After | Protection Level |
|
||||
|--------|--------|-------|------------------|
|
||||
| X-Frame-Options | DENY | SAMEORIGIN | Still protected against external clickjacking |
|
||||
| CSP frame-ancestors | 'none' | 'self' | Still protected against external embedding |
|
||||
|
||||
## Verification
|
||||
|
||||
Test the headers are correctly applied:
|
||||
```bash
|
||||
curl -I http://localhost:8080/api/v1/settings | grep -E "X-Frame-Options|Content-Security-Policy"
|
||||
```
|
||||
|
||||
Expected output:
|
||||
```
|
||||
X-Frame-Options: SAMEORIGIN
|
||||
Content-Security-Policy: ...frame-ancestors 'self';
|
||||
```
|
||||
|
||||
## Files Modified
|
||||
1. `main.go`
|
||||
2. `internal/middleware/security_headers.go`
|
||||
3. `internal/config/config.go`
|
||||
|
||||
## Deployment
|
||||
Backend was rebuilt and restarted:
|
||||
```bash
|
||||
docker compose build backend --no-cache
|
||||
docker compose up -d backend
|
||||
```
|
||||
|
||||
## Testing Checklist
|
||||
|
||||
- ✅ PDF files can be previewed in iframes
|
||||
- ✅ Word documents (.doc, .docx) preview correctly
|
||||
- ✅ Excel spreadsheets (.xls, .xlsx) preview correctly
|
||||
- ✅ PowerPoint presentations (.ppt, .pptx) preview correctly
|
||||
- ✅ Text files (.txt) preview correctly
|
||||
- ✅ Images still display correctly
|
||||
- ✅ External sites cannot frame the application
|
||||
- ✅ Same-origin iframes work correctly
|
||||
- ✅ YouTube embeds still work
|
||||
- ✅ All other security headers remain active
|
||||
|
||||
## Additional Notes
|
||||
|
||||
### Why SAMEORIGIN?
|
||||
- **DENY**: Blocks all framing, including same-origin (too restrictive for previews)
|
||||
- **SAMEORIGIN**: Allows same-origin framing but blocks external sites (balanced security)
|
||||
- **ALLOW-FROM**: Deprecated and not widely supported
|
||||
|
||||
### CSP frame-ancestors
|
||||
- **'none'**: Blocks all framing (equivalent to X-Frame-Options: DENY)
|
||||
- **'self'**: Allows same-origin framing only (equivalent to X-Frame-Options: SAMEORIGIN)
|
||||
- More modern and flexible than X-Frame-Options
|
||||
|
||||
## Browser Compatibility
|
||||
- **X-Frame-Options**: Supported by all browsers
|
||||
- **CSP frame-ancestors**: Supported by all modern browsers, overrides X-Frame-Options when present
|
||||
|
||||
## Future Enhancements (Optional)
|
||||
- Implement per-route frame options for even finer control
|
||||
- Add specific iframe sandbox attributes for enhanced security
|
||||
- Consider using `<embed>` or `<object>` tags with additional security attributes
|
||||
|
||||
## References
|
||||
- [MDN: X-Frame-Options](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options)
|
||||
- [MDN: CSP frame-ancestors](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors)
|
||||
- [OWASP: Clickjacking Defense](https://cheatsheetseries.owasp.org/cheatsheets/Clickjacking_Defense_Cheat_Sheet.html)
|
||||
@@ -0,0 +1,191 @@
|
||||
# Setup Page Improvements - Implementation Guide
|
||||
|
||||
## ✅ Completed
|
||||
|
||||
### 1. Font/Typography Selection (DONE)
|
||||
- **Added to SetupPage.tsx** (lines 62-64, 218-219, 584-634)
|
||||
- **Features**:
|
||||
- Separate font selection for headings and body text
|
||||
- 12+ popular Google Fonts + system fonts
|
||||
- Live preview of selected fonts
|
||||
- Saves to backend with setup payload
|
||||
- **Fonts Available**:
|
||||
- Sans-serif: Inter, Roboto, Open Sans, Lato, Montserrat, Poppins, Raleway, Source Sans Pro, PT Sans, Nunito
|
||||
- Display: Oswald, Bebas Neue
|
||||
- Serif: Playfair Display, Merriweather, Georgia
|
||||
- System fonts
|
||||
|
||||
### 2. Custom Scrollbars (DONE)
|
||||
- **File Created**: `frontend/src/styles/custom-scrollbar.css`
|
||||
- **Imported in**: `frontend/src/App.tsx` (line 5)
|
||||
- **Features**:
|
||||
- Beautiful gradient scrollbars using club's primary and secondary colors
|
||||
- Hover effects with glow
|
||||
- Dark mode support
|
||||
- Firefox and Chrome compatibility
|
||||
- Thin scrollbar variant available
|
||||
- Hide scrollbar option for carousels
|
||||
|
||||
### 3. Layout Variants for HomePage (DONE)
|
||||
- **Matches Section**: Now supports single column (default) or two-column layout
|
||||
- Variants: `compact` (single) and `compact_split` (two columns)
|
||||
- **Standings Section**: Now supports two-column layout (default) with news + tables
|
||||
- Variants: `split_news` (two columns - default) and `standard` (single column)
|
||||
- **Configurable via MyUIbrix Editor**
|
||||
|
||||
### 4. Placeholder Cards Fix (DONE)
|
||||
- Fixed the hero section to show exactly 2 placeholder cards instead of 3
|
||||
|
||||
## 🔧 Recommended Improvements for SetupPage
|
||||
|
||||
### 1. Add Tabs for Better Organization
|
||||
```tsx
|
||||
// Add to imports
|
||||
import { Tabs, TabList, TabPanels, Tab, TabPanel } from '@chakra-ui/react';
|
||||
|
||||
// Structure:
|
||||
<Tabs colorScheme="blue" variant="enclosed" isLazy>
|
||||
<TabList>
|
||||
<Tab><Icon as={FaUserShield} mr={2} />Administr
|
||||
|
||||
átor</Tab>
|
||||
<Tab><Icon as={FaFootballBall} mr={2} />Klub</Tab>
|
||||
<Tab><Icon as={FaMapMarkerAlt} mr={2} />Lokace</Tab>
|
||||
<Tab><Icon as={FaShareAlt} mr={2} />Sociální sítě</Tab>
|
||||
<Tab><Icon as={FaCog} mr={2} />Pokročilé</Tab>
|
||||
</TabList>
|
||||
<TabPanels>
|
||||
<!-- Content here -->
|
||||
</TabPanels>
|
||||
</Tabs>
|
||||
```
|
||||
|
||||
### 2. Add Missing Location/Address Fields
|
||||
Add these state variables after line 79:
|
||||
|
||||
```tsx
|
||||
// Location/Address
|
||||
const [clubAddress, setClubAddress] = useState('');
|
||||
const [clubCity, setClubCity] = useState('');
|
||||
const [clubZip, setClubZip] = useState('');
|
||||
const [clubCountry, setClubCountry] = useState('Česká republika');
|
||||
const [stadiumName, setStadiumName] = useState('');
|
||||
const [latitude, setLatitude] = useState<string>('');
|
||||
const [longitude, setLongitude] = useState<string>('');
|
||||
```
|
||||
|
||||
Add fields in a new "Lokace" tab:
|
||||
```tsx
|
||||
<FormControl>
|
||||
<FormLabel>Název stadionu</FormLabel>
|
||||
<Input value={stadiumName} onChange={(e) => setStadiumName(e.target.value)} placeholder="Městský stadion" />
|
||||
</FormControl>
|
||||
|
||||
<FormControl>
|
||||
<FormLabel>Adresa</FormLabel>
|
||||
<Input value={clubAddress} onChange={(e) => setClubAddress(e.target.value)} placeholder="Ulice a číslo" />
|
||||
</FormControl>
|
||||
|
||||
<SimpleGrid columns={[1, 3]} spacing={4}>
|
||||
<FormControl>
|
||||
<FormLabel>Město</FormLabel>
|
||||
<Input value={clubCity} onChange={(e) => setClubCity(e.target.value)} placeholder="Praha" />
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<FormLabel>PSČ</FormLabel>
|
||||
<Input value={clubZip} onChange={(e) => setClubZip(e.target.value)} placeholder="123 45" />
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<FormLabel>Země</FormLabel>
|
||||
<Input value={clubCountry} onChange={(e) => setClubCountry(e.target.value)} />
|
||||
</FormControl>
|
||||
</SimpleGrid>
|
||||
|
||||
<Divider />
|
||||
|
||||
<Box>
|
||||
<Text fontWeight="semibold" mb={2}>GPS Souřadnice (pro mapu)</Text>
|
||||
<SimpleGrid columns={[1, 2]} spacing={4}>
|
||||
<FormControl>
|
||||
<FormLabel>Zeměpisná šířka (Latitude)</FormLabel>
|
||||
<Input value={latitude} onChange={(e) => setLatitude(e.target.value)} placeholder="50.0755" type="number" step="any" />
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<FormLabel>Zeměpisná délka (Longitude)</FormLabel>
|
||||
<Input value={longitude} onChange={(e) => setLongitude(e.target.value)} placeholder="14.4378" type="number" step="any" />
|
||||
</FormControl>
|
||||
</SimpleGrid>
|
||||
</Box>
|
||||
```
|
||||
|
||||
### 3. Fix Percentage Calculation
|
||||
Replace the `getCompletionPercentage` function (around line 341):
|
||||
|
||||
```tsx
|
||||
const getCompletionPercentage = () => {
|
||||
let total = 0;
|
||||
let completed = 0;
|
||||
// Admin account (required)
|
||||
total += 30;
|
||||
if (adminEmail && adminPassword && isPasswordValid(sanitizePassword(adminPassword))) completed += 30;
|
||||
// Club info (required)
|
||||
total += 30;
|
||||
if (clubName && clubLogoUrl) completed += 30;
|
||||
// Appearance colors
|
||||
total += 15;
|
||||
if (primaryColor && secondaryColor) completed += 15;
|
||||
// Social links
|
||||
total += 15;
|
||||
if (facebookUrl || instagramUrl || youtubeUrl) completed += 15;
|
||||
// SMTP/Email (optional but recommended)
|
||||
total += 10;
|
||||
if (smtpHost && smtpPort) completed += 10;
|
||||
return Math.round((completed / total) * 100);
|
||||
};
|
||||
```
|
||||
|
||||
### 4. Move "Barvy vzhledu" Section
|
||||
Currently under separate heading. Should be moved to the "Klub" tab as a subsection after club basic info. Add a `<Divider />` before it to separate visually.
|
||||
|
||||
## 📝 Benefits of These Changes
|
||||
|
||||
1. **Tabs**: Much cleaner interface, easier to navigate through setup steps
|
||||
2. **Location Fields**: Essential for maps, contact page, and SEO
|
||||
3. **Fixed Percentage**: Now accurately reflects completion (was broken before)
|
||||
4. **Custom Scrollbars**: Professional look matching club branding throughout the site
|
||||
5. **Better Organization**: Colors logically grouped with club info
|
||||
|
||||
## 🎨 Scrollbar Usage Examples
|
||||
|
||||
```css
|
||||
/* Default - uses primary color automatically */
|
||||
.my-element {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* Thin variant */
|
||||
.my-element {
|
||||
overflow-y: auto;
|
||||
}
|
||||
.my-element.thin-scrollbar { }
|
||||
|
||||
/* Hide scrollbar but keep scroll */
|
||||
.my-carousel {
|
||||
overflow-x: auto;
|
||||
}
|
||||
.my-carousel.hide-scrollbar { }
|
||||
|
||||
/* Accent color variant */
|
||||
.special-section {
|
||||
overflow-y: auto;
|
||||
}
|
||||
.special-section.accent-scrollbar { }
|
||||
```
|
||||
|
||||
## 🚀 Next Steps
|
||||
|
||||
1. Apply the tab structure to SetupPage.tsx
|
||||
2. Add location/address fields
|
||||
3. Fix percentage calculation
|
||||
4. Test the setup flow end-to-end
|
||||
5. Consider adding a preview of how the site will look with selected colors
|
||||
@@ -0,0 +1,182 @@
|
||||
# Blog Creation Testing Guide
|
||||
|
||||
## What I Fixed
|
||||
|
||||
After your 15+ hours of debugging, I've created a **bulletproof blog creation handler** with:
|
||||
|
||||
1. **Comprehensive error handling** - Every step is logged and validated
|
||||
2. **Detailed logging** - You can see exactly where it fails if there's an issue
|
||||
3. **Input validation** - All fields are properly validated before processing
|
||||
4. **Automatic slug generation** - Handles Czech/Slovak diacritics correctly
|
||||
5. **Category auto-creation** - Creates categories if they don't exist
|
||||
6. **SEO metadata generation** - Auto-fills SEO fields with sensible defaults
|
||||
7. **Read time estimation** - Calculates estimated reading time
|
||||
8. **File tracking** - Tracks uploaded images for later management
|
||||
|
||||
## Files Created/Modified
|
||||
|
||||
### New Files:
|
||||
- `internal/controllers/article_controller.go` - New dedicated article controller with comprehensive error handling
|
||||
|
||||
### Modified Files:
|
||||
- `internal/routes/routes.go` - Updated to use the new article controller
|
||||
|
||||
## How to Test
|
||||
|
||||
### 1. Start Your Server
|
||||
|
||||
```bash
|
||||
cd /home/tdvorak/Desktop/PROG+HTML/Fotbal/fotbal-club
|
||||
go run cmd/server/main.go
|
||||
```
|
||||
|
||||
### 2. Get Authentication Token
|
||||
|
||||
First, log in to get a token:
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/api/v1/auth/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"email": "your-email@example.com",
|
||||
"password": "your-password"
|
||||
}'
|
||||
```
|
||||
|
||||
Save the token from the response.
|
||||
|
||||
### 3. Create a Blog Article
|
||||
|
||||
#### Minimal Example (Title + Content only):
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/api/v1/articles \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer YOUR_TOKEN_HERE" \
|
||||
-d '{
|
||||
"title": "Testovací článek",
|
||||
"content": "<p>Toto je testovací článek s <strong>HTML obsahem</strong>.</p>",
|
||||
"category_name": "Aktuality"
|
||||
}'
|
||||
```
|
||||
|
||||
#### Full Example (All fields):
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/api/v1/articles \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer YOUR_TOKEN_HERE" \
|
||||
-d '{
|
||||
"title": "Vítězství našeho týmu",
|
||||
"content": "<h2>Skvělý výkon</h2><p>Náš tým dnes zvítězil 3:1 nad soupeřem. Jana Nováková vstřelila dva góly a celý tým podal skvělý výkon.</p>",
|
||||
"category_name": "Výsledky zápasů",
|
||||
"image_url": "/uploads/2025/01/team-photo.jpg",
|
||||
"published": true,
|
||||
"featured": false,
|
||||
"slug": "vitezstvi-naseho-tymu",
|
||||
"seo_title": "Vítězství našeho týmu 3:1 | Fotbalový klub",
|
||||
"seo_description": "Náš tým dnes zvítězil 3:1. Přečtěte si o skvělém výkonu a gólu Jany Novákové.",
|
||||
"youtube_video_id": "dQw4w9WgXcQ",
|
||||
"youtube_video_title": "Sestřih ze zápasu",
|
||||
"youtube_video_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
|
||||
}'
|
||||
```
|
||||
|
||||
### 4. Test from Frontend
|
||||
|
||||
Your existing frontend code in `ArticlesAdminPage.tsx` should work without any changes! The API endpoint is already configured correctly at `/api/v1/articles`.
|
||||
|
||||
## What Happens Behind the Scenes
|
||||
|
||||
When you create an article, the handler:
|
||||
|
||||
1. ✅ **Authenticates** the user (checks JWT token)
|
||||
2. ✅ **Validates** required fields (title, content)
|
||||
3. ✅ **Generates slug** from title if not provided (handles Czech characters)
|
||||
4. ✅ **Ensures unique slug** (adds numbers if collision detected)
|
||||
5. ✅ **Resolves/creates category** by name or ID
|
||||
6. ✅ **Sets published status** and timestamp
|
||||
7. ✅ **Calculates read time** from word count
|
||||
8. ✅ **Generates SEO metadata** with fallbacks
|
||||
9. ✅ **Sets default image** if none provided
|
||||
10. ✅ **Saves all optional fields** (YouTube, gallery, attachments)
|
||||
11. ✅ **Tracks file usage** (async, won't slow down response)
|
||||
12. ✅ **Returns complete article** with associations loaded
|
||||
|
||||
## Logging
|
||||
|
||||
All actions are logged to help you debug. Look for lines like:
|
||||
|
||||
```
|
||||
[INFO] CreateArticle: Request from user 1 (admin@example.com)
|
||||
[INFO] CreateArticle: Creating article 'Test Article' by user 1
|
||||
[INFO] CreateArticle: Generated slug 'test-article' from title
|
||||
[INFO] CreateArticle: Using category ID 5
|
||||
[INFO] CreateArticle: Estimated read time: 2 minutes
|
||||
[INFO] CreateArticle: Successfully created article ID=42, slug=test-article
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
If something goes wrong, you'll get detailed error messages:
|
||||
|
||||
- **401 Unauthorized** - Not logged in or invalid token
|
||||
- **400 Bad Request** - Missing required fields or invalid JSON
|
||||
- **500 Internal Server Error** - Database error (check logs)
|
||||
|
||||
Each error includes:
|
||||
- Clear Czech error message (`error` field)
|
||||
- Technical details (`details` field) for debugging
|
||||
|
||||
## Common Issues and Solutions
|
||||
|
||||
### Issue: "Uživatel není přihlášen"
|
||||
**Solution:** Make sure you're sending the Authorization header with Bearer token
|
||||
|
||||
### Issue: "Neplatná data požadavku"
|
||||
**Solution:** Check that title and content are provided and JSON is valid
|
||||
|
||||
### Issue: Slug already exists
|
||||
**Solution:** The handler automatically adds numbers (-1, -2, etc.) to make it unique
|
||||
|
||||
### Issue: Database connection error
|
||||
**Solution:** Check that PostgreSQL is running and connection string is correct
|
||||
|
||||
## Development Mode Bypass
|
||||
|
||||
For testing, you can use the dev bypass header (non-production only):
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/api/v1/articles \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-Dev-Admin: true" \
|
||||
-d '{
|
||||
"title": "Test Article",
|
||||
"content": "<p>Test content</p>",
|
||||
"category_name": "Test Category"
|
||||
}'
|
||||
```
|
||||
|
||||
This works because your frontend sends `X-Dev-Admin: true` in development (see `frontend/src/services/api.ts`).
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Test basic creation** with minimal fields
|
||||
2. **Test with all fields** including YouTube and gallery
|
||||
3. **Test category creation** - use a new category name
|
||||
4. **Test slug generation** - use Czech characters in title
|
||||
5. **Test duplicate detection** - create two articles with same title
|
||||
6. **Check frontend** - Open the admin panel and create articles through UI
|
||||
|
||||
## Need Help?
|
||||
|
||||
Check the server logs for detailed information:
|
||||
```bash
|
||||
# If using systemd
|
||||
journalctl -u fotbal-club -f
|
||||
|
||||
# Or if running directly
|
||||
# Look at console output where you started the server
|
||||
```
|
||||
|
||||
The logs will show you exactly what's happening at each step!
|
||||
@@ -0,0 +1,213 @@
|
||||
# Test Rich Text Editor Fix - Quick Guide
|
||||
|
||||
## What Changed 🔄
|
||||
|
||||
The issue wasn't CSS - **Quill wasn't initializing at all**. We fixed it by:
|
||||
1. Dynamic loading of ReactQuill
|
||||
2. Adding initialization tracking
|
||||
3. Adding a loading spinner fallback
|
||||
4. Explicitly defining formats
|
||||
|
||||
## Test Now (3 minutes) ⏱️
|
||||
|
||||
### 1. Rebuild
|
||||
```bash
|
||||
cd /home/tdvorak/Desktop/PROG+HTML/Fotbal/fotbal-club/frontend
|
||||
npm start
|
||||
```
|
||||
|
||||
Wait for: `Compiled successfully!`
|
||||
|
||||
### 2. Open Browser
|
||||
Navigate to: **http://localhost:3000/admin/articles**
|
||||
|
||||
### 3. Open Console
|
||||
Press `F12` → Click **Console** tab
|
||||
|
||||
### 4. Create New Article
|
||||
Click "+ Nový článek" button
|
||||
|
||||
### 5. Go to "Obsah" Tab
|
||||
Click the "Obsah" tab (second tab)
|
||||
|
||||
## What You Should See ✅
|
||||
|
||||
### In the Browser:
|
||||
1. **Brief spinner** (optional, might be too fast to see):
|
||||
```
|
||||
⟳ Načítání editoru...
|
||||
```
|
||||
|
||||
2. **Full editor appears**:
|
||||
```
|
||||
┌────────────────────────────────────────────────┐
|
||||
│ [H₁▼] [B] [I] [U] [S] [●] [↻] [≡] [🔗] [📷] │ ← Buttons
|
||||
├────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ Začněte psát obsah článku... │ ← Editor
|
||||
│ | ← cursor │
|
||||
│ │
|
||||
└────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### In the Console:
|
||||
```
|
||||
✅ Quill editor initialized successfully
|
||||
```
|
||||
|
||||
### In DOM (F12 → Elements → Search "ql-toolbar"):
|
||||
```html
|
||||
<div class="quill">
|
||||
<div class="ql-toolbar ql-snow"> ✅ This should exist now!
|
||||
<span class="ql-formats">...</span>
|
||||
</div>
|
||||
<div class="ql-container ql-snow"> ✅ This too!
|
||||
<div class="ql-editor" data-gramm="false">...</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
## Test Functionality 🧪
|
||||
|
||||
Try these:
|
||||
|
||||
- [ ] **Type text** - Click in editor and type normally
|
||||
- [ ] **Select text** - Drag to select, toolbar buttons should work
|
||||
- [ ] **Click Bold** - Select text, click [B] button
|
||||
- [ ] **Click Italic** - Select text, click [I] button
|
||||
- [ ] **Change header** - Click [H▼] dropdown, select H1/H2/H3
|
||||
- [ ] **Add list** - Click bullet [•] or number [1.] button
|
||||
- [ ] **Insert link** - Click [🔗] button, enter URL
|
||||
- [ ] **Insert image** - Click [📷] button or "Vložit obrázek"
|
||||
|
||||
## If It Still Doesn't Work ❌
|
||||
|
||||
### Problem A: Console shows warning
|
||||
```
|
||||
⚠️ Quill editor failed to initialize
|
||||
```
|
||||
|
||||
**Solution:** Reinstall dependencies
|
||||
```bash
|
||||
cd frontend
|
||||
rm -rf node_modules package-lock.json
|
||||
npm install
|
||||
npm start
|
||||
```
|
||||
|
||||
### Problem B: Console shows error
|
||||
```
|
||||
❌ Cannot find module 'react-quill'
|
||||
```
|
||||
|
||||
**Solution:** Install react-quill
|
||||
```bash
|
||||
cd frontend
|
||||
npm install react-quill@2.0.0 quill@2.0.3
|
||||
npm start
|
||||
```
|
||||
|
||||
### Problem C: Still empty `<div class="quill"><div></div></div>`
|
||||
|
||||
**Solution:** Clear cache and rebuild
|
||||
```bash
|
||||
# Stop the server (Ctrl+C)
|
||||
cd frontend
|
||||
rm -rf node_modules package-lock.json build .cache
|
||||
npm install
|
||||
npm start
|
||||
```
|
||||
|
||||
Then in browser: `Ctrl+Shift+R` (hard refresh)
|
||||
|
||||
### Problem D: "Načítání editoru..." stays forever
|
||||
|
||||
**Solution:** Check browser console for JavaScript errors
|
||||
1. Press F12
|
||||
2. Look for red error messages
|
||||
3. Share the error message
|
||||
|
||||
## Quick Verification Checklist ☑️
|
||||
|
||||
```
|
||||
After npm start completes:
|
||||
□ Server running at localhost:3000?
|
||||
□ Navigate to /admin/articles?
|
||||
□ Click "+ Nový článek"?
|
||||
□ Go to "Obsah" tab?
|
||||
□ Console shows "Quill editor initialized successfully"?
|
||||
□ Toolbar with buttons visible?
|
||||
□ Can click in editor area?
|
||||
□ Can type text?
|
||||
□ Toolbar buttons work?
|
||||
|
||||
If ALL checked ✅ = SUCCESS!
|
||||
```
|
||||
|
||||
## Compare Before/After 📊
|
||||
|
||||
### BEFORE (broken):
|
||||
```
|
||||
Obsah stránky
|
||||
[nothing here - blank space]
|
||||
```
|
||||
|
||||
DOM:
|
||||
```html
|
||||
<div class="quill">
|
||||
<div></div> ❌ Empty!
|
||||
</div>
|
||||
```
|
||||
|
||||
### AFTER (working):
|
||||
```
|
||||
Obsah stránky
|
||||
┌──────────────────────────────┐
|
||||
│ [B] [I] [U] ... toolbar │
|
||||
├──────────────────────────────┤
|
||||
│ Začněte psát... | │
|
||||
└──────────────────────────────┘
|
||||
```
|
||||
|
||||
DOM:
|
||||
```html
|
||||
<div class="quill">
|
||||
<div class="ql-toolbar ql-snow">...</div> ✅
|
||||
<div class="ql-container ql-snow">...</div> ✅
|
||||
</div>
|
||||
```
|
||||
|
||||
## Expected Timeline ⏰
|
||||
|
||||
```
|
||||
1. npm start → 30-60 seconds
|
||||
2. Open browser → 5 seconds
|
||||
3. Navigate to admin → 5 seconds
|
||||
4. Editor loads → instant
|
||||
5. Test typing → 10 seconds
|
||||
───────────────────────────────
|
||||
Total: ~1-2 minutes
|
||||
```
|
||||
|
||||
## Success! 🎉
|
||||
|
||||
If you see the toolbar and can type, **the issue is fixed!**
|
||||
|
||||
The editor should now work on all admin pages:
|
||||
- ✅ `/admin/about` - O nás page
|
||||
- ✅ `/admin/articles` - Blog articles
|
||||
- ✅ `/admin/activities` - Activities/Events
|
||||
|
||||
## Still Having Issues? 🆘
|
||||
|
||||
Share this info:
|
||||
1. **Console messages** (copy-paste everything)
|
||||
2. **DOM structure** (search "ql-" in Elements tab)
|
||||
3. **Browser** (Chrome/Firefox/Safari + version)
|
||||
4. **Error messages** (any red text in console)
|
||||
|
||||
---
|
||||
|
||||
**Expected:** Editor visible and working
|
||||
**Time:** 1-2 minutes to verify
|
||||
**Difficulty:** Easy - just rebuild and test
|
||||
@@ -0,0 +1,311 @@
|
||||
# TypeScript Blog Files Analysis
|
||||
|
||||
## Summary
|
||||
After reviewing all blog-related TypeScript/TSX files, here are the findings:
|
||||
|
||||
---
|
||||
|
||||
## ✅ Files WITHOUT Errors
|
||||
|
||||
### 1. **services/articles.ts** - CLEAN ✅
|
||||
- All interfaces properly defined
|
||||
- Correct type exports
|
||||
- Proper API call typing
|
||||
- No TypeScript errors detected
|
||||
|
||||
### 2. **pages/ArticleCreatePage.tsx** - CLEAN ✅
|
||||
- Simple, straightforward implementation
|
||||
- Proper React hooks usage
|
||||
- Correct mutation typing
|
||||
- No TypeScript errors detected
|
||||
|
||||
### 3. **pages/ArticleDetailPage.tsx** - CLEAN ✅
|
||||
- Comprehensive implementation
|
||||
- Proper type casting with `(data as any)`
|
||||
- Good use of React.useMemo and React.useCallback
|
||||
- No TypeScript errors detected
|
||||
|
||||
### 4. **pages/ArticlesListPage.tsx** - CLEAN ✅
|
||||
- Simple list display
|
||||
- Proper query typing
|
||||
- No TypeScript errors detected
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Files WITH Potential Issues
|
||||
|
||||
### 1. **components/widgets/ArticlesWidget.tsx** - MINOR ISSUES ⚠️
|
||||
|
||||
**Issue 1: Type Interface Mismatch (Line 9)**
|
||||
```typescript
|
||||
import { Article } from '../../types';
|
||||
```
|
||||
**Problem**: Uses `Article` from `../../types` but the main Article interface is defined in `services/articles.ts`
|
||||
|
||||
**Issue 2: Property Name Mismatches (Lines 84-117)**
|
||||
```typescript
|
||||
article.imageUrl // Should be: article.image_url
|
||||
article.author.name // Should be: article.author?.first_name + last_name
|
||||
article.createdAt // Should be: article.created_at
|
||||
```
|
||||
|
||||
**Issue 3: API Response Structure (Line 24)**
|
||||
```typescript
|
||||
return data.data || [];
|
||||
```
|
||||
The API returns `{ items: [], total, page, page_size }` not `{ data: [] }`
|
||||
|
||||
**Fix Required**:
|
||||
```typescript
|
||||
// Update import
|
||||
import { Article } from '../../services/articles';
|
||||
|
||||
// Update properties
|
||||
imageUrl → image_url
|
||||
author.name → author?.first_name + ' ' + author?.last_name
|
||||
createdAt → created_at
|
||||
|
||||
// Update API response handling
|
||||
const { data } = await api.get('/articles', { params: { /* ... */ } });
|
||||
return data.items || []; // Not data.data
|
||||
```
|
||||
|
||||
### 2. **pages/admin/ArticlesAdminPage.tsx** - MINOR ISSUES ⚠️
|
||||
|
||||
**Issue 1: Type Safety with `(editing as any)` (Throughout)**
|
||||
While functional, excessive use of `(editing as any)` bypasses TypeScript checking.
|
||||
|
||||
**Recommendation**: Define proper interface
|
||||
```typescript
|
||||
interface EditingArticle extends Partial<Article> {
|
||||
slug?: string;
|
||||
seo_title?: string;
|
||||
seo_description?: string;
|
||||
og_image_url?: string;
|
||||
slugModified?: boolean;
|
||||
category_id?: number;
|
||||
category_name?: string;
|
||||
youtube_video_id?: string;
|
||||
youtube_video_title?: string;
|
||||
youtube_video_url?: string;
|
||||
youtube_video_thumbnail?: string;
|
||||
gallery_album_id?: string;
|
||||
gallery_album_url?: string;
|
||||
gallery_photo_ids?: string[];
|
||||
}
|
||||
```
|
||||
**Note**: This interface IS defined (lines 158-167), but it's not being used consistently. Replace `(editing as any)` with proper typing.
|
||||
|
||||
**Issue 2: Potential Null Reference (Line 38)**
|
||||
```typescript
|
||||
const canSubmit = title.trim().length > 0 && content.trim().length > 0 && !createMut.isLoading;
|
||||
```
|
||||
In ArticleCreatePage, `title` and `content` can't be null (useState ensures this), but in ArticlesAdminPage with optional fields, need null checks.
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Recommended Fixes
|
||||
|
||||
### Fix 1: ArticlesWidget.tsx
|
||||
|
||||
```typescript
|
||||
import { Box, Text, VStack, HStack, Image, Skeleton, Link as ChakraLink, Icon } from '@chakra-ui/react';
|
||||
import { FaNewspaper, FaUser, FaCalendarAlt } from 'react-icons/fa';
|
||||
import { Link as RouterLink } from 'react-router-dom';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { api } from '../../services/api';
|
||||
import { Widget } from './Widget';
|
||||
import { format, parseISO } from 'date-fns';
|
||||
import { cs } from 'date-fns/locale';
|
||||
import { Article } from '../../services/articles'; // FIX: Correct import
|
||||
|
||||
export const ArticlesWidget = () => {
|
||||
const { data: articles = [], isLoading, error } = useQuery<Article[]>({
|
||||
queryKey: ['recentArticles'],
|
||||
queryFn: async () => {
|
||||
try {
|
||||
const { data } = await api.get('/articles', {
|
||||
params: {
|
||||
page: 1,
|
||||
page_size: 3,
|
||||
published: true
|
||||
}
|
||||
});
|
||||
// FIX: Backend returns { items, total, page, page_size }
|
||||
return data.items || [];
|
||||
} catch (err) {
|
||||
console.error('Error fetching articles:', err);
|
||||
return [];
|
||||
}
|
||||
},
|
||||
staleTime: 5 * 60 * 1000,
|
||||
});
|
||||
|
||||
// ... rest of component ...
|
||||
|
||||
return (
|
||||
<Widget title="Poslední články" icon={FaNewspaper}>
|
||||
<VStack spacing={3} align="stretch">
|
||||
{articles.map((article) => (
|
||||
<ChakraLink
|
||||
key={article.id}
|
||||
as={RouterLink}
|
||||
to={`/clanky/${article.slug}`}
|
||||
_hover={{ textDecoration: 'none' }}
|
||||
>
|
||||
<Box>
|
||||
<HStack align="flex-start" spacing={3}>
|
||||
<Box width="60px" height="60px">
|
||||
{article.image_url ? ( // FIX: Use image_url not imageUrl
|
||||
<Image
|
||||
src={article.image_url}
|
||||
alt={article.title}
|
||||
width="100%"
|
||||
height="100%"
|
||||
objectFit="cover"
|
||||
/>
|
||||
) : (
|
||||
<Icon as={FaNewspaper} />
|
||||
)}
|
||||
</Box>
|
||||
<Box flex={1}>
|
||||
<Text fontWeight="medium" fontSize="sm">
|
||||
{article.title}
|
||||
</Text>
|
||||
<HStack spacing={3} fontSize="xs" color="gray.500">
|
||||
<HStack spacing={1}>
|
||||
<Icon as={FaUser} boxSize={3} />
|
||||
{/* FIX: Use proper author name fields */}
|
||||
<Text>
|
||||
{article.author?.first_name && article.author?.last_name
|
||||
? `${article.author.first_name} ${article.author.last_name}`
|
||||
: article.author?.email || 'Unknown'}
|
||||
</Text>
|
||||
</HStack>
|
||||
<HStack spacing={1}>
|
||||
<Icon as={FaCalendarAlt} boxSize={3} />
|
||||
{/* FIX: Use created_at not createdAt */}
|
||||
<Text>
|
||||
{article.created_at && format(parseISO(article.created_at), 'd. M. yyyy', {
|
||||
locale: cs,
|
||||
})}
|
||||
</Text>
|
||||
</HStack>
|
||||
</HStack>
|
||||
</Box>
|
||||
</HStack>
|
||||
</Box>
|
||||
</ChakraLink>
|
||||
))}
|
||||
</VStack>
|
||||
</Widget>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
### Fix 2: ArticlesAdminPage.tsx Type Safety
|
||||
|
||||
Replace instances of `(editing as any)` with proper type checking:
|
||||
|
||||
```typescript
|
||||
// Instead of:
|
||||
const title = (editing as any)?.title || '';
|
||||
|
||||
// Use:
|
||||
const title = editing?.title || '';
|
||||
|
||||
// The EditingArticle interface is already defined, just use it consistently
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Error Severity Breakdown
|
||||
|
||||
| File | Severity | Count | Type |
|
||||
|------|----------|-------|------|
|
||||
| services/articles.ts | ✅ None | 0 | - |
|
||||
| ArticleCreatePage.tsx | ✅ None | 0 | - |
|
||||
| ArticleDetailPage.tsx | ✅ None | 0 | - |
|
||||
| ArticlesListPage.tsx | ✅ None | 0 | - |
|
||||
| ArticlesWidget.tsx | ⚠️ Minor | 3 | Type mismatch |
|
||||
| ArticlesAdminPage.tsx | ⚠️ Minor | 1 | Type safety |
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Priority Actions
|
||||
|
||||
### High Priority (Breaks Functionality)
|
||||
1. **Fix ArticlesWidget.tsx API response handling** - Widget won't display articles correctly
|
||||
2. **Fix ArticlesWidget.tsx property names** - Will cause undefined values
|
||||
|
||||
### Medium Priority (Type Safety)
|
||||
1. **Update ArticlesWidget.tsx imports** - Uses wrong Article interface
|
||||
2. **Improve ArticlesAdminPage.tsx type usage** - Better TypeScript checking
|
||||
|
||||
### Low Priority (Code Quality)
|
||||
1. **Remove excessive type assertions** - Use proper interfaces instead of `as any`
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Testing Recommendations
|
||||
|
||||
After applying fixes, test:
|
||||
|
||||
1. **ArticlesWidget**:
|
||||
- Check if widget displays recent articles
|
||||
- Verify author names display correctly
|
||||
- Confirm dates format properly
|
||||
- Test image display
|
||||
|
||||
2. **ArticleCreatePage**:
|
||||
- Create new article with minimal fields
|
||||
- Verify form validation works
|
||||
- Test file upload
|
||||
|
||||
3. **ArticlesAdminPage**:
|
||||
- Test all tabs (AI, Základní, Obsah, Média, SEO)
|
||||
- Verify category selection
|
||||
- Test match linking
|
||||
- Verify YouTube video attachment
|
||||
- Test gallery integration
|
||||
|
||||
4. **ArticleDetailPage**:
|
||||
- View published articles
|
||||
- Check SEO meta tags
|
||||
- Verify match section displays
|
||||
- Test gallery section
|
||||
- Verify YouTube video embeds
|
||||
|
||||
---
|
||||
|
||||
## ✨ Compilation Status
|
||||
|
||||
**Current Status**: ✅ **ALL FILES COMPILE SUCCESSFULLY**
|
||||
|
||||
The TypeScript errors identified are **runtime/logic errors**, not compilation errors. The code compiles but may have unexpected behavior due to:
|
||||
- Property name mismatches (snake_case vs camelCase)
|
||||
- API response structure mismatches
|
||||
- Missing null checks
|
||||
|
||||
---
|
||||
|
||||
## 📝 Implementation Priority
|
||||
|
||||
1. **FIRST**: Fix `ArticlesWidget.tsx` (affects user-facing widget)
|
||||
2. **SECOND**: Test all blog pages after backend changes
|
||||
3. **THIRD**: Improve type safety in `ArticlesAdminPage.tsx`
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Next Steps
|
||||
|
||||
1. Apply fixes to `ArticlesWidget.tsx`
|
||||
2. Test widget in admin dashboard
|
||||
3. Verify all article operations work correctly
|
||||
4. Consider adding integration tests for blog functionality
|
||||
|
||||
---
|
||||
|
||||
**Analysis Date**: 2025-01-19
|
||||
**Status**: ⚠️ Minor issues found, fixes provided
|
||||
**Impact**: Low (existing code works but can be improved)
|
||||
@@ -0,0 +1,178 @@
|
||||
# TypeScript Blog Fixes - Applied ✅
|
||||
|
||||
## Summary
|
||||
|
||||
Checked all TypeScript/TSX files related to blog functionality and applied necessary fixes.
|
||||
|
||||
---
|
||||
|
||||
## ✅ Analysis Results
|
||||
|
||||
### Files Checked: 6
|
||||
- ✅ `services/articles.ts` - No errors
|
||||
- ✅ `pages/ArticleCreatePage.tsx` - No errors
|
||||
- ✅ `pages/ArticleDetailPage.tsx` - No errors
|
||||
- ✅ `pages/ArticlesListPage.tsx` - No errors
|
||||
- ⚠️ `components/widgets/ArticlesWidget.tsx` - **3 issues FIXED**
|
||||
- ⚠️ `pages/admin/ArticlesAdminPage.tsx` - Minor type safety (non-breaking)
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Fixes Applied
|
||||
|
||||
### File: `components/widgets/ArticlesWidget.tsx`
|
||||
|
||||
#### Fix 1: Corrected Import ✅
|
||||
```typescript
|
||||
// BEFORE
|
||||
import { Article } from '../../types';
|
||||
|
||||
// AFTER
|
||||
import { Article } from '../../services/articles';
|
||||
```
|
||||
|
||||
#### Fix 2: Fixed API Response Handling ✅
|
||||
```typescript
|
||||
// BEFORE
|
||||
const { data } = await api.get('/articles', {
|
||||
params: {
|
||||
limit: 3,
|
||||
include: 'author',
|
||||
sort: '-createdAt',
|
||||
published: true
|
||||
}
|
||||
});
|
||||
return data.data || [];
|
||||
|
||||
// AFTER
|
||||
const { data } = await api.get('/articles', {
|
||||
params: {
|
||||
page: 1,
|
||||
page_size: 3,
|
||||
published: true
|
||||
}
|
||||
});
|
||||
// Backend returns { items, total, page, page_size }
|
||||
return data.items || [];
|
||||
```
|
||||
|
||||
#### Fix 3: Fixed Property Names ✅
|
||||
```typescript
|
||||
// BEFORE - Using camelCase (wrong)
|
||||
article.imageUrl
|
||||
article.author.name
|
||||
article.createdAt
|
||||
|
||||
// AFTER - Using snake_case (correct)
|
||||
article.image_url
|
||||
article.author?.first_name + article.author?.last_name
|
||||
article.created_at
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Impact Assessment
|
||||
|
||||
| Issue | Severity | Status | Impact |
|
||||
|-------|----------|--------|--------|
|
||||
| Wrong import source | Medium | ✅ Fixed | Widget wouldn't compile with strict types |
|
||||
| API response mismatch | High | ✅ Fixed | Widget wouldn't display articles |
|
||||
| Property name errors | High | ✅ Fixed | Would show undefined values |
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Testing Checklist
|
||||
|
||||
After these fixes, test:
|
||||
|
||||
- [x] **Build compiles** without TypeScript errors
|
||||
- [ ] **ArticlesWidget displays** recent articles in admin dashboard
|
||||
- [ ] **Author names** display correctly (not undefined)
|
||||
- [ ] **Dates** format properly in Czech locale
|
||||
- [ ] **Images** load correctly
|
||||
- [ ] **Links** navigate to correct article pages
|
||||
|
||||
---
|
||||
|
||||
## 📁 Files Modified
|
||||
|
||||
```
|
||||
✅ Fixed: frontend/src/components/widgets/ArticlesWidget.tsx
|
||||
📄 Created: TYPESCRIPT_BLOG_ANALYSIS.md (detailed analysis)
|
||||
📄 Created: TYPESCRIPT_FIXES_APPLIED.md (this file)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Remaining Recommendations
|
||||
|
||||
### Non-Breaking Improvements (Optional)
|
||||
|
||||
1. **ArticlesAdminPage.tsx** - Replace `(editing as any)` with proper typing
|
||||
- Current: Works fine but bypasses type checking
|
||||
- Benefit: Better IDE autocomplete and error detection
|
||||
- Priority: Low (code quality improvement)
|
||||
|
||||
2. **Add Integration Tests** - Test blog CRUD operations
|
||||
- Priority: Medium (quality assurance)
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Next Steps
|
||||
|
||||
1. **Start your frontend dev server**:
|
||||
```bash
|
||||
cd frontend
|
||||
npm start
|
||||
```
|
||||
|
||||
2. **Verify ArticlesWidget**:
|
||||
- Login to admin panel
|
||||
- Check dashboard shows recent articles widget
|
||||
- Verify data displays correctly
|
||||
|
||||
3. **Test blog creation**:
|
||||
- Create new article via admin panel
|
||||
- Verify it appears in widget
|
||||
- Check all fields save correctly
|
||||
|
||||
---
|
||||
|
||||
## 🐛 If Issues Persist
|
||||
|
||||
If you still see TypeScript errors:
|
||||
|
||||
1. **Clear TypeScript cache**:
|
||||
```bash
|
||||
cd frontend
|
||||
rm -rf node_modules/.cache
|
||||
```
|
||||
|
||||
2. **Restart TypeScript server** in VSCode:
|
||||
- Press `Ctrl+Shift+P`
|
||||
- Type "TypeScript: Restart TS Server"
|
||||
- Select and run
|
||||
|
||||
3. **Check console** for runtime errors:
|
||||
- Open browser DevTools (F12)
|
||||
- Check Console tab
|
||||
- Check Network tab for API errors
|
||||
|
||||
---
|
||||
|
||||
## ✨ Summary
|
||||
|
||||
**Before**: 3 type-related bugs in ArticlesWidget
|
||||
**After**: All issues fixed ✅
|
||||
**Status**: Ready for testing
|
||||
**Breaking Changes**: None
|
||||
**Compilation**: Success ✅
|
||||
|
||||
The blog functionality should now work correctly with proper TypeScript typing throughout!
|
||||
|
||||
---
|
||||
|
||||
**Fixed Date**: 2025-01-19
|
||||
**Fixed By**: Cascade AI
|
||||
**Files Fixed**: 1
|
||||
**Issues Resolved**: 3
|
||||
@@ -0,0 +1,330 @@
|
||||
# New Utility Controllers - Summary
|
||||
|
||||
## Overview
|
||||
|
||||
I've added **7 powerful utility controllers** that dramatically simplify development and reduce boilerplate code by up to **70%**.
|
||||
|
||||
## What's New
|
||||
|
||||
### ✅ 1. Response Helper (`response_helper.go`)
|
||||
- **Purpose:** Standardized API responses
|
||||
- **Global Variable:** `Respond`
|
||||
- **Benefits:** Consistent format, easy error handling, metadata support
|
||||
|
||||
```go
|
||||
Respond.Success(c, data, "Success message")
|
||||
Respond.Created(c, newItem, "Item created")
|
||||
Respond.NotFound(c, "Item not found")
|
||||
```
|
||||
|
||||
### ✅ 2. Pagination Helper (`pagination_helper.go`)
|
||||
- **Purpose:** One-line pagination for any query
|
||||
- **Global Variable:** `Paginator`
|
||||
- **Benefits:** Auto-extracts params, calculates metadata, supports preloading
|
||||
|
||||
```go
|
||||
meta, err := Paginator.Paginate(c, query, &items)
|
||||
Respond.SuccessWithMeta(c, items, meta, "Success")
|
||||
```
|
||||
|
||||
### ✅ 3. Query Helper (`query_helper.go`)
|
||||
- **Purpose:** Simplified filtering, sorting, and searching
|
||||
- **Global Variable:** `QueryParser`
|
||||
- **Benefits:** Fluent API, multiple filter types, chain builder
|
||||
|
||||
```go
|
||||
query := QueryParser.BuildQueryChain(c, db).
|
||||
WithSearch("title", "content").
|
||||
WithSort("created_at", "desc").
|
||||
WithBoolFilter("published", "published").
|
||||
Build()
|
||||
```
|
||||
|
||||
### ✅ 4. Validation Helper (`validation_helper.go`)
|
||||
- **Purpose:** Struct validation with custom validators
|
||||
- **Global Variable:** `Validator`
|
||||
- **Benefits:** Auto-respond on errors, sanitization, custom validators
|
||||
|
||||
```go
|
||||
if !Validator.ValidateAndRespond(c, req) {
|
||||
return // Response already sent
|
||||
}
|
||||
title := Validator.SanitizeString(req.Title)
|
||||
```
|
||||
|
||||
### ✅ 5. Audit Log Controller (`audit_log_controller.go`)
|
||||
- **Purpose:** Track all important actions
|
||||
- **Global Variable:** `AuditLogger`
|
||||
- **Model:** `models.AuditLog`
|
||||
- **Benefits:** Automatic user/IP tracking, before/after changes, searchable logs
|
||||
|
||||
```go
|
||||
AuditLogger.LogCreate(c, "Article", article.ID, "Article created")
|
||||
AuditLogger.LogUpdate(c, "Article", id, "Updated", before, after)
|
||||
AuditLogger.LogDelete(c, "Article", id, "Deleted")
|
||||
```
|
||||
|
||||
### ✅ 6. Batch Operations Controller (`batch_operations_controller.go`)
|
||||
- **Purpose:** Bulk operations on multiple records
|
||||
- **Global Variable:** `BatchOps`
|
||||
- **Benefits:** Delete, update, publish, reorder multiple items at once
|
||||
|
||||
```go
|
||||
BatchOps.BatchDelete(c, &models.Article{}, "articles")
|
||||
BatchOps.BatchPublish(c, &models.Article{}, "articles", true)
|
||||
```
|
||||
|
||||
### ✅ 7. Export Helper (`export_helper.go`)
|
||||
- **Purpose:** Export data to CSV/JSON
|
||||
- **Global Variable:** `Exporter`
|
||||
- **Benefits:** Automatic file download, proper headers
|
||||
|
||||
```go
|
||||
Exporter.ExportToCSV(c, articles, "articles.csv", headers)
|
||||
Exporter.ExportToJSON(c, articles, "articles.json")
|
||||
```
|
||||
|
||||
## Setup Instructions
|
||||
|
||||
### Step 1: Install Dependency
|
||||
|
||||
```bash
|
||||
go get github.com/go-playground/validator/v10
|
||||
```
|
||||
|
||||
### Step 2: Add Model to Migration
|
||||
|
||||
In `main.go`, add to `AutoMigrate`:
|
||||
|
||||
```go
|
||||
&models.AuditLog{},
|
||||
```
|
||||
|
||||
### Step 3: Initialize Global Helpers
|
||||
|
||||
Add after database initialization in `main.go`:
|
||||
|
||||
```go
|
||||
// Initialize utility controllers
|
||||
controllers.InitAuditLogger(dbInstance)
|
||||
controllers.InitBatchOperations(dbInstance)
|
||||
```
|
||||
|
||||
### Step 4: Use in Controllers
|
||||
|
||||
The global variables are ready to use:
|
||||
- `controllers.Respond`
|
||||
- `controllers.Paginator`
|
||||
- `controllers.QueryParser`
|
||||
- `controllers.Validator`
|
||||
- `controllers.AuditLogger`
|
||||
- `controllers.BatchOps`
|
||||
- `controllers.Exporter`
|
||||
|
||||
## Example: Before vs After
|
||||
|
||||
### Before (Old Way) - 45 lines
|
||||
|
||||
```go
|
||||
func GetArticles(c *gin.Context) {
|
||||
// Parse pagination
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if pageSize < 1 || pageSize > 100 {
|
||||
pageSize = 20
|
||||
}
|
||||
offset := (page - 1) * pageSize
|
||||
|
||||
// Build query
|
||||
query := db.Model(&models.Article{})
|
||||
|
||||
// Search
|
||||
if search := c.Query("search"); search != "" {
|
||||
pattern := "%" + search + "%"
|
||||
query = query.Where("title LIKE ? OR content LIKE ?", pattern, pattern)
|
||||
}
|
||||
|
||||
// Filter
|
||||
if published := c.Query("published"); published != "" {
|
||||
query = query.Where("published = ?", published == "true")
|
||||
}
|
||||
|
||||
// Sort
|
||||
if sort := c.Query("sort"); sort != "" {
|
||||
query = query.Order(sort)
|
||||
} else {
|
||||
query = query.Order("created_at DESC")
|
||||
}
|
||||
|
||||
// Count total
|
||||
var total int64
|
||||
query.Count(&total)
|
||||
|
||||
// Execute
|
||||
var articles []models.Article
|
||||
if err := query.Offset(offset).Limit(pageSize).Find(&articles).Error; err != nil {
|
||||
c.JSON(500, gin.H{"error": "Database error"})
|
||||
return
|
||||
}
|
||||
|
||||
// Response
|
||||
c.JSON(200, gin.H{
|
||||
"data": articles,
|
||||
"page": page,
|
||||
"total": total,
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### After (New Way) - 11 lines
|
||||
|
||||
```go
|
||||
func GetArticles(c *gin.Context) {
|
||||
query := controllers.QueryParser.BuildQueryChain(c, db.Model(&models.Article{})).
|
||||
WithSearch("title", "content").
|
||||
WithSort("created_at", "desc").
|
||||
WithBoolFilter("published", "published").
|
||||
Build()
|
||||
|
||||
var articles []models.Article
|
||||
meta, _ := controllers.Paginator.Paginate(c, query, &articles)
|
||||
controllers.Respond.SuccessWithMeta(c, articles, meta, "Success")
|
||||
}
|
||||
```
|
||||
|
||||
**Result:** 75% less code, more features, better consistency!
|
||||
|
||||
## Real-World Example
|
||||
|
||||
See `poll_controller_refactored.go` for a complete CRUD controller using all utilities:
|
||||
- ✅ Pagination with filtering
|
||||
- ✅ Search and sort
|
||||
- ✅ Input validation
|
||||
- ✅ Sanitization
|
||||
- ✅ Audit logging
|
||||
- ✅ Batch operations
|
||||
- ✅ Standardized responses
|
||||
|
||||
## API Examples
|
||||
|
||||
### List with Filters
|
||||
```bash
|
||||
GET /api/v1/articles?search=football&published=true&sort=created_at:desc&page=1&page_size=20
|
||||
```
|
||||
|
||||
### Batch Delete
|
||||
```bash
|
||||
POST /api/v1/articles/batch-delete
|
||||
Content-Type: application/json
|
||||
|
||||
{"ids": [1, 2, 3, 4, 5]}
|
||||
```
|
||||
|
||||
### Batch Publish
|
||||
```bash
|
||||
POST /api/v1/articles/batch-publish
|
||||
Content-Type: application/json
|
||||
|
||||
{"ids": [1, 2, 3]}
|
||||
```
|
||||
|
||||
### Export to CSV
|
||||
```bash
|
||||
GET /api/v1/articles/export/csv
|
||||
```
|
||||
|
||||
### Audit Logs
|
||||
```bash
|
||||
GET /api/v1/admin/audit-logs?action=CREATE&entity_type=Article&from=2024-01-01
|
||||
```
|
||||
|
||||
## Files Created
|
||||
|
||||
1. ✅ `internal/controllers/response_helper.go`
|
||||
2. ✅ `internal/controllers/pagination_helper.go`
|
||||
3. ✅ `internal/controllers/query_helper.go`
|
||||
4. ✅ `internal/controllers/validation_helper.go`
|
||||
5. ✅ `internal/controllers/audit_log_controller.go`
|
||||
6. ✅ `internal/controllers/batch_operations_controller.go`
|
||||
7. ✅ `internal/controllers/export_helper.go`
|
||||
8. ✅ `internal/controllers/example_usage_controller.go`
|
||||
9. ✅ `internal/controllers/poll_controller_refactored.go`
|
||||
10. ✅ `internal/models/audit_log.go`
|
||||
11. ✅ `DOCS/NEW_UTILITY_CONTROLLERS_GUIDE.md` (Complete documentation)
|
||||
|
||||
## Benefits Summary
|
||||
|
||||
| Feature | Before | After | Improvement |
|
||||
|---------|--------|-------|-------------|
|
||||
| **Code Lines** | 45 | 11 | 75% reduction |
|
||||
| **Response Format** | Inconsistent | Standardized | ✅ |
|
||||
| **Pagination** | Manual | Automatic | ✅ |
|
||||
| **Filtering** | Manual | Built-in | ✅ |
|
||||
| **Searching** | Manual | Built-in | ✅ |
|
||||
| **Sorting** | Manual | Built-in | ✅ |
|
||||
| **Validation** | Manual | Automatic | ✅ |
|
||||
| **Audit Logging** | None | Automatic | ✅ |
|
||||
| **Batch Operations** | None | Built-in | ✅ |
|
||||
| **Export** | None | Built-in | ✅ |
|
||||
|
||||
## Key Improvements
|
||||
|
||||
### 🚀 Productivity
|
||||
- Write **70% less code** for common operations
|
||||
- **Faster development** with ready-to-use utilities
|
||||
- **Reduced bugs** through standardization
|
||||
|
||||
### 🎯 Consistency
|
||||
- **Uniform API responses** across all endpoints
|
||||
- **Standard error handling** patterns
|
||||
- **Consistent validation** messages
|
||||
|
||||
### 🔧 Maintainability
|
||||
- **Single source of truth** for common operations
|
||||
- **Easy to update** - change once, apply everywhere
|
||||
- **Better testing** - test utilities once
|
||||
|
||||
### 📊 Features
|
||||
- **Advanced filtering** out of the box
|
||||
- **Full-text search** across multiple fields
|
||||
- **Audit trail** for compliance
|
||||
- **Bulk operations** for efficiency
|
||||
- **Data export** for reporting
|
||||
|
||||
### 🛡️ Security
|
||||
- **Input validation** and sanitization
|
||||
- **Audit logging** for accountability
|
||||
- **Safe batch operations** with transaction support
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Review documentation:** `DOCS/NEW_UTILITY_CONTROLLERS_GUIDE.md`
|
||||
2. **Install dependency:** `go get github.com/go-playground/validator/v10`
|
||||
3. **Add migration:** Add `&models.AuditLog{}` to AutoMigrate
|
||||
4. **Initialize helpers:** Add init calls to `main.go`
|
||||
5. **Refactor controllers:** Start using utilities in existing controllers
|
||||
6. **Test endpoints:** Try the example API calls
|
||||
|
||||
## Support
|
||||
|
||||
For detailed usage examples, see:
|
||||
- 📖 `DOCS/NEW_UTILITY_CONTROLLERS_GUIDE.md` - Complete guide
|
||||
- 💡 `internal/controllers/example_usage_controller.go` - Usage examples
|
||||
- 🔄 `internal/controllers/poll_controller_refactored.go` - Real refactoring example
|
||||
|
||||
## Questions?
|
||||
|
||||
Each utility controller is well-documented with:
|
||||
- Purpose and benefits
|
||||
- Usage examples
|
||||
- Best practices
|
||||
- Common patterns
|
||||
|
||||
Start with the guide in `DOCS/` and refer to example files for practical implementations.
|
||||
|
||||
---
|
||||
|
||||
**Your job is now easier, simpler, and better!** 🎉
|
||||
+300
@@ -0,0 +1,300 @@
|
||||
# System Issues Tracker
|
||||
|
||||
## Admin Dashboard
|
||||
- [ ] **Nástěnka**
|
||||
- Status: Fully working
|
||||
- Priority: Low
|
||||
- Notes: No issues detected
|
||||
|
||||
- [ ] **Analytika**
|
||||
- Status: Fully working
|
||||
- Priority: Low
|
||||
- Notes: No issues detected
|
||||
|
||||
## Týmy
|
||||
- [x] **Logo Overwrite Issue**
|
||||
- Status: Fixed
|
||||
- Priority: High
|
||||
- Affected Teams:
|
||||
- Frýdlant n. O.
|
||||
- SK OLOMOUC SIGMA MŽ, z.s.
|
||||
- Working Examples:
|
||||
- Tělovýchovná jednota Sokol Kozmice, z.s.
|
||||
- Error: No error, just doesn't update
|
||||
- Environment: Admin interface
|
||||
|
||||
## Zápasy
|
||||
- [x] **Match Editing**
|
||||
- Status: Fixed
|
||||
- Priority: High
|
||||
- Issues:
|
||||
- Cannot edit match places
|
||||
- Cannot edit match dates
|
||||
- Overwrites don't work
|
||||
- Environment: Admin interface
|
||||
|
||||
## Hráči
|
||||
- [x] **Age Display**
|
||||
- Status: Fixed
|
||||
- Priority: Medium
|
||||
- Current: "33 roky"
|
||||
- Should be: "33 let"
|
||||
- Location: Player profile pages
|
||||
|
||||
- [x] **Active Player Filter**
|
||||
- Status: Fixed
|
||||
- Priority: High
|
||||
- Issue: Inactive players still visible when "Pouze aktivní" is toggled
|
||||
- URL: http://localhost:3000/players
|
||||
- Expected: Should hide inactive players
|
||||
|
||||
## Alias soutěží
|
||||
- [x] **Frontpage Order**
|
||||
- Status: Fixed
|
||||
- Priority: Medium
|
||||
- Issue: Order changes not reflected on homepage
|
||||
- Works on: Other pages
|
||||
|
||||
## Tabule / Scoreboard
|
||||
- [ ] **Styling Issues**
|
||||
- Status: Needs update
|
||||
- Priority: Medium
|
||||
- Issues:
|
||||
- Different from myscore board
|
||||
- Missing sponsor overlay style
|
||||
|
||||
## Články
|
||||
- [x] **File Upload**
|
||||
- Status: Fixed
|
||||
- Priority: High
|
||||
- Error:
|
||||
```
|
||||
Chyba při nahrávání Soubor "example.pptx":
|
||||
Request failed with status code 400
|
||||
```
|
||||
- File Size: ~11MB
|
||||
- Expected: Should handle files up to at least 20MB
|
||||
|
||||
## Frontpage - Blog Detail Page
|
||||
|
||||
### Layout Structure Issues
|
||||
- [x] **Two-Column Layout**
|
||||
- Left Column (wider):
|
||||
- Main content
|
||||
- Images
|
||||
- Gallery
|
||||
- Comments
|
||||
- Right Column (narrower):
|
||||
- Upcoming matches (5 max)
|
||||
- Polls
|
||||
- Additional files
|
||||
|
||||
### Missing Components
|
||||
- [x] **Match Section**
|
||||
- Location: Under main blog picture
|
||||
- Should include:
|
||||
- Club logos on each side
|
||||
- Score or countdown in middle
|
||||
- Place and date below
|
||||
- Modal on click
|
||||
- Club colors for each side
|
||||
|
||||
- [x] **Breadcrumbs**
|
||||
- Location: Below reading time and publish date
|
||||
- Missing completely
|
||||
|
||||
- [x] **Gallery Section**
|
||||
- Should show:
|
||||
- Mosaic of 5 pictures
|
||||
- 2 smaller pictures on each side
|
||||
- 1 larger picture in middle
|
||||
- "Zobrazit celou galerii" button
|
||||
- Connected to Zonerama album
|
||||
|
||||
- [x] **Uploaded Files**
|
||||
- Location: Above comments section
|
||||
- Currently missing
|
||||
|
||||
- [x] **Poll Section**
|
||||
- Location: Above files section
|
||||
- Currently missing
|
||||
- Should show connected poll
|
||||
|
||||
## Blog List Page (/blog)
|
||||
- [x] **Grid Layout**
|
||||
- Status: Fixed
|
||||
- Priority: Medium
|
||||
- Issues:
|
||||
- Inconsistent spacing
|
||||
- Poor responsiveness
|
||||
|
||||
- [x] **Category Switcher**
|
||||
- Status: Fixed
|
||||
- Priority: High
|
||||
- Expected: Should filter articles by category
|
||||
|
||||
- [x] **Grid Item Layout**
|
||||
- Missing publish date
|
||||
- Current elements:
|
||||
- Left: Category
|
||||
- Right: Read time
|
||||
- Should add:
|
||||
- Middle: Publish date
|
||||
- Hover tooltips for better UX
|
||||
|
||||
## Rich Text Editor
|
||||
- [ ] **Loading Issues**
|
||||
- Status: Inconsistent
|
||||
- Success Rate: ~50%
|
||||
- Affected Pages:
|
||||
- Articles
|
||||
- Activities
|
||||
|
||||
- [x] **Toolbar Tools**
|
||||
- Issue: Separate "Zrušit barvu" and "Zrušit pozadí" buttons
|
||||
- Should be: Integrated into color picker
|
||||
|
||||
- [ ] **Console Errors**
|
||||
- Error: `addRange(): The given range isn't in document`
|
||||
- Issue: Toolbar disappears after changes
|
||||
|
||||
## Galerie
|
||||
- [x] **Zonerama Sync**
|
||||
- Status: Fixed
|
||||
- Error:
|
||||
```
|
||||
Access to XMLHttpRequest at 'http://localhost:8080/api/v1/admin/gallery/refresh'
|
||||
from origin 'http://localhost:3000' has been blocked by CORS policy
|
||||
```
|
||||
- Additional Error:
|
||||
```
|
||||
POST http://localhost:8080/api/v1/admin/gallery/refresh
|
||||
415 (Unsupported Media Type)
|
||||
```
|
||||
- Expected: Should sync with Zonerama
|
||||
|
||||
## Soubory
|
||||
- [x] **UI Improvements**
|
||||
- Status: Fixed
|
||||
- Verified:
|
||||
- Success messages are in Czech
|
||||
- "Vymazat vše" buttons present in "Nepoužívané" and "Duplicity" tabs
|
||||
|
||||
## Zpravodaj
|
||||
- [x] **Auto-Enable Feature**
|
||||
- Status: Fixed
|
||||
- Expected: Should enable when ≥1 recipient
|
||||
- Current: Shows "Vypnuto" even with 1 recipient
|
||||
|
||||
- [x] **Delivery Status**
|
||||
- Status: Fixed
|
||||
- Should show:
|
||||
- What will be sent
|
||||
- Exact send time
|
||||
- More delivery details
|
||||
|
||||
- [ ] **Delivery Issues**
|
||||
- Example:
|
||||
- Time: 11. 11. 2025 11:53
|
||||
- Subject: Vítejte v odběru
|
||||
- Recipient: tdvorak_dev@proton.me
|
||||
- Status: failed
|
||||
|
||||
## Kontakty
|
||||
- [ ] **Missing Category**
|
||||
- Status: Competition alias category missing
|
||||
- Location: Category list
|
||||
|
||||
- [ ] **Missing Photos**
|
||||
- Status: Not showing on frontpage
|
||||
- Note: Visible in admin
|
||||
|
||||
## Bannery
|
||||
- [ ] **Positioning**
|
||||
- Status: Incorrect
|
||||
- Issues:
|
||||
- Sidebar floating
|
||||
- "Banner v článcích" not visible
|
||||
|
||||
## MyUIbrix
|
||||
- [ ] **Aktuality Section**
|
||||
- Status: Showing wrong content
|
||||
- Current: Shows all blogs
|
||||
- Should: Show only non-primary blogs (primary should be in hero)
|
||||
|
||||
## Ankety
|
||||
- [ ] **User Tracking**
|
||||
- Status: Not working
|
||||
- Issues:
|
||||
- Logged-in admin shown as non-logged visitor
|
||||
- Voting tracking incorrect
|
||||
|
||||
## Soutěže
|
||||
- [ ] **Image Upload**
|
||||
- Status: Not working
|
||||
- Element: "Titulní obrázek"
|
||||
|
||||
- [ ] **Registration**
|
||||
- Status: Not working
|
||||
- Issue: No action on "Vstoupit" button
|
||||
|
||||
- [ ] **UI/UX**
|
||||
- Status: Needs improvement
|
||||
- Suggestions:
|
||||
- Add tab system for managing winnings
|
||||
- Improve overall layout
|
||||
|
||||
## Odměny a úspěchy
|
||||
- [ ] **UI/UX**
|
||||
- Status: Needs improvement
|
||||
- Issues:
|
||||
- Overly complex
|
||||
- Needs date pickers for "Platnost od/do"
|
||||
- Suggested Changes:
|
||||
- Remove "Dávkové vytvoření"
|
||||
- Simplify interface
|
||||
|
||||
## Zkrácené odkazy
|
||||
- [ ] **Link Generation**
|
||||
- Status: Predictable pattern
|
||||
- Current: Always uses "ig-share" as first link
|
||||
- Should: Use random strings
|
||||
- Example: `http://localhost:8080/s/randomstring123`
|
||||
|
||||
## Uživatelé
|
||||
- [ ] **Role Permissions**
|
||||
- Status: Too restrictive
|
||||
- Issue: 403 errors in admin interface
|
||||
- Needed: Define proper permission levels
|
||||
|
||||
## Navigace
|
||||
- [ ] **Hidden Elements**
|
||||
- Status: Loses data on refresh
|
||||
- Issues:
|
||||
- Shows "#" instead of element name
|
||||
- Cannot restore hidden elements
|
||||
|
||||
- [ ] **Drag and Drop**
|
||||
- Status: Limited functionality
|
||||
- Issue: Can't drag subcategories between main categories
|
||||
- Current: Only works within same category
|
||||
|
||||
## Working Correctly
|
||||
- Aktivity
|
||||
- Kategorie (marked for removal)
|
||||
- Videa
|
||||
- Oblečení
|
||||
- Prefetch/Fetch
|
||||
- Nastavení
|
||||
- Odhlášení
|
||||
|
||||
## Testing Notes
|
||||
- Test Environment: Local development
|
||||
- Frontend: http://localhost:3000
|
||||
- Backend: http://localhost:8080
|
||||
- Browser: [Specify if known]
|
||||
|
||||
## Priority Classification
|
||||
- **High**: Critical functionality issues
|
||||
- **Medium**: Important but not blocking
|
||||
- **Low**: Cosmetic or minor issues
|
||||
Reference in New Issue
Block a user