QuizApp
Mobilna aplikacja edukacyjna do rozwiązywania testów wielokrotnego wyboru — timer na każde pytanie, ranking wyników, tryb offline z SQLite i synchronizacja z REST API. React Native 0.82, TypeScript 91%.
Aplikacja w akcji
Nauka przez
quizy i ranking
Quiz App to mobilna aplikacja edukacyjna do rozwiązywania testów wielokrotnego wyboru z zewnętrznego API tgryl.pl. Każde pytanie ma własny timer, a wyniki trafiają do globalnego rankingu.
Aplikacja działa w pełni offline dzięki lokalnemu cache SQLite — testy są synchronizowane raz dziennie i dostępne bez połączenia z internetem.
Stack technologiczny
Jak to działa
App.tsx inicjalizuje bazę danych, tworzy tabele SQLite, sprawdza onboarding w AsyncStorage i synchronizuje dane z API jeśli minął dzień od ostatniej synchronizacji.
// App.tsx
async function initApp() {
const db = await getDBConnection();
await createTables(db);
await checkOnboarding();
// Check lastFetchDate in meta table
await fetchAndSaveTestsDaily();
SplashScreen.hide();
}
Każde zapytanie o dane sprawdza najpierw lokalną bazę SQLite. Jeśli dane są — zwraca je bez wywołania API. NetInfo decyduje czy sieć jest dostępna.
// quizService.ts
async fetchTestDetails(id) {
const local = await getTestFromDb(id);
if (local) return local;
const net = await NetInfo.fetch();
if (!net.isConnected)
throw new Error('Brak sieci i danych');
const data = await fetch(API + id);
await saveTest(data);
return data;
}
Każde pytanie ma własny timer (np. 30s z API). Gdy zostaje <5 sekund — kolor czerwony. Po upływie czasu odpowiedzi blokowane, przejście dalej.
useEffect(() => {
const interval = setInterval(() => {
setTimeLeft(t => {
if (t <= 1) {
clearInterval(interval);
nextQuestion();
return 0;
}
return t - 1;
});
}, 1000);
return () => clearInterval(interval);
}, [currentQuestionIndex]);
Tabela tests przechowuje całe dane testu jako JSON,
tabela meta przechowuje datę ostatniej synchronizacji.
CREATE TABLE tests ( id TEXT PRIMARY KEY, name TEXT, description TEXT, tags TEXT, -- JSON string tasks TEXT, -- JSON string updatedAt TEXT ); CREATE TABLE meta ( key TEXT PRIMARY KEY, value TEXT -- lastFetchDate );
Wynik wysyłany na serwer przez POST po zakończeniu quizu. Tabela top 20 z API, wynik użytkownika podświetlony na żółto. Pull-to-refresh aktualizuje ranking.
// POST wynik
await fetch('http://tgryl.pl/quiz/result', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
nick: 'Ty',
score: 15,
total: 20,
type: 'Historia'
})
});
Animowany drawer z lewej strony — 5 losowych testów, przycisk "Losowy Quiz", synchronizacja i nawigacja. Obsługuje offline — wyświetla z SQLite gdy brak sieci.
// Drawer.tsx
// 5 losowych testów z lodash shuffle
const random = _.shuffle(allTests)
.slice(0, 5);
// Losowy quiz
const pick = _.sample(allTests);
navigation.navigate('Quiz', {
testId: pick.id
});
Struktura aplikacji
Tryb offline
Endpointy — tgryl.pl
// Typy danych
type ApiTestListItem = {
id: string; name: string;
description: string;
tags: string[]; level: string;
tasks: number; // liczba pytań
};
type ApiTestTask = {
id: string; question: string;
answers: ApiTaskAnswer[];
duration: number; // czas w sekundach
};
type ApiTaskAnswer = {
id: string; content: string;
isCorrect: boolean;
};
type ResultItem = {
id: string; nick: string;
score: number; total: number;
type: string; date: string;
};
Skład projektu
Jak uruchomić
git clone https://github.com/Andrii418/Quiz.git cd Quiz npm install
cd ios && pod install && cd ..
npm start # W osobnym terminalu: npm run android # Android npm run ios # iOS