cda-hackathon-quiz-app-frontend
Frontend quiz application with themed tracks (Front-end, Back-end, DevOps) and a complete player journey (selection, answers, score, history), built with React/Redux Toolkit, protected routing, and local persistence. The project uses REST API consumption and centralized state management to maintain session consistency.
🎯 Context and goals
- Build a web game interface with a guided multi-screen flow and persistent session/game state.
- Synchronize frontend interactions with backend endpoints (questions, rankings, history).
- Industrialize frontend delivery through a GitLab CI/CD pipeline based on Vite build and automated deployment.
🛠️ Deliverables
🧩 Design
- The build architecture is based on Vite and a React/Redux SPA stack, with tooling focused on global state and HTTP integration. Source: cda-hackathon-quiz-app-frontend/Hackathon-Quiz-App/package.json
{
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"@reduxjs/toolkit": "^1.7.0",
"axios": "^0.24.0",
"react": "^17.0.2",
"react-redux": "^7.2.6",
"react-router-dom": "^6.1.1",
"redux": "^4.1.2",
"redux-logger": "^3.0.6"
},
"devDependencies": {
"@vitejs/plugin-react": "^1.0.7",
"vite": "^2.7.2"
}
}
- The store centralizes
authandgameslices throughconfigureStore, separating auth/session and quiz domain logic. Source: cda-hackathon-quiz-app-frontend/Hackathon-Quiz-App/src/js/store/store.js
import { configureStore } from "@reduxjs/toolkit";
import logger from "redux-logger";
import auth from "../features/auth/authSlice";
import game from "../features/game/gameSlice"
const reducer = {
auth:auth,
game:game,
}
export const store = configureStore({
reducer,
});
💻 Development
- Backend :
The frontend consumes dedicated business endpoints (
/questions,/rankings,/history) through an Axios instance configured per environment. Source: cda-hackathon-quiz-app-frontend/Hackathon-Quiz-App/src/js/utils/api.js
import axios from 'axios'
import { API_BASE_URL } from './constants'
const instance = axios.create({
baseURL: API_BASE_URL
})
export default instance
- Frontend :
React Router v6 enforces protected access with
RequireAuthon gameplay, score, and history pages. Source: cda-hackathon-quiz-app-frontend/Hackathon-Quiz-App/src/js/App.jsx
<Routes>
<Route path="/home" element={<HomePage />} />
<Route path="/" element={<Navigate replace to="/home" />} />
<Route path="/games/nickname" element={<ChooseNickname />}></Route>
<Route
path="/games/choose-category"
element={<RequireAuth><ChooseCategoryQuestion /></RequireAuth>}
></Route>
<Route path="/games/choose-mode" element={<RequireAuth><ChooseModeQuestion /></RequireAuth>}></Route>
<Route path="/games/questions" element={<RequireAuth><ChooseResponsePage /></RequireAuth>}></Route>
<Route path="/score" element={<RequireAuth><ScorePage /></RequireAuth>}></Route>
<Route path="/history" element={<RequireAuth><HistoricPage /></RequireAuth>}></Route>
<Route path="/historyDetails" element={<RequireAuth><HistoricDetailsPage /></RequireAuth>}></Route>
</Routes>
The auth guard restores the session from localStorage and redirects to /home when no nickname is available.
Source: cda-hackathon-quiz-app-frontend/Hackathon-Quiz-App/src/js/features/auth/requireAuth.jsx
export const RequireAuth = ({ children }) => {
let location = useLocation();
const dispatch = useDispatch()
const currentPlayer = getLocalStorageItem("nickname");
useEffect(() => {
const currentPlayer = getLocalStorageItem("nickname");
if (typeof(currentPlayer) === "string") {
dispatch(login(currentPlayer));
}
}, []);
if (typeof(currentPlayer) !== "string") {
return <Navigate to="/home" state={{ from: location }} />;
}
return children;
};
The game flow implements category-based question loading and persists game state (questionsFetched, gameInfo) for downstream screens.
Source: cda-hackathon-quiz-app-frontend/Hackathon-Quiz-App/src/js/components/CategoryQuestion.jsx
async function fetchQuestions() {
let body = "";
if (category !== "" && getLocalStorageItem("currentCategory") !== category) {
body = category;
} else if (
category === "" &&
(getLocalStorageItem("currentCategory") !== null ||
getLocalStorageItem("currentCategory") !== undefined)
) {
body = getLocalStorageItem("currentCategory");
} else {
return;
}
const result = await api.get(`/questions/${body}`);
if (result.status === 200 && result.data.data !== false) {
await dispatch(categoryChosen(result.data.data[0].categoryId));
setLocalStorageItem(result.data.data,"questionsFetched")
}
}
The score page orchestrates filterable ranking retrieval (category + scoring mode) and pushes ranking state into Redux. Source: cda-hackathon-quiz-app-frontend/Hackathon-Quiz-App/src/js/views/ScorePage.jsx
async function fetchRankings(cat = 'total', avg = false) {
try {
const rankings = await api.get(`/rankings/${cat}/${avg}`);
if (rankings.status === 200) {
if (rankings.data.data) {
dispatch(updateRankings(rankings.data.data));
return rankings.data.data;
}
}
} catch (err) {
console.log(`Erreur lors de la requête : /rankings/${cat}/${avg}`);
}
}
🏗️ DevOps & Quality
- A GitLab CI pipeline runs dependency installation and Vite build, then publishes distribution artifacts. Source: cda-hackathon-quiz-app-frontend/.gitlab-ci.yml
image: node:13
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- node_modules/
stages:
- build
- deploy
build_parcel_master:
stage: build
script:
- cd ./Hackathon-Quiz-App/
- npm install
- npm run build
artifacts:
expire_in: 20 mins
paths:
- ./Hackathon-Quiz-App/dist
📈 Results
- Based on the analyzed Git history, the work spans 2021-12-13 -> 2026-02-14, with 91 commits across 8 contributors. The implementation delivers a complete quiz frontend with protected flows, Redux-based game/session state, API-driven ranking/history rendering, and persisted session behavior. The repository also includes continuous delivery logic with automated build and packaging. The technical benefit is a production-ready SPA baseline that can be executed and deployed quickly for API-driven game scenarios.
🔧 Technical environment
- Frontend: React 17, React Router 6, Redux Toolkit, React Redux, Redux Logger, Vite.
- API integration: Axios,
import.meta.env-based configuration. - State management:
authandgameslices withlocalStoragepersistence. - Product features: category/mode/question flow, score, history, ranking filters.
- DevOps: GitLab CI (build + artifacts + automated deployment).