LambertQuiz is a React Native-based and cross-platform mobile app that offers interactive and timed quizzes on various topics.
-
Quiz on various topics: Users can choose from a wide range of topics for the quiz, including mathematics, science, history, geographics, and more.
-
Game Modes: Timed gameplay with final scoring.
-
Results Display: Shows the final score and correct / incorrect answers.
-
Dynamic sounds: Quizzes with beatiful sounds!
-
Security: The user's sensitive data, such as their password, are encrypted and stored in a very robust database.
-
Language: There is only the English language.
-
Node.js
-
React Native
-
NPM or Yarn
- Clone the repository:
git clone https://github.com/MattDEV02/LambertQuiz.git
- Navigate to the project directory:
cd LambertQuiz
- Install dependencies:
npm install
# or using yarn
# yarn install
- Start the application:
npm start
# or using yarn
# yarn start
P.S. = You can do both third and fourth step with "my comand script":
npm run all
import React, { useState, useEffect } from "react";
import "react-native-gesture-handler";
import { NavigationContainer } from "@react-navigation/native";
import { RootSiblingParent } from "react-native-root-siblings";
import AuthStackNavigator from "./navigators/AuthStackNavigator";
import AppStackNavigator from "./navigators/AppStackNavigator";
import { supabase } from "./app/lib/supabase-client";
import { validateObject } from "./utils/validators";
const App = () => {
const [session, setSession] = useState(null);
useEffect(() => {
supabase.auth
.getSession()
.then(({ data: { session } }) => {
setSession(session);
})
.catch((error) => console.error(error));
supabase.auth.onAuthStateChange(async (_event, session) => {
console.log(_event); // INITIAL_SESSION / SIGNED_IN / SIGNED_OUT
setSession(session);
});
}, []);
return (
<RootSiblingParent>
<NavigationContainer>
{validateObject(session) && validateObject(session.user) ? (
<AppStackNavigator sessionUser={session.user} />
) : (
<AuthStackNavigator />
)}
</NavigationContainer>
</RootSiblingParent>
);
};
export default App;
import React, { useState, useEffect } from "react";
import {
View,
Text,
SafeAreaView,
FlatList,
ScrollView,
StyleSheet,
} from "react-native";
import { supabase } from "../app/lib/supabase-client";
import Quiz from "../components/screens/HomeScreen/Quiz";
import FormInput from "../components/shared/FormInput";
import { COLORS } from "../constants/theme";
import {
validateObject,
validateString,
validateArray,
} from "../utils/validators";
import { playClickSound } from "../utils/sounds";
const HomeScreen = ({ navigation, route }) => {
const user = route.params.user;
const [quizzes, setQuizzes] = useState([]);
const [quiz, setQuiz] = useState("");
const [searching, setSearching] = useState(false);
const [refreshing, setRefreshing] = useState(false);
useEffect(() => {
const getQuizzes = async () => {
setRefreshing(true);
const { data, error } = await supabase
.from("quizzes")
.select()
.order("category");
if (validateObject(error)) {
console.error(error);
setRefreshing(false);
} else if (validateArray(data, 1)) {
setQuizzes(data);
}
setRefreshing(false);
};
const getQuizzesWithSearching = async () => {
setRefreshing(true);
const { data, error } = await supabase.rpc("get_searched_quizzes", {
quiz_category: quiz,
});
if (validateObject(error)) {
console.error(error);
setRefreshing(false);
} else if (validateArray(data, 0)) {
setQuizzes(data);
} else if (!validateString(quiz)) {
setSearching(false);
getQuizzes();
}
setRefreshing(false);
};
searching ? getQuizzesWithSearching() : getQuizzes();
}, [quiz]);
const handleOnPlayPress = async (quiz_id) => {
await playClickSound();
navigation.setParams({ quizId: quiz_id });
navigation.navigate("Play Quiz page", {
quizId: quiz_id,
openedQuiz: true,
});
};
return (
<SafeAreaView
style={{
flex: 1,
backgroundColor: COLORS.background,
position: "relative",
}}
>
{/* TOP BAR */}
<ScrollView
style={{
marginBottom: 6.75,
}}
>
<View>
{/* Welcome title */}
<View
style={{
...styles.container,
marginTop: 27.5,
}}
>
<Text style={{ ...styles.text, fontSize: 29 }}>
Welcome{" "}
{validateObject(user) && validateString(user.username)
? user.username
: null}{" "}
!
</Text>
</View>
{/* Quiz search form */}
<View style={styles.container}>
<FormInput
placeholderText={"Search for a Quiz"}
value={quiz}
maxLength={15}
autoComplete={"name"}
autoCorrect={true}
inputMode={"text"}
keyboardType={"default"}
inputError={false}
inputSuccess={false}
onChangeText={(quiz) => {
setQuiz(quiz);
setSearching(true);
}}
style={{ width: "89.5%" }}
inputStyle={{
marginTop: 7.5,
marginBottom: 5,
paddingVertical: 15,
backgroundColor: COLORS.white,
borderWidth: 0.35,
borderColor: COLORS.secondary,
borderRadius: 12,
fontSize: 16,
}}
/>
</View>
{/* Quiz list */}
<View style={{ marginBottom: 20 }}>
{validateArray(quizzes, 1) ? (
<FlatList
data={quizzes}
scrollEnabled={false}
onRefresh={() => undefined}
refreshing={refreshing}
showsVerticalScrollIndicator={false}
keyExtractor={(item) => item.quiz_id}
renderItem={({ item: quiz }) => (
<Quiz
quiz={quiz}
handleOnPlayPress={() =>
handleOnPlayPress(quiz.quiz_id)
}
/>
)}
/>
) : searching ? (
<View style={{ ...styles.container, marginTop: 47 }}>
<Text style={{ ...styles.text, color: "#EF0909" }}>
NO Quizzes found.
</Text>
</View>
) : null}
</View>
</View>
</ScrollView>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
},
text: {
fontSize: 26.5,
color: COLORS.black,
fontWeight: "bold",
},
});
export default HomeScreen;
import React from "react";
import { SafeAreaView, ScrollView } from "react-native";
import AccordionItem from "../components/screens/HelpScreen/AccordionItem";
import HelpFooter from "../components/screens/HelpScreen/HelpFooter";
import { appName, questionsNumber } from "../constants/theme";
import { passwordMaxLength } from "../constants/fieldsConstants";
const HelpScreen = () => {
const accordionList = [
{
question: "",
response: "",
},
];
return (
<SafeAreaView>
<ScrollView>
{accordionList.map((item, index) => (
<AccordionItem
question={item.question}
response={item.response}
key={index}
/>
))}
<HelpFooter />
</ScrollView>
</SafeAreaView>
);
};
export default HelpScreen;
Made with β€οΈ and a lot of hard work ποΈββοΈ by:
-
Matteo Lambertucci (matricola 578219, Roma TRE)
I am the only author of this beatiful app π
Name | Version |
---|---|
Javascript | ES6 |
React native | 0.72.6 |
NodeJS | 20.4.0 |
NPM | 9.7.2 |
PostgreSQL | 16.0 |
Visual Studio Code | 1.85 |
Altervista | // |
Bootstrap | 5 |
HTML | 5 |
CSS | 4.15 |
Markdown | // |
Windows | 11 |
-
src/
: The main folder for the application source code.-
src/components/
: Contains all reusable components of the application. -
src/screens/
: Primary screens of the application, each associated with specific functionalities. -
src/navigators/
: Configuration and management of application navigation, using React Navigation or a similar library. -
src/utils/
: Utility functions, or helpers used across multiple parts of the code. -
src/constants/
: Utility constants, or helpers used across multiple parts of the code. -
src/App.js
: The main component of this project, it gets rendered in the index.js file (see below).
-
-
assets/
: Images, fonts, or other multimedia assets used in the application. -
index.js
: The main entry of this project. -
lambertquiz.sql
: A SQL (PostGreSQL) script file that allows to create the database that I used for this App. -
package.json
: JSON metadata file that to define various properties and configurations related to the project, including its dependencies, scripts, version information, and other metadata. -
README.md
: Markdown documentation of this project.
This project is licensed under the MIT License - see the LICENSE file for more details.