6d25a499b2
BREAKING CHANGE: Replaced all direct useNavigate() usage with HandleNavigate hook
## Summary
- Complete frontend navigation refactoring
- Centralized route management with routes.js
- Converted 18+ components to use HandleNavigate
- Enhanced navigation with 20+ type-safe functions
## New Files
- src/utils/routes.js - Central route constants and helpers
- Documentations/FRONTEND_CODING_GUIDELINES.md - Frontend best practices (300+ lines)
- Documentations/NAVIGATION_REFACTORING_REPORT.md - Detailed refactoring report (400+ lines)
## Modified Components (18+)
### Pages
- Home.jsx, LoginForm.jsx, RegisterForm.jsx
- ResetPassword.jsx, VerifyEmailPage.jsx
- DeckCreator.jsx, Card_display.jsx
- Lobby.jsx, GameTest.jsx, ChooseDeck.jsx, PlayerSetup.jsx
- Landingpage.jsx
### Components
- Userdetails.jsx, DeckInfoPopUp.jsx
- PlayMenu.jsx, LandingPage.jsx, DeckManager.jsx
### Hooks
- useRequireAuth.jsx
### Core
- App.jsx - Route constants integration
- HandleNavigate.jsx - Enhanced with 20+ navigation functions
## Key Improvements
Type-safe navigation (goDeckDetails(id) vs navigate('/deck/'+id))
Automatic scroll management
Centralized state passing
Single source of truth for routes
Backwards compatibility aliases
Zero compile errors
Production ready
## Validation
- useNavigate: Only in HandleNavigate.jsx
- navigate() calls: 0 direct usage
- Compile errors: 0
- Documentation: Complete
14 KiB
14 KiB
Frontend Kódolási Útmutató - SerpentRace
Tartalomjegyzék
- Navigáció és Routing
- Fájl és Mappa Struktúra
- Komponens Konvenciók
- State Management
- API Hívások
- Hibakezelés
- Elnevezési Konvenciók
Navigáció és Routing
✅ Helyes gyakorlat: HandleNavigate használata
MINDIG használd a központosított HandleNavigate hook-ot navigációhoz:
import HandleNavigate from "../../utils/HandleNavigate/HandleNavigate"
const MyComponent = () => {
const { goHome, goLogin, goDeckDetails } = HandleNavigate()
const handleClick = () => {
goHome() // Egyszerű navigáció
}
const handleDeckView = (deckId) => {
goDeckDetails(deckId) // Dinamikus route paraméterrel
}
const handleLobby = (gameCode) => {
goLobby({ gameCode }) // State passzolással
}
}
❌ Kerülendő: Direkt useNavigate használat
// SOHA NE HASZNÁLD EZT!
import { useNavigate } from "react-router-dom"
const MyComponent = () => {
const navigate = useNavigate()
navigate("/home") // ❌ NEM JÓ!
}
Elérhető Navigációs Függvények
HandleNavigate által biztosított függvények:
const {
// Általános
goTo, // goTo('/any-path', { state: {...} })
goBack, // Vissza az előző oldalra
// Authentikáció
goHome, // → /home
goLogin, // → /login, state: { success, message }
goRegister, // → /register (alias: goAuth)
goLanding, // → / (landing page)
// Deck Management
goDecks, // → /decks
goDeckDetails, // goDeckDetails(deckId) → /deck/:deckId
goDeckCreator, // → /deck-creator
goDeckCreatorEdit, // goDeckCreatorEdit(deckId) → /deck-creator/:deckId
// Game Flow
goLobby, // goLobby({ gameCode }) → /lobby
goChooseDeck, // goChooseDeck({ username, deckIds }) → /choosedeck
goPlayerSetup, // goPlayerSetup({ deckIds }) → /player-setup
goGame, // goGame({ players, gameState }) → /game
// Egyéb
goContacts // → /contacts (alias: goCompanies)
} = HandleNavigate()
Route Konstansok
Használd a centralizált route konstansokat:
// src/utils/routes.js
import { ROUTES } from '../../utils/routes'
// App.jsx-ben
<Route path={ROUTES.HOME} element={<Home />} />
<Route path={ROUTES.DECK_DETAILS} element={<DeckDetails />} />
// ❌ NE használj string literálokat:
<Route path="/home" element={<Home />} /> // NEM JÓ!
State Passzolás
Így adj át adatokat navigáció során:
// Régi mód (useNavigate) - ❌ NE!
navigate('/lobby', { state: { gameCode: 'ABC123' } })
// Új mód (HandleNavigate) - ✅ JÓ!
goLobby({ gameCode: 'ABC123' })
// Fogadó oldalon:
import { useLocation } from 'react-router-dom'
const Lobby = () => {
const location = useLocation()
const gameCode = location.state?.gameCode
}
Fájl és Mappa Struktúra
Mappa Szervezés
src/
├── api/ # API hívások
│ ├── userApi.js
│ ├── deckApi.js
│ └── gameApi.js
├── assets/ # Statikus fájlok
│ ├── backgrounds/
│ ├── images/
│ └── icons/
├── components/ # Újrahasználható komponensek
│ ├── Buttons/
│ ├── Inputs/
│ ├── Navbar/
│ └── PopUp/
├── hooks/ # Custom Hooks
│ └── useRequireAuth.jsx
├── pages/ # Oldal komponensek
│ ├── Auth/
│ ├── Game/
│ ├── Decks/
│ └── Landing/
├── utils/ # Utility függvények
│ ├── HandleNavigate/
│ └── routes.js
└── App.jsx # Fő alkalmazás komponens
Fájl Elnevezési Konvenciók
-
Komponensek: PascalCase
LoginForm.jsx,DeckCreator.jsx,ButtonGreen.jsx
-
Utility fájlok: camelCase
routes.js,randomUtils.js,userApi.js
-
Hook fájlok: camelCase, "use" prefix
useRequireAuth.jsx,useLocalStorage.jsx
Komponens Konvenciók
Funkcionális Komponens Sablon
import React, { useState, useEffect } from 'react'
import HandleNavigate from '../../utils/HandleNavigate/HandleNavigate'
/**
* Komponens rövid leírása
* @returns {JSX.Element}
*/
const MyComponent = () => {
// 1. Hooks (HandleNavigate, useState, useEffect, stb.)
const { goHome } = HandleNavigate()
const [data, setData] = useState(null)
// 2. Effect hooks
useEffect(() => {
// Component mount logic
}, [])
// 3. Event handlers
const handleClick = () => {
// Logic
}
// 4. Render
return (
<div>
{/* JSX */}
</div>
)
}
export default MyComponent
Import Sorrend
// 1. React és third-party library-k
import React, { useState } from 'react'
import { motion } from 'framer-motion'
// 2. React Router hooks (useLocation, useParams - NEM useNavigate!)
import { useLocation } from 'react-router-dom'
// 3. Custom hooks és utils
import HandleNavigate from '../../utils/HandleNavigate/HandleNavigate'
import useRequireAuth from '../../hooks/useRequireAuth'
// 4. API
import { getUserData } from '../../api/userApi'
// 5. Komponensek
import Button from '../../components/Buttons/Button'
import Navbar from '../../components/Navbar/Navbar'
// 6. Assets
import Background from '../../assets/backgrounds/Background'
State Management
Local State
// Egyszerű state
const [count, setCount] = useState(0)
// Object state
const [user, setUser] = useState({
name: '',
email: ''
})
// Array state
const [items, setItems] = useState([])
LocalStorage Használat
useRequireAuth hook használata auth kezeléshez:
import useRequireAuth from '../../hooks/useRequireAuth'
const MyComponent = () => {
const [username] = useRequireAuth({
key: 'username',
redirectTo: '/login'
})
// username automatikusan szinkronizálva van localStorage-el
// Ha nincs username, automatikus redirect /login-re
}
Manuális localStorage:
// Írás
localStorage.setItem('gameToken', token)
// Olvasás
const token = localStorage.getItem('gameToken')
// Törlés
localStorage.removeItem('gameToken')
API Hívások
API File Struktúra
Minden API endpoint egy külön file-ban (userApi.js, deckApi.js, gameApi.js):
// src/api/userApi.js
import axiosInstance from './axiosInstance'
export const getUserData = async (userId) => {
try {
const response = await axiosInstance.get(`/users/${userId}`)
return response.data
} catch (error) {
console.error('Error fetching user data:', error)
throw error
}
}
export const updateUser = async (userId, userData) => {
try {
const response = await axiosInstance.put(`/users/${userId}`, userData)
return response.data
} catch (error) {
console.error('Error updating user:', error)
throw error
}
}
API Hívás Komponensben
import { getUserData } from '../../api/userApi'
const MyComponent = () => {
const [loading, setLoading] = useState(false)
const [error, setError] = useState(null)
const [data, setData] = useState(null)
const fetchData = async () => {
setLoading(true)
setError(null)
try {
const result = await getUserData(userId)
setData(result)
} catch (err) {
setError(err.message || 'Hiba történt')
} finally {
setLoading(false)
}
}
useEffect(() => {
fetchData()
}, [userId])
if (loading) return <div>Betöltés...</div>
if (error) return <div>Hiba: {error}</div>
return <div>{/* data megjelenítése */}</div>
}
Hibakezelés
Try-Catch Blokkok
const handleSubmit = async () => {
try {
const response = await createDeck(deckData)
// Siker kezelése
notifySuccess('Deck sikeresen létrehozva!')
goDecks()
} catch (error) {
// Hiba kezelése
const errorMessage = error.response?.data?.message || 'Ismeretlen hiba'
setError(errorMessage)
notifyError(errorMessage)
}
}
Toast Notifications
import { notifySuccess, notifyError } from '../../components/Toastify/toastifyServices'
// Siker üzenet
notifySuccess('✅ Művelet sikeres!')
// Hiba üzenet
notifyError('❌ Hiba történt!')
// Egyedi konfiguráció
notifySuccess('Mentve!', { autoClose: 2000 })
Elnevezési Konvenciók
JavaScript/React
| Típus | Konvenció | Példa |
|---|---|---|
| Komponensek | PascalCase | LoginForm, DeckCreator |
| Függvények | camelCase | handleClick, fetchUserData |
| Változók | camelCase | userName, isLoading |
| Konstansok | UPPER_SNAKE_CASE | API_BASE_URL, MAX_PLAYERS |
| Private változók | _camelCase | _internalState |
| Event handlers | handle + PascalCase | handleSubmit, handleInputChange |
| Boolean változók | is/has/can prefix | isLoading, hasError, canEdit |
CSS Classes (Tailwind)
// Használj explicit class neveket
<div className="flex items-center justify-between p-4 bg-white rounded-lg shadow-md">
// Kerüld a túl hosszú class stringeket - bontsd több sorra
<div
className="
flex items-center justify-between
p-4 bg-white rounded-lg shadow-md
hover:shadow-lg transition-shadow duration-200
"
>
Fájl Nevek
- Egyedi komponens:
LoginForm.jsx(nemlogin-form.jsx) - Index fájlok:
index.jsx(ha könyvtárban több file van) - Utility fájlok:
randomUtils.js(camelCase) - API fájlok:
userApi.js(camelCase + Api postfix)
Teljes Példa - Best Practices
// src/pages/Example/ExamplePage.jsx
import React, { useState, useEffect } from 'react'
import { useLocation } from 'react-router-dom'
import { motion } from 'framer-motion'
import HandleNavigate from '../../utils/HandleNavigate/HandleNavigate'
import useRequireAuth from '../../hooks/useRequireAuth'
import { fetchExampleData, updateExampleData } from '../../api/exampleApi'
import { notifySuccess, notifyError } from '../../components/Toastify/toastifyServices'
import Navbar from '../../components/Navbar/Navbar'
import Button from '../../components/Buttons/Button'
import Background from '../../assets/backgrounds/Background'
/**
* Example Page - Komponens rövid leírása
* @returns {JSX.Element}
*/
const ExamplePage = () => {
// 1. Auth & Navigation
const [username] = useRequireAuth({ key: 'username', redirectTo: '/login' })
const { goHome, goBack } = HandleNavigate()
const location = useLocation()
// 2. State
const [data, setData] = useState(null)
const [loading, setLoading] = useState(false)
const [error, setError] = useState(null)
// 3. Effects
useEffect(() => {
loadData()
}, [])
// 4. Functions
const loadData = async () => {
setLoading(true)
setError(null)
try {
const result = await fetchExampleData()
setData(result)
} catch (err) {
const errorMsg = err.response?.data?.message || 'Hiba történt'
setError(errorMsg)
notifyError(errorMsg)
} finally {
setLoading(false)
}
}
const handleSave = async () => {
try {
await updateExampleData(data)
notifySuccess('✅ Sikeresen mentve!')
goHome()
} catch (err) {
notifyError('❌ Mentés sikertelen')
}
}
const handleCancel = () => {
goBack()
}
// 5. Conditional Rendering
if (loading) {
return (
<div className="flex items-center justify-center min-h-screen">
<div>Betöltés...</div>
</div>
)
}
if (error) {
return (
<div className="flex items-center justify-center min-h-screen">
<div className="text-red-500">Hiba: {error}</div>
</div>
)
}
// 6. Main Render
return (
<div className="min-h-screen bg-gray-100">
<Background />
<Navbar />
<main className="container mx-auto px-4 py-8">
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
>
<h1 className="text-3xl font-bold mb-6">Example Page</h1>
{/* Content */}
<div className="bg-white rounded-lg shadow-md p-6">
{data && (
<div>
{/* Render data */}
</div>
)}
</div>
{/* Actions */}
<div className="flex gap-4 mt-6">
<Button onClick={handleSave} text="Mentés" />
<Button onClick={handleCancel} text="Mégse" variant="secondary" />
</div>
</motion.div>
</main>
</div>
)
}
export default ExamplePage
Összefoglalás - Legfontosabb Szabályok
- ✅ MINDIG használd HandleNavigate-et navigációhoz
- ✅ Használd a ROUTES konstansokat az App.jsx-ben
- ✅ API hívások külön file-okban (userApi.js, deckApi.js, stb.)
- ✅ Try-catch minden async műveletnél
- ✅ Toast notifications a felhasználói visszajelzéshez
- ✅ useRequireAuth hook auth védett oldalaknál
- ✅ Konzisztens import sorrend
- ✅ PascalCase komponenseknek, camelCase változóknak
- ❌ SOHA ne használj useNavigate közvetlen
- ❌ Ne használj string literal route-okat
Verzió: 1.0
Utolsó frissítés: 2025-01-17
Készítette: SerpentRace Development Team