diff --git a/frontend/iQMA-Skills-Builder/app/screens/Home.tsx b/frontend/iQMA-Skills-Builder/app/screens/Home.tsx index 7ad9c44..be7516e 100644 --- a/frontend/iQMA-Skills-Builder/app/screens/Home.tsx +++ b/frontend/iQMA-Skills-Builder/app/screens/Home.tsx @@ -1,10 +1,10 @@ // screens/HomeScreen.tsx +import * as accountEndpoints from '@/helpers/accountEndpoints'; import * as lessonEndpoints from '@/helpers/lessonEndpoints'; import * as resultEndpoints from '@/helpers/resultEndpoints'; import * as sectionEndpoints from '@/helpers/sectionEndpoints'; import * as unitEndpoints from '@/helpers/unitEndpoints'; -import * as accountEndpoints from '@/helpers/accountEndpoints'; import { NativeScrollEvent, @@ -21,6 +21,7 @@ import React, {useEffect, useRef, useState} from 'react'; import AsyncStorage from '@react-native-async-storage/async-storage'; import {AuthContext} from '@/context/AuthContext'; import {Colors} from '@/constants/Colors'; +import FeedbackComponent from '@/components/Feedback'; import {Ionicons} from '@expo/vector-icons'; import {LoadingIndicator} from '@/components/LoadingIndicator'; import {SafeAreaView} from 'react-native-safe-area-context'; @@ -29,7 +30,6 @@ import TopStats from '@/components/TopStats'; import {router} from 'expo-router'; import {useContext} from 'react'; - const HomeScreen: React.FC = () => { const {currentUser, isLoading} = useContext(AuthContext); const [circularProgress, setCircularProgress] = useState(0); @@ -172,7 +172,10 @@ const HomeScreen: React.FC = () => { // console.log("unitID", unitID) // console.log("totalLesson", totalLesson) - const getAllLessons = await lessonEndpoints.getAllLesson(sectionID, unitID); + const getAllLessons = await lessonEndpoints.getAllLesson( + sectionID, + unitID + ); if (getAllLessons.length === 0) { return; @@ -225,7 +228,8 @@ const HomeScreen: React.FC = () => { } } else { if (getAllLessons[completedLessons]) { - currentLessonId = getAllLessons[completedLessons].lessonID; + currentLessonId = + getAllLessons[completedLessons].lessonID; } currentLessonIdx = completedLessons; if (completedLessons !== 0) { @@ -233,7 +237,10 @@ const HomeScreen: React.FC = () => { currentProgress = 1 + completedLessons * 2 + - accountEndpoints.calculateKTProgress(getLessonIds, completedLessons); + accountEndpoints.calculateKTProgress( + getLessonIds, + completedLessons + ); // console.log('Current Progress:', currentProgress); } else if (completedUnits === 0) { routerName = 'SectionIntroduction'; @@ -309,8 +316,11 @@ const HomeScreen: React.FC = () => { useEffect(() => { (async () => { try { - const sectionDetails = await sectionEndpoints.getAllSectionDetails(); - let currentSection = await resultEndpoints.getCurrentSection(currentUser.sub); + const sectionDetails = + await sectionEndpoints.getAllSectionDetails(); + let currentSection = await resultEndpoints.getCurrentSection( + currentUser.sub + ); console.log('Current Section Outside:', currentSection); if (currentSection > sectionDetails.length) { @@ -359,8 +369,7 @@ const HomeScreen: React.FC = () => { })(); }, [completedFinals, sectionCircularProgress, circularProgress]); - useEffect(() => { - }, [allSectionDetails]); + useEffect(() => {}, [allSectionDetails]); const handlePress = ( pathName: string, @@ -452,6 +461,7 @@ const HomeScreen: React.FC = () => { )} + ); }; diff --git a/frontend/iQMA-Skills-Builder/components/Feedback.tsx b/frontend/iQMA-Skills-Builder/components/Feedback.tsx new file mode 100644 index 0000000..80ac24e --- /dev/null +++ b/frontend/iQMA-Skills-Builder/components/Feedback.tsx @@ -0,0 +1,223 @@ +import { + Modal, + StyleSheet, + Text, + TextInput, + TouchableOpacity, + View, +} from 'react-native'; +import React, {useState} from 'react'; + +import {Colors} from '@/constants/Colors'; +import {Picker} from '@react-native-picker/picker'; + +// Define types for the component +type FeedbackComponentProps = {}; + +const FeedbackComponent: React.FC = () => { + const [visible, setVisible] = useState(false); // To toggle form visibility + const [selectedOption, setSelectedOption] = useState(''); // Dropdown state + const [selectedRating, setSelectedRating] = useState(null); // Rating state + const [message, setMessage] = useState(''); // Message based on dropdown + + // Messages corresponding to dropdown options + const customMessages: {[key: string]: string} = { + feedback: + "We're here to listen! Are your feedback about gamification techniques or the course content?", + bug: "We're here to help! Are you reporting a bug related to the system functionality or a display issue?", + suggestion: + 'We love hearing new ideas! Is your suggestion about improving the course or adding new features?', + }; + + const onDropdownChange = (itemValue: string) => { + setSelectedOption(itemValue); + setMessage(customMessages[itemValue] || ''); // Set custom message based on dropdown selection + }; + + const ratingFaces = ['😭', '😐', '😊', '😀']; + + return ( + + {/* Floating Button */} + setVisible(true)} + > + 🗳️ + + + {/* Modal for Form */} + + + + User Feedback Form + + {/* Dropdown Field */} + + + onDropdownChange(itemValue) + } + > + + + + + + + + {/* Rating Field with Faces */} + + {/* Render the rating faces */} + {ratingFaces.map((emoji, index) => ( + setSelectedRating(index)} // Set selected rating + style={[ + styles.faceContainer, + selectedRating !== null && + selectedRating !== index + ? styles.grayscale + : {}, + ]} + > + {emoji} + {index + 1} + + ))} + + + {/* Custom Message */} + {selectedOption ? ( + {message} + ) : null} + + {/* Text Input Field */} + + + {/* Close Form Button */} + setVisible(false)} + > + Close + + + + + + ); +}; + +// Styles +const styles = StyleSheet.create({ + bubble: { + alignItems: 'center', + backgroundColor: Colors.default.purple100, + borderRadius: 30, + bottom: 20, + width: 60, + height: 60, + justifyContent: 'center', + left: 20, + position: 'absolute', + zIndex: 1000, + }, + bubbleText: { + color: Colors.chatbot.inputColor, + fontSize: 30, + }, + closeButton: { + backgroundColor: '#C3B1FF', + borderRadius: 5, + marginTop: 10, + padding: 10, + }, + closeButtonText: { + color: '#7654F2', + }, + container: { + flex: 1, + justifyContent: 'flex-end', + alignItems: 'center', + }, + customMessage: { + color: Colors.light.text, + fontSize: 16, + marginRight: 10, + paddingLeft: 20, + paddingHorizontal: 10, + paddingVertical: 5, + }, + dropdown: { + color: Colors.light.text, + height: 50, + width: 200, + }, + dropdownContainer: { + borderWidth: 1, // Border width + borderColor: Colors.default.purple500, // Custom border color + borderRadius: 5, // Rounded corners + overflow: 'hidden', // Ensures content doesn't overflow the border + marginBottom: 10, // Space below the dropdown + }, + grayscale: { + // Apply grayscale filter + opacity: 0.3, // Make the unselected emojis look like they are black and white + }, + face: { + fontSize: 30, + marginHorizontal: 10, + }, + faceContainer: { + padding: 10, // Optional padding around the emoji + }, + formContainer: { + alignItems: 'center', + backgroundColor: 'white', + borderRadius: 10, + padding: 20, + margin: 20, + }, + formTitle: { + color: Colors.default.purple500, + fontSize: 18, + marginBottom: 10, + }, + modalBackground: { + flex: 1, + justifyContent: 'center', + backgroundColor: 'rgba(0,0,0,0.5)', + }, + ratingContainer: { + flexDirection: 'row', + justifyContent: 'space-around', + marginVertical: 10, + }, + textInput: { + borderColor: 'gray', + borderWidth: 1, + borderRadius: 5, + color: Colors.light.text, + height: 100, + marginVertical: 20, + marginRight: 10, + paddingHorizontal: 10, + paddingLeft: 20, + width: 300, + }, +}); + +export default FeedbackComponent;