diff --git a/FindMyClass/app/api/googleCalendar.js b/FindMyClass/app/api/googleCalendar.js index 2bddec6c..6e400499 100644 --- a/FindMyClass/app/api/googleCalendar.js +++ b/FindMyClass/app/api/googleCalendar.js @@ -2,7 +2,8 @@ import { getAuth } from "firebase/auth"; import AsyncStorage from '@react-native-async-storage/async-storage'; import { googleCalendarConfig } from '../secrets'; -//This file is only called from Chatbot, since the schedule is using a refined version, this is hardcoded into schedule.js +// This file is only called from Chatbot, since the schedule is using a refined version, +// this is hardcoded into schedule.js const fetchGoogleCalendarEvents = async () => { try { @@ -35,12 +36,11 @@ const fetchGoogleCalendarEvents = async () => { console.error("Google API Error:", data.error); return []; } - - return data.items || []; // ✅ Return events list + return data.items || []; // Return events list } catch (error) { - - return []; + console.error("Error fetching Google Calendar events:", error); + throw error; // Rethrow the error after logging it } }; diff --git a/FindMyClass/app/index.jsx b/FindMyClass/app/index.jsx index f04bd395..e13b3349 100644 --- a/FindMyClass/app/index.jsx +++ b/FindMyClass/app/index.jsx @@ -3,6 +3,7 @@ import { View, StyleSheet } from 'react-native'; import { useRoute } from '@react-navigation/native'; import ToggleCampusMap from '../components/ToggleCampusMap'; import 'react-native-get-random-values' +import FloatingChatButton from '../components/FloatingChatButton'; // Ensure this path is correct export default function MapScreen() { // Renamed to avoid conflict @@ -15,7 +16,7 @@ export default function MapScreen() { // Renamed to avoid conflict return ( - {/* */} + { } ); } diff --git a/FindMyClass/app/screens/directions.jsx b/FindMyClass/app/screens/directions.jsx index ce38ebc9..17514259 100644 --- a/FindMyClass/app/screens/directions.jsx +++ b/FindMyClass/app/screens/directions.jsx @@ -7,6 +7,7 @@ import polyline from "@mapbox/polyline"; import { googleAPIKey } from "../../app/secrets"; import LocationSelector from "../../components/directions/LocationSelector"; import ModalSearchBars from "../../components/directions/ModalSearchBars"; +import { isBuildingFocused } from "../../components/locationUtils"; import SwipeUpModal from "../../components/directions/SwipeUpModal"; import { isNearCampus, @@ -630,80 +631,34 @@ export default function DirectionsScreen() { - const onRegionChange = (region) => { - // Calculate zoom level based on latitudeDelta - const calculatedZoom = calculateZoomLevel(region); - setZoomLevel( calculatedZoom ); - const minimumZoom = 17; - // Check if we're zoomed in on the Hall Building - if (hallBuilding ) { - const hallLatLng = { - latitude: hallBuilding.latitude, - longitude: hallBuilding.longitude, - }; - - // Calculate distance between map center and Hall Building - const distance = Math.sqrt( - Math.pow(region.latitude - hallLatLng.latitude, 2) + - Math.pow(region.longitude - hallLatLng.longitude, 2) - ); - - // Determine if we're focused on Hall Building (centered and zoomed in) - const isHallFocused = distance < 0.0005 && calculatedZoom > minimumZoom; - setHallBuildingFocused(isHallFocused); - } - if (jmsbBuilding) { - const jmsbLatLng = { - latitude: jmsbBuilding.latitude, - longitude: jmsbBuilding.longitude, - }; - - // Calculate distance between map center and Hall Building - const distance = Math.sqrt( - Math.pow(region.latitude - jmsbLatLng.latitude, 2) + - Math.pow(region.longitude - jmsbLatLng.longitude, 2) - ); - - // Determine if we're focused on Hall Building (centered and zoomed in) - const isJMSBFocused = distance < 0.0006 && calculatedZoom > minimumZoom; - setJMSBBuildingFocused(isJMSBFocused); - } - - if (vanierBuilding) { - const vanierLatLng = { - latitude: vanierBuilding.latitude, - longitude: vanierBuilding.longitude, - }; - - // Calculate distance between map center and Hall Building - const distance = Math.sqrt( - Math.pow(region.latitude - vanierLatLng.latitude, 2) + - Math.pow(region.longitude - vanierLatLng.longitude, 2) - ); - - // Determine if we're focused on Hall Building (centered and zoomed in) - const isVanierFocused = distance < 0.001 && calculatedZoom > minimumZoom; - setVanierBuildingFocused(isVanierFocused); - } - - if (ccBuilding) { - const ccLatLng = { - latitude: ccBuilding.latitude, - longitude: ccBuilding.longitude, - }; - - // Calculate distance between map center and Hall Building - const distance = Math.sqrt( - Math.pow(region.latitude - ccLatLng.latitude, 2) + - Math.pow(region.longitude - ccLatLng.longitude, 2) - ); - - // Determine if we're focused on Hall Building (centered and zoomed in) - const isCCFocused = distance < 0.0005 && calculatedZoom > minimumZoom; - setCCBuildingFocused(isCCFocused); - } - - }; + const onRegionChange = (region) => { + // Calculate zoom level based on latitudeDelta + const calculatedZoom = calculateZoomLevel(region); + setZoomLevel(calculatedZoom); + const minimumZoom = 17; + + // Set focus for each building using the helper + if (hallBuilding) { + setHallBuildingFocused( + isBuildingFocused(region, hallBuilding, calculatedZoom, 0.0005, minimumZoom) + ); + } + if (jmsbBuilding) { + setJMSBBuildingFocused( + isBuildingFocused(region, jmsbBuilding, calculatedZoom, 0.0006, minimumZoom) + ); + } + if (vanierBuilding) { + setVanierBuildingFocused( + isBuildingFocused(region, vanierBuilding, calculatedZoom, 0.001, minimumZoom) + ); + } + if (ccBuilding) { + setCCBuildingFocused( + isBuildingFocused(region, ccBuilding, calculatedZoom, 0.0005, minimumZoom) + ); + } + }; const handleMarkerPress = (coordinate) => { mapRef.current?.animateToRegion({ diff --git a/FindMyClass/app/screens/profile.jsx b/FindMyClass/app/screens/profile.jsx index 5a8b1f2a..ea96329d 100644 --- a/FindMyClass/app/screens/profile.jsx +++ b/FindMyClass/app/screens/profile.jsx @@ -6,6 +6,7 @@ import { useAuth } from '../../contexts/AuthContext'; import { useTheme } from '../../contexts/ThemeContext'; import { useLanguage } from '../../contexts/LanguageContext'; import { useRouter } from 'expo-router'; +import FloatingChatButton from '../../components/FloatingChatButton'; export default function Profile() { const { user } = useAuth(); @@ -503,7 +504,7 @@ export default function Profile() { {t.viewSchedule} - {/* */} + { } ); } diff --git a/FindMyClass/app/screens/schedule.jsx b/FindMyClass/app/screens/schedule.jsx index a53d5a5f..04142244 100644 --- a/FindMyClass/app/screens/schedule.jsx +++ b/FindMyClass/app/screens/schedule.jsx @@ -14,8 +14,6 @@ import { } from 'react-native'; import { MaterialIcons } from '@expo/vector-icons'; import AsyncStorage from '@react-native-async-storage/async-storage'; -import { getAuth } from 'firebase/auth'; -import { googleCalendarConfig } from '../secrets'; import { useAuth } from '../../contexts/AuthContext'; import { useTheme } from '../../contexts/ThemeContext'; import { useLanguage } from '../../contexts/LanguageContext'; diff --git a/FindMyClass/components/BuildingMap.js b/FindMyClass/components/BuildingMap.js index fbf71604..789bdd97 100644 --- a/FindMyClass/components/BuildingMap.js +++ b/FindMyClass/components/BuildingMap.js @@ -14,10 +14,17 @@ import {vanierBounds, vanierFlippedGrid, gridVanier } from "./rooms/VanierBuildi import {ccBounds, ccFlippedGrid, gridCC } from "./rooms/CCBuildingRooms"; import { googleAPIKey } from '../app/secrets'; import RoomMarker from './RoomMarker'; + +import { isBuildingFocused } from "./locationUtils"; + + + + import { useTheme } from '../contexts/ThemeContext'; import { useLanguage } from '../contexts/LanguageContext'; import * as Location from 'expo-location'; + // Define paths to floor plan images/SVGs const floorPlans = { 1: require('../floorPlans/Hall-1.png'), @@ -194,73 +201,12 @@ export default function BuildingMap({ const calculatedZoom = Math.log2(360 / region.latitudeDelta); setZoomLevel(calculatedZoom); - // Check if we're zoomed in on the Hall Building - if (hallBuilding ) { - const hallLatLng = { - latitude: hallBuilding.latitude, - longitude: hallBuilding.longitude, - }; - - // Calculate distance between map center and Hall Building - const distance = Math.sqrt( - Math.pow(region.latitude - hallLatLng.latitude, 2) + - Math.pow(region.longitude - hallLatLng.longitude, 2) - ); - - // Determine if we're focused on Hall Building (centered and zoomed in) - const isHallFocused = distance < 0.0005 && calculatedZoom > 18; - setHallBuildingFocused(isHallFocused); - } - if (jmsbBuilding) { - const jmsbLatLng = { - latitude: jmsbBuilding.latitude, - longitude: jmsbBuilding.longitude, - }; - - // Calculate distance between map center and Hall Building - const distance = Math.sqrt( - Math.pow(region.latitude - jmsbLatLng.latitude, 2) + - Math.pow(region.longitude - jmsbLatLng.longitude, 2) - ); - - // Determine if we're focused on Hall Building (centered and zoomed in) - const isJMSBFocused = distance < 0.0006 && calculatedZoom > 18; - setJMSBBuildingFocused(isJMSBFocused); - } - if (vanierBuilding) { - const vanierLatLng = { - latitude: vanierBuilding.latitude, - longitude: vanierBuilding.longitude, - }; - - // Calculate distance between map center and Hall Building - const distance = Math.sqrt( - Math.pow(region.latitude - vanierLatLng.latitude, 2) + - Math.pow(region.longitude - vanierLatLng.longitude, 2) - ); - - // Determine if we're focused on Hall Building (centered and zoomed in) - const isVanierFocused = distance < 0.001 && calculatedZoom > 18; - setVanierBuildingFocused(isVanierFocused); - } - - if (ccBuilding) { - const ccLatLng = { - latitude: ccBuilding.latitude, - longitude: ccBuilding.longitude, - }; - - // Calculate distance between map center and Hall Building - const distance = Math.sqrt( - Math.pow(region.latitude - ccLatLng.latitude, 2) + - Math.pow(region.longitude - ccLatLng.longitude, 2) - ); - - // Determine if we're focused on Hall Building (centered and zoomed in) - const isCCFocused = distance < 0.0005 && calculatedZoom > 18; - setCCBuildingFocused(isCCFocused); - } + // Use the helper to determine if each building is focused. + setHallBuildingFocused(isBuildingFocused(region, hallBuilding, calculatedZoom, 0.0005, 18)); + setJMSBBuildingFocused(isBuildingFocused(region, jmsbBuilding, calculatedZoom, 0.0006, 18)); + setVanierBuildingFocused(isBuildingFocused(region, vanierBuilding, calculatedZoom, 0.001, 18)); + setCCBuildingFocused(isBuildingFocused(region, ccBuilding, calculatedZoom, 0.0005, 18)); }; // Search for a building and move the map to it diff --git a/FindMyClass/components/__tests__/locationUtils.test.js b/FindMyClass/components/__tests__/locationUtils.test.js new file mode 100644 index 00000000..c5ace938 --- /dev/null +++ b/FindMyClass/components/__tests__/locationUtils.test.js @@ -0,0 +1,36 @@ +import { calculateDistance, isBuildingFocused } from '../locationUtils'; + +describe('calculateDistance', () => { + it('returns 0 when both points are the same', () => { + expect(calculateDistance(45.0, -73.0, 45.0, -73.0)).toBe(0); + }); + + it('returns a positive value when points differ', () => { + const distance = calculateDistance(45.0, -73.0, 45.1, -73.1); + expect(distance).toBeGreaterThan(0); + }); +}); + +describe('isBuildingFocused', () => { + const region = { latitude: 45.5, longitude: -73.6 }; + const building = { latitude: 45.5, longitude: -73.6 }; + const farBuilding = { latitude: 46.0, longitude: -74.0 }; + + it('returns false if building is null', () => { + expect(isBuildingFocused(region, null, 10, 0.1, 5)).toBe(false); + }); + + it('returns true if the distance is less than threshold and zoom is above minZoom', () => { + expect(isBuildingFocused(region, building, 10, 0.1, 5)).toBe(true); + }); + + it('returns false if the distance is greater than or equal to threshold', () => { + // Use a very low distanceThreshold. + expect(isBuildingFocused(region, farBuilding, 10, 0.1, 5)).toBe(false); + }); + + it('returns false if the calculatedZoom is not above minZoom', () => { + // Even if the distance is small but zoom is too low. + expect(isBuildingFocused(region, building, 4, 0.1, 5)).toBe(false); + }); +}); diff --git a/FindMyClass/components/locationUtils.js b/FindMyClass/components/locationUtils.js new file mode 100644 index 00000000..85c1d90b --- /dev/null +++ b/FindMyClass/components/locationUtils.js @@ -0,0 +1,32 @@ +// locationUtils.js + +/** + * Calculate the distance between two points (lat1, lon1) and (lat2, lon2) + */ +export const calculateDistance = (lat1, lon1, lat2, lon2) => { + return Math.sqrt( + Math.pow(lat1 - lat2, 2) + Math.pow(lon1 - lon2, 2) + ); + }; + + /** + * Determine if the map is focused on a building based on a distance threshold and minimum zoom. + * @param {object} region - The current region from the map. + * @param {object} building - The building object containing latitude and longitude. + * @param {number} calculatedZoom - The zoom level calculated from the region. + * @param {number} distanceThreshold - Maximum allowed distance to consider the building focused. + * @param {number} minZoom - The minimum zoom level required. + * @returns {boolean} True if focused, false otherwise. + */ + export const isBuildingFocused = (region, building, calculatedZoom, distanceThreshold, minZoom) => { + if (!building) return false; + + const distance = calculateDistance( + region.latitude, + region.longitude, + building.latitude, + building.longitude + ); + + return distance < distanceThreshold && calculatedZoom > minZoom; + }; \ No newline at end of file diff --git a/FindMyClass/coverage/lcov-report/components/BuildingMap.js.html b/FindMyClass/coverage/lcov-report/components/BuildingMap.js.html index a16343ea..961e9f85 100644 --- a/FindMyClass/coverage/lcov-report/components/BuildingMap.js.html +++ b/FindMyClass/coverage/lcov-report/components/BuildingMap.js.html @@ -25,14 +25,14 @@

All files / components
0% Statements - 0/220 + 0/204
0% Branches - 0/147 + 0/129
@@ -46,7 +46,7 @@

All files / components
0% Lines - 0/196 + 0/180
@@ -883,60 +883,9 @@

All files / components 818 819 820 -821 -822 -823 -824 -825 -826 -827 -828 -829 -830 -831 -832 -833 -834 -835 -836 -837 -838 -839 -840 -841 -842 -843 -844 -845 -846 -847 -848 -849 -850 -851 -852 -853 -854 -855 -856 -857 -858 -859 -860 -861 -862 -863 -864 -865 -866 -867 -868 -869 -870 -871 -872 -873 -874  +821  +  +        @@ -1041,80 +990,18 @@

All files / components       -  -  -  -  -  -  -  -  -  -  -        -  -  -  -  -  -  -  -  -  -  -            -          -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -        @@ -1571,6 +1458,13 @@

All files / components       +  +  +  +  +  +  +        @@ -1824,6 +1718,8 @@

All files / components import {vanierBounds, vanierFlippedGrid, gridVanier } from "./rooms/VanierBuildingRooms"; import {ccBounds, ccFlippedGrid, gridCC } from "./rooms/CCBuildingRooms"; import { googleAPIKey } from '../app/secrets'; +import RoomMarker from './RoomMarker'; +import { isBuildingFocused } from "./locationUtils";       @@ -1911,74 +1807,11 @@

All files / components const calculatedZoom = Math.log2(360 / region.latitudeDelta); setZoomLevel(calculatedZoom); - // Check if we're zoomed in on the Hall Building - if (hallBuilding ) { - const hallLatLng = { - latitude: hallBuilding.latitude, - longitude: hallBuilding.longitude, - }; - - // Calculate distance between map center and Hall Building - const distance = Math.sqrt( - Math.pow(region.latitude - hallLatLng.latitude, 2) + - Math.pow(region.longitude - hallLatLng.longitude, 2) - ); - - // Determine if we're focused on Hall Building (centered and zoomed in) - const isHallFocused = distance < 0.0005 && calculatedZoom > 18; - setHallBuildingFocused(isHallFocused); - } - if (jmsbBuilding) { - const jmsbLatLng = { - latitude: jmsbBuilding.latitude, - longitude: jmsbBuilding.longitude, - }; - - // Calculate distance between map center and Hall Building - const distance = Math.sqrt( - Math.pow(region.latitude - jmsbLatLng.latitude, 2) + - Math.pow(region.longitude - jmsbLatLng.longitude, 2) - ); - - // Determine if we're focused on Hall Building (centered and zoomed in) - const isJMSBFocused = distance < 0.0006 && calculatedZoom > 18; - setJMSBBuildingFocused(isJMSBFocused); - } -  - if (vanierBuilding) { - const vanierLatLng = { - latitude: vanierBuilding.latitude, - longitude: vanierBuilding.longitude, - }; - - // Calculate distance between map center and Hall Building - const distance = Math.sqrt( - Math.pow(region.latitude - vanierLatLng.latitude, 2) + - Math.pow(region.longitude - vanierLatLng.longitude, 2) - ); - - // Determine if we're focused on Hall Building (centered and zoomed in) - const isVanierFocused = distance < 0.001 && calculatedZoom > 18; - setVanierBuildingFocused(isVanierFocused); - } -  - if (ccBuilding) { - const ccLatLng = { - latitude: ccBuilding.latitude, - longitude: ccBuilding.longitude, - }; - - // Calculate distance between map center and Hall Building - const distance = Math.sqrt( - Math.pow(region.latitude - ccLatLng.latitude, 2) + - Math.pow(region.longitude - ccLatLng.longitude, 2) - ); - - // Determine if we're focused on Hall Building (centered and zoomed in) - const isCCFocused = distance < 0.0005 && calculatedZoom > 18; - setCCBuildingFocused(isCCFocused); - } -  + // Use the helper to determine if each building is focused. + setHallBuildingFocused(isBuildingFocused(region, hallBuilding, calculatedZoom, 0.0005, 18)); + setJMSBBuildingFocused(isBuildingFocused(region, jmsbBuilding, calculatedZoom, 0.0006, 18)); + setVanierBuildingFocused(isBuildingFocused(region, vanierBuilding, calculatedZoom, 0.001, 18)); + setCCBuildingFocused(isBuildingFocused(region, ccBuilding, calculatedZoom, 0.0005, 18)); };   // Search for a building and move the map to it @@ -1988,11 +1821,12 @@

All files / components const building = buildings.find((b) => b.name?.toLowerCase().includes(searchText.toLowerCase()) ); - console.log("Building searched: ",building); + // console.log("Building searched: ",building); if (building){ if (building.building) { - console.log("Room searched: ",building); + console.log("Room searched: ",building.building); setRoom(building); + console.log("room name: ", building.name); let coordinates; if (building.object.id === 'H') {   @@ -2429,13 +2263,20 @@

All files / components </Marker> ))}   - { room != null && + {/* { room != null && (<Marker coordinate={clasroomCoordinates} title={room.name} pinColor="#912338" />) - } + } */} + {/* Room Marker */} +  + <RoomMarker + classroomCoordinates={clasroomCoordinates} + room={room} + router={router} + />   </MapView> @@ -2465,29 +2306,29 @@

All files / components </View> )}   -{jmsbBuildingFocused && ( - <View style={styles.floorSelectorContainer}> - {[1, 2].map((floor) => ( - <TouchableOpacity - key={floor} - style={[ - styles.floorButton, - jmsbSelectedFloor === floor && styles.selectedFloorButton, - ]} - onPress={() => setJMSBSelectedFloor(floor)} - > - <Text - style={[ - styles.floorButtonText, - jmsbSelectedFloor === floor && styles.selectedFloorButtonText - ]} - > - {floor} - </Text> - </TouchableOpacity> - ))} - </View> - )} + {jmsbBuildingFocused && ( + <View style={styles.floorSelectorContainer}> + {[1, 2].map((floor) => ( + <TouchableOpacity + key={floor} + style={[ + styles.floorButton, + jmsbSelectedFloor === floor && styles.selectedFloorButton, + ]} + onPress={() => setJMSBSelectedFloor(floor)} + > + <Text + style={[ + styles.floorButtonText, + jmsbSelectedFloor === floor && styles.selectedFloorButtonText + ]} + > + {floor} + </Text> + </TouchableOpacity> + ))} + </View> + )}   { vanierBuildingFocused && ( <View style={styles.floorSelectorContainer}> @@ -2647,7 +2488,7 @@

All files / components maxWidth: 100, }, }); -const styles = StyleSheet.create({ +export const styles = StyleSheet.create({ floorSelectorContainer: { position: 'absolute', right: 20, @@ -2689,7 +2530,7 @@

All files / components