You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							210 lines
						
					
					
						
							7.5 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							210 lines
						
					
					
						
							7.5 KiB
						
					
					
				| import React from "react"; | |
| import { View, ScrollView, StyleSheet, Text, Dimensions, ImageBackground, BackHandler } from "react-native"; | |
| import { Picker } from '@react-native-picker/picker'; | |
| import SafeAreaView from 'react-native-safe-area-view'; | |
| import AsyncStorage from '@react-native-async-storage/async-storage'; | |
| 
 | |
| import { Button, ButtonContainer } from "../components/Button"; | |
| import { Banner } from "../components/Banner"; | |
| import { texts, colors } from "../components/Variables"; | |
| 
 | |
| const bgImage = require("../assets/bg.jpg"); | |
| const screen = Dimensions.get("window"); | |
| 
 | |
| const styles = StyleSheet.create({ | |
|   container: { flex: 1 }, | |
|   text: { color: colors.white, fontSize: 20, textAlign: "center", fontWeight: "600", paddingTop: 5, paddingBottom: 20 }, | |
|   textCode: { color: colors.white, fontSize: 12, textAlign: "center", fontWeight: "500", paddingTop: 20, paddingBottom: 0 }, | |
|   safearea: { flex: 1, paddingHorizontal: 20, paddingTop: 20, justifyContent: "space-between" }, | |
|   box: { width: screen.width, paddingVertical: 10, overflow: "hidden" }, | |
|   scrollView: { height: screen.height - 20 }, | |
|   bg: { width: "100%", height: "100%" }, | |
|   dropdownContainer: { marginTop: 20, borderRadius: 5, width: "100%", textAlign: "center", backgroundColor: colors.white_alpha2 }, | |
|   dropdown: { color: colors.black, fontSize: 16, width: "100%", textAlign: "center", fontWeight: "600", backgroundColor: "transparent" }, | |
|   dropdownItem: { color: colors.white, backgroundColor: "red", fontSize: 16, borderRadius: 10, textAlign: "center", fontWeight: "600" }, | |
|   bannerContainer: { flex: 1, alignItems: "center", justifyContent: "center" } | |
| }); | |
| 
 | |
| class Quiz extends React.Component { | |
|   constructor(props) { | |
|     super(props); | |
| 
 | |
|     // Access route params safely | |
|     const { questions = [], randomQuestions = false, isWrong = false } = props.route.params || {}; | |
| 
 | |
|     this.state = { | |
|       correctCount: 0, | |
|       wrongCount: 0, | |
|       wrongAnswers: [], | |
|       pointsCount: 0, | |
|       totalPoints: 0, | |
|       totalCount: questions.length, | |
|       availableIds: questions.map(q => q.id), | |
|       availableQuestions: questions, | |
|       activeQuestionId: randomQuestions | |
|         ? questions[Math.floor(Math.random() * questions.length)]?.id | |
|         : questions[0]?.id, | |
|       minIndex: 0, | |
|       answered: false, | |
|       answerCorrect: false, | |
|       results: false, | |
|       setupData: {}, | |
|       isWrongParam: isWrong, | |
|       randomQuestionsParam: randomQuestions, | |
|       clickedId: null | |
|     }; | |
|   } | |
| 
 | |
|   bannerError = (e) => { | |
|     //console.log("Banner error (footer): ", e) | |
|   } | |
| 
 | |
|   componentDidMount() { | |
|     // BackHandler subscription | |
|     this.backHandler =  BackHandler.addEventListener( 'hardwareBackPress', this.handleBackButton) | |
| 
 | |
|     AsyncStorage.getItem('setupData').then((value) => { | |
|       this.setState({ setupData: JSON.parse(value) || {} }); | |
|     }); | |
|   } | |
| 
 | |
|   componentWillUnmount() { | |
|     this.backHandler?.remove(); | |
|   } | |
| 
 | |
|   handleBackButton = () => { | |
|     this.props.navigation.navigate("Splash"); | |
|     return true; | |
|   } | |
| 
 | |
|   answer = (correct, id, question) => { | |
|     this.setState( | |
|       state => { | |
|         const nextState = { answered: true, clickedId: id, totalPoints: state.totalPoints + parseInt(question.points) }; | |
| 
 | |
|         if (correct) { | |
|           nextState.correctCount = state.correctCount + 1; | |
|           nextState.pointsCount = state.pointsCount + parseInt(question.points); | |
|           nextState.answerCorrect = true; | |
|         } else { | |
|           nextState.wrongCount = state.wrongCount + 1; | |
|           nextState.answerCorrect = false; | |
|           nextState.wrongAnswers = [...state.wrongAnswers, { | |
|             question: question.question, | |
|             id: question.id, | |
|             clicked: id, | |
|             answers: question.answers | |
|           }]; | |
|         } | |
| 
 | |
|         return nextState; | |
|       }, | |
|       () => setTimeout(() => this.nextQuestion(), correct ? 750 : 3000) | |
|     ); | |
|   } | |
| 
 | |
|   nextQuestion = () => { | |
|     const { availableIds, availableQuestions, activeQuestionId, minIndex } = this.state; | |
| 
 | |
|     const updatedIndexes = availableIds.filter(item => item !== activeQuestionId); | |
|     const updatedQuestions = availableQuestions.filter(item => updatedIndexes.includes(item.id)); | |
| 
 | |
|     const nextId = this.state.randomQuestionsParam | |
|       ? updatedIndexes[Math.floor(Math.random() * updatedIndexes.length)] | |
|       : updatedIndexes[minIndex]; | |
| 
 | |
|     const resultsShow = !updatedIndexes.length || (this.state.correctCount + this.state.wrongCount) === this.state.totalCount; | |
| 
 | |
|     if (!updatedIndexes.length) { | |
|       this.props.navigation.navigate("Results", { | |
|         results: { | |
|           isExam: false, | |
|           isWrong: this.state.isWrongParam, | |
|           total: this.state.totalCount, | |
|           correct: this.state.correctCount, | |
|           wrong: this.state.wrongCount, | |
|           points: this.state.pointsCount, | |
|           totalPoints: this.state.totalPoints, | |
|           wrongAnswers: this.state.wrongAnswers | |
|         } | |
|       }); | |
|     } else { | |
|       this.setState({ | |
|         availableIds: updatedIndexes, | |
|         availableQuestions: updatedQuestions, | |
|         minIndex: minIndex >= updatedIndexes.length - 1 ? 0 : minIndex, | |
|         activeQuestionId: nextId, | |
|         answered: false, | |
|         results: resultsShow, | |
|         clickedId: null | |
|       }); | |
|     } | |
|   } | |
| 
 | |
|   jumpTo = (questionId, itemIndex) => { | |
|     if (itemIndex) { | |
|       this.setState({ | |
|         activeQuestionId: questionId, | |
|         minIndex: itemIndex - 1 | |
|       }); | |
|     } | |
|   } | |
| 
 | |
|   render() { | |
|     const { availableQuestions, activeQuestionId, results, correctCount, wrongCount, totalCount, clickedId } = this.state; | |
| 
 | |
|     const question = availableQuestions.find(item => item.id === activeQuestionId) || availableQuestions[0]; | |
| 
 | |
|     return ( | |
|       <ImageBackground source={bgImage} style={styles.bg} resizeMode="cover"> | |
|         <View style={styles.box}> | |
|           <View style={styles.scrollView}> | |
|             <ScrollView style={styles.container}> | |
|               {!results ? ( | |
|                 <SafeAreaView style={styles.safearea}> | |
|                   <Text style={styles.textCode}>{question?.id}</Text> | |
|                   <Text style={styles.text}>{question?.question}</Text> | |
| 
 | |
|                   <ButtonContainer> | |
|                     {question?.answers.map(answer => ( | |
|                       <Button | |
|                         key={answer.id} | |
|                         text={answer.text} | |
|                         noBorder | |
|                         colorize={{ id: answer.id, clicked: clickedId, answered: this.state.answered, isCorrect: answer.correct }} | |
|                         onPress={() => this.answer(answer.correct, answer.id, question)} | |
|                       /> | |
|                     ))} | |
|                   </ButtonContainer> | |
| 
 | |
|                   <Text style={styles.text}>{`${correctCount + wrongCount}/${totalCount}`}</Text> | |
| 
 | |
|                   <View style={styles.dropdownContainer}> | |
|                     <Picker | |
|                       style={styles.dropdown} | |
|                       itemStyle={styles.dropdownItem} | |
|                       onValueChange={(itemValue, itemIndex) => this.jumpTo(itemValue, itemIndex)} | |
|                     > | |
|                       <Picker.Item key="itemPlaceholder" label={texts.changeQuestion} value={0} /> | |
|                       {availableQuestions.map((item, index) => ( | |
|                         <Picker.Item key={`item${item.id}`} label={`${item.id} - ${item.question}`} value={item.id} /> | |
|                       ))} | |
|                     </Picker> | |
|                   </View> | |
|                 </SafeAreaView> | |
|               ) : ( | |
|                 <SafeAreaView></SafeAreaView> | |
|               )} | |
| 
 | |
|               <View style={styles.bannerContainer}> | |
|                 <Banner /> | |
|               </View> | |
|             </ScrollView> | |
|           </View> | |
|         </View> | |
|       </ImageBackground> | |
|     ); | |
|   } | |
| } | |
| 
 | |
| export default Quiz;
 |