Skip to content

Commit a985a39

Browse files
authored
Add files via upload
1 parent 0517f3b commit a985a39

6 files changed

Lines changed: 205 additions & 0 deletions

File tree

App.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
import React from 'react';
3+
import { NavigationContainer } from '@react-navigation/native';
4+
import { createStackNavigator } from '@react-navigation/stack';
5+
import QuizScreen from './QuizScreen';
6+
import ResultsScreen from './ResultsScreen';
7+
8+
const Stack = createStackNavigator();
9+
10+
function App() {
11+
return (
12+
<NavigationContainer>
13+
<Stack.Navigator initialRouteName="Quiz">
14+
<Stack.Screen name="Quiz" component={QuizScreen} />
15+
<Stack.Screen name="Results" component={ResultsScreen} />
16+
</Stack.Navigator>
17+
</NavigationContainer>
18+
);
19+
}
20+
21+
export default App;
22+

QuizScreen.js

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
2+
import React, { useState, useEffect } from 'react';
3+
import { View, Text, Button, StyleSheet } from 'react-native';
4+
import { useDispatch, useSelector } from 'react-redux';
5+
import { setQuestion, setScore, nextQuestion } from './redux/actions';
6+
import { questions } from './data/questions.json';
7+
8+
const QuizScreen = ({ navigation }) => {
9+
const dispatch = useDispatch();
10+
const currentQuestionIndex = useSelector((state) => state.currentQuestionIndex);
11+
const score = useSelector((state) => state.score);
12+
13+
const [timer, setTimer] = useState(30);
14+
15+
useEffect(() => {
16+
dispatch(setQuestion(questions[0]));
17+
}, []);
18+
19+
useEffect(() => {
20+
if (timer > 0) {
21+
const interval = setInterval(() => setTimer((prev) => prev - 1), 1000);
22+
return () => clearInterval(interval);
23+
}
24+
}, [timer]);
25+
26+
const handleAnswer = (selectedAnswer) => {
27+
const correctAnswer = questions[currentQuestionIndex].answer;
28+
if (selectedAnswer === correctAnswer) {
29+
dispatch(setScore(score + 1));
30+
}
31+
dispatch(nextQuestion());
32+
};
33+
34+
const currentQuestion = questions[currentQuestionIndex];
35+
36+
return (
37+
<View style={styles.container}>
38+
<Text style={styles.question}>{currentQuestion.question}</Text>
39+
{currentQuestion.options.map((option, idx) => (
40+
<Button key={idx} title={option} onPress={() => handleAnswer(option)} />
41+
))}
42+
<Text>Time Remaining: {timer}s</Text>
43+
</View>
44+
);
45+
};
46+
47+
const styles = StyleSheet.create({
48+
container: {
49+
flex: 1,
50+
justifyContent: 'center',
51+
alignItems: 'center',
52+
padding: 20,
53+
},
54+
question: {
55+
fontSize: 20,
56+
marginBottom: 20,
57+
},
58+
});
59+
60+
export default QuizScreen;
61+

ResultsScreen.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
2+
import React from 'react';
3+
import { View, Text, Button, StyleSheet } from 'react-native';
4+
import { useDispatch, useSelector } from 'react-redux';
5+
import { resetGame } from './redux/actions';
6+
7+
const ResultsScreen = ({ navigation }) => {
8+
const score = useSelector((state) => state.score);
9+
10+
const dispatch = useDispatch();
11+
12+
const handleRestart = () => {
13+
dispatch(resetGame());
14+
navigation.navigate('Quiz');
15+
};
16+
17+
return (
18+
<View style={styles.container}>
19+
<Text style={styles.result}>Your Score: {score}</Text>
20+
<Button title="Restart Quiz" onPress={handleRestart} />
21+
</View>
22+
);
23+
};
24+
25+
const styles = StyleSheet.create({
26+
container: {
27+
flex: 1,
28+
justifyContent: 'center',
29+
alignItems: 'center',
30+
padding: 20,
31+
},
32+
result: {
33+
fontSize: 24,
34+
marginBottom: 20,
35+
},
36+
});
37+
38+
export default ResultsScreen;
39+

actions.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
2+
export const setQuestion = (question) => ({
3+
type: 'SET_QUESTION',
4+
payload: question,
5+
});
6+
7+
export const setScore = (score) => ({
8+
type: 'SET_SCORE',
9+
payload: score,
10+
});
11+
12+
export const nextQuestion = () => ({
13+
type: 'NEXT_QUESTION',
14+
});
15+
16+
export const resetGame = () => ({
17+
type: 'RESET_GAME',
18+
});
19+

questions.json

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
2+
{
3+
"questions": [
4+
{
5+
"id": 1,
6+
"domain": "Perform Ultrasound Examinations",
7+
"question": "Which of the following is the primary reason to use a warm gel during an abdominal ultrasound?",
8+
"options": [
9+
"Enhance acoustic impedance mismatch",
10+
"Improve patient comfort and reduce motion",
11+
"Increase frequency penetration",
12+
"Reduce lateral resolution"
13+
],
14+
"answer": "Improve patient comfort and reduce motion",
15+
"explanation": "Warm gel helps relax the patient, reducing involuntary motion that could degrade image quality.",
16+
"reference": "ARDMS SPI Content Outline — Patient Care; AIUM Practice Parameter for Ultrasound Examinations",
17+
"difficulty": "easy"
18+
},
19+
{
20+
"id": 2,
21+
"domain": "Perform Ultrasound Examinations",
22+
"question": "When obtaining a longitudinal view of the liver, which anatomic landmark helps confirm proper scan orientation?",
23+
"options": [
24+
"Gallbladder",
25+
"Portal vein",
26+
"Falciform ligament",
27+
"Hepatic artery"
28+
],
29+
"answer": "Falciform ligament",
30+
"explanation": "The falciform ligament is a reliable midline landmark in longitudinal liver scans.",
31+
"reference": "AIUM Abdominal Ultrasound Guidelines",
32+
"difficulty": "easy"
33+
}
34+
]
35+
}
36+

reducer.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
2+
const initialState = {
3+
score: 0,
4+
currentQuestionIndex: 0,
5+
};
6+
7+
const quizReducer = (state = initialState, action) => {
8+
switch (action.type) {
9+
case 'SET_QUESTION':
10+
return { ...state, currentQuestion: action.payload };
11+
case 'SET_SCORE':
12+
return { ...state, score: action.payload };
13+
case 'NEXT_QUESTION':
14+
const nextIndex = state.currentQuestionIndex + 1;
15+
return {
16+
...state,
17+
currentQuestionIndex: nextIndex,
18+
currentQuestion: questions[nextIndex],
19+
};
20+
case 'RESET_GAME':
21+
return initialState;
22+
default:
23+
return state;
24+
}
25+
};
26+
27+
export default quizReducer;
28+

0 commit comments

Comments
 (0)