diff --git a/src/components/Api/Api.tsx b/src/components/Api/Api.tsx index 74b86d5..430124f 100644 --- a/src/components/Api/Api.tsx +++ b/src/components/Api/Api.tsx @@ -246,7 +246,6 @@ export async function GetStudentStatus() { export async function PatchStudentStatus(info: StudentStatusPatchType) { const config = await GetConfig(); - console.log(info); return instance .patch("/api/v1/student_status/self/", info, config) .then((response) => { @@ -297,3 +296,30 @@ export async function GetStudentStatusListFilteredCurrentLocation() { return [false, error_message]; }); } + +export async function GetStudyGroupListFiltered() { + const config = await GetConfig(); + return instance + .get("/api/v1/study_groups/near/", config) + .then((response) => { + return [true, response.data]; + }) + .catch((error) => { + let error_message = ParseError(error); + return [false, error_message]; + }); +} + +export async function GetStudyGroupList() { + const config = await GetConfig(); + return instance + .get("/api/v1/study_groups/", config) + .then((response) => { + console.log("test", response.data); + return [true, response.data]; + }) + .catch((error) => { + let error_message = ParseError(error); + return [false, error_message]; + }); +} diff --git a/src/components/ParseStudentStatusList/ParseStudentStatusList.tsx b/src/components/ParseStudentStatusList/ParseStudentStatusList.tsx deleted file mode 100644 index 4e673c9..0000000 --- a/src/components/ParseStudentStatusList/ParseStudentStatusList.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import * as React from "react"; -import { View, Text } from "react-native"; -import { - StudentStatusFilterType, - LocationType, - subjectUserMapType, - StudentStatusListType, - StudentStatusFilterTypeFlattened, -} from "../../interfaces/Interfaces"; -import { Double, Float } from "react-native/Libraries/Types/CodegenTypes"; - -export default function ParseStudentStatusList(data: any) { - // Individual map point generation for student statuses - // Include only those that do not have study groups - // Then we simply flatten the data. Much simpler compared to study groups - let data_filtered = data.filter( - (item: StudentStatusFilterType) => item.study_group == "" - ); - console.log("Filtered Data:", data_filtered); - // Then we flatten the data so that all attributes are in the first layer - // We first flatten the data to remove nested entries - let data_flattened = data_filtered.map((item: StudentStatusFilterType) => ({ - active: item.active, - distance: item.distance, - landmark: item.landmark, - latitude: item.location.latitude, - longitude: item.location.longitude, - study_group: item.study_group, - subject: item.subject, - user: item.user, - weight: 1, - })); - - return data_flattened; -} diff --git a/src/components/ParseStudyGroupList/ParseStudyGroupList.tsx b/src/components/ParseStudyGroupList/ParseStudyGroupList.tsx deleted file mode 100644 index 93c70cb..0000000 --- a/src/components/ParseStudyGroupList/ParseStudyGroupList.tsx +++ /dev/null @@ -1,173 +0,0 @@ -import * as React from "react"; -import { View, Text } from "react-native"; -import { - StudentStatusFilterType, - LocationType, - subjectUserMapType, - StudentStatusListType, - StudentStatusFilterTypeFlattened, -} from "../../interfaces/Interfaces"; -import { Double, Float } from "react-native/Libraries/Types/CodegenTypes"; - -export default function ParseStudyGroupList( - data: any, - user_location: LocationType -) { - // Circle generation for students in a study group - let result: any[] = []; - // We first remove any instances that do not have a study group associated with it - let data_filtered = data.filter( - (item: StudentStatusFilterType) => item.study_group !== "" - ); - // console.log("Filtered Data:", data_filtered); - // Then we flatten the data so that all attributes are in the first layer - // We first flatten the data to remove nested entries - let data_flattened = data_filtered.map((item: StudentStatusFilterType) => ({ - active: item.active, - distance: item.distance, - landmark: item.landmark, - latitude: item.location.latitude, - longitude: item.location.longitude, - study_group: item.study_group, - subject: item.subject, - user: item.user, - weight: 1, - })); - // console.log("Flattened Data:", data_flattened); - - // We take from the array all unique subject names - let unique_subjects = [ - ...new Set( - data_flattened.map((item: StudentStatusFilterType) => item.subject) - ), - ]; - - // Then we create arrays unique to each subject - unique_subjects.forEach((subject, index: number) => { - // We build another array for each subject, including only those instances that are the same subject name - let unique_subject_list = data_flattened - .filter( - (item: StudentStatusFilterTypeFlattened) => item.subject === subject - ) - .map((item: StudentStatusFilterTypeFlattened) => ({ - active: item.active, - distance: item.distance, - landmark: item.landmark, - latitude: item.latitude, - longitude: item.longitude, - study_group: item.study_group, - subject: item.subject, - user: item.user, - weight: 1, - })); - - /* - let unique_subject_object = data_flattened.filter( - (item: StudentStatusFilterTypeFlattened) => item.subject === subject - ); - */ - - // We get the circle's center by averaging all the points - // Calculate the average latitude and longitude - const totalLat = unique_subject_list.reduce( - (sum: Double, point: LocationType) => sum + point.latitude, - 0 - ); - const totalLng = unique_subject_list.reduce( - (sum: Double, point: LocationType) => sum + point.longitude, - 0 - ); - - let avgLat = totalLat / unique_subject_list.length; - let avgLng = totalLng / unique_subject_list.length; - - // console.log("Center Latitude:", avgLat); - // console.log("Center Longitude:", avgLng); - - // Haversine Distance Function - function haversineDistance( - lat1: number, - lon1: number, - lat2: number, - lon2: number - ) { - function toRad(x: number) { - return (x * Math.PI) / 180; - } - - lat1 = toRad(lat1); - lon1 = toRad(lon1); - lat2 = toRad(lat2); - lon2 = toRad(lon2); - - let dLat = lat2 - lat1; - let dLon = lon2 - lon1; - - let a = - Math.sin(dLat / 2) * Math.sin(dLat / 2) + - Math.cos(lat1) * - Math.cos(lat2) * - Math.sin(dLon / 2) * - Math.sin(dLon / 2); - let c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); - - // Multiply by Earth's radius (in kilometers) to obtain distance - let distance = 6371 * c; - - // Convert to meters - return distance * 1000; - } - - // We now calculate the radius of the circle using the Haversine Distance Formula - // For each entry, we calculate the Haversine Distance from the user's location. - // The largest value is used as the circle radius - - let circle_radius = Math.max( - ...unique_subject_list.map( - (item: StudentStatusFilterTypeFlattened, index: number) => { - let distance = haversineDistance( - item.latitude, - item.longitude, - user_location.latitude, - user_location.longitude - ); - - /*console.log( - "Haversine Distance for entry #", - index + 1, - ":", - distance - );*/ - return distance; - } - ) - ); - // console.log("Radius:", circle_radius); - - // We now build the object that we will return - const subjectUserMap: subjectUserMapType = { - subject: "", - users: [], - latitude: 0, - longitude: 0, - radius: 0, - }; - unique_subject_list.forEach((item: StudentStatusFilterType) => { - if (!subjectUserMap["users"]) { - subjectUserMap["users"] = []; - } - subjectUserMap["subject"] = item.subject; - subjectUserMap["latitude"] = avgLat; - subjectUserMap["longitude"] = avgLng; - subjectUserMap["radius"] = circle_radius; - subjectUserMap["users"].push(item.user); - }); - console.log(subjectUserMap); - - result = result.concat([subjectUserMap]); - }); - - // console.log("Final Result:", result); - - return result; -} diff --git a/src/interfaces/Interfaces.tsx b/src/interfaces/Interfaces.tsx index 7623b88..be6d983 100644 --- a/src/interfaces/Interfaces.tsx +++ b/src/interfaces/Interfaces.tsx @@ -166,6 +166,17 @@ export interface StudentStatusFilterTypeFlattened { weight?: number; } +export interface StudyGroupType { + name: string; + users: string[]; + distance: number; + landmark: string | null; + location: LocationType; + subject: string; + radius: number; +} +export type StudyGroupReturnType = [boolean, StudyGroupType[]]; + export type StudentStatusReturnType = [boolean, StudentStatusType]; export type StudentStatusListType = Array; diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index 3a0317a..f926c26 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -24,20 +24,23 @@ import { subjectUserMapType, StudentStatusFilterTypeFlattened, StudentStatusPatchType, + StudyGroupType, + StudyGroupReturnType, + StudentStatusFilterType, } from "../../interfaces/Interfaces"; import { useNavigation } from "@react-navigation/native"; import { GetStudentStatus, GetStudentStatusList, GetStudentStatusListFiltered, + GetStudyGroupList, + GetStudyGroupListFiltered, PatchStudentStatus, urlProvider, } from "../../components/Api/Api"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { useToast } from "react-native-toast-notifications"; import React from "react"; -import ParseStudyGroupList from "../../components/ParseStudyGroupList/ParseStudyGroupList"; -import ParseStudentStatusList from "../../components/ParseStudentStatusList/ParseStudentStatusList"; import CustomMapCallout from "../../components/CustomMapCallout/CustomMapCallout"; import MapRendererFar from "../../components/MapRenderer/MapRendererFar"; import GetDistanceFromUSTP from "../../components/GetDistance/GetDistanceFromUSTP"; @@ -120,7 +123,7 @@ export default function Home() { const [subject, setSubject] = useState(""); const [buttonLabel, setButtonLabel] = useState("Start studying"); const [student_status, setStudentStatus] = useState(); - const StudentStatus = useQuery({ + const StudentStatusQuery = useQuery({ queryKey: ["user_status"], queryFn: async () => { const data = await GetStudentStatus(); @@ -182,12 +185,10 @@ export default function Home() { }, }); - const [student_statuses, setStudentStatuses] = useState< - StudentStatusFilterTypeFlattened[] - >([]); - const [study_groups, setStudyGroups] = useState([]); + const [student_statuses, setStudentStatuses] = + useState([]); // Student Status List - const StudentStatusList = useQuery({ + const StudentStatusListQuery = useQuery({ enabled: studying, queryKey: ["user_status_list"], queryFn: async () => { @@ -199,13 +200,66 @@ export default function Home() { }, onSuccess: (data: StudentStatusListReturnType) => { if (data[1] && location) { - setStudyGroups( - ParseStudyGroupList(data[1], { - latitude: location.coords.latitude, - longitude: location.coords.longitude, - }) + // Filter to only include students studying solo + let data_filtered = data[1].filter( + (item: StudentStatusFilterType) => item.study_group == "" ); - setStudentStatuses(ParseStudentStatusList(data[1])); + setStudentStatuses(data_filtered); + } + }, + onError: (error: Error) => { + toast.show(String(error), { + type: "warning", + placement: "top", + duration: 2000, + animationType: "slide-in", + }); + }, + }); + + const [study_groups, setStudyGroups] = useState([]); + // Student Status List + const StudyGroupQuery = useQuery({ + enabled: studying, + queryKey: ["study_group_list"], + queryFn: async () => { + const data = await GetStudyGroupListFiltered(); + if (data[0] == false) { + return Promise.reject(new Error(JSON.stringify(data[1]))); + } + return data; + }, + onSuccess: (data: StudyGroupReturnType) => { + if (data[1] && location) { + setStudyGroups(data[1]); + } + }, + onError: (error: Error) => { + toast.show(String(error), { + type: "warning", + placement: "top", + duration: 2000, + animationType: "slide-in", + }); + }, + }); + const [study_groups_global, setStudyGroupsGlobal] = useState< + StudyGroupType[] + >([]); + // Student Status List + const StudyGroupGlobalQuery = useQuery({ + enabled: !studying, + queryKey: ["study_group_list_global"], + queryFn: async () => { + const data = await GetStudyGroupList(); + if (data[0] == false) { + return Promise.reject(new Error(JSON.stringify(data[1]))); + } + return data; + }, + onSuccess: (data: StudyGroupReturnType) => { + if (data[1] && location) { + setStudyGroupsGlobal(data[1]); } }, onError: (error: Error) => { @@ -243,18 +297,19 @@ export default function Home() { minZoomLevel={19} zoomTapEnabled initialRegion={{ - latitude: location.coords.latitude, - longitude: location.coords.longitude, + latitude: + student_status?.location?.latitude || + location.coords.latitude, + longitude: + student_status?.location?.longitude || + location.coords.longitude, latitudeDelta: 0.4, longitudeDelta: 0.4, }} loadingBackgroundColor={colors.secondary_2} > {student_statuses.map( - ( - student_status: StudentStatusFilterTypeFlattened, - index: number - ) => { + (student_status: StudentStatusFilterType, index: number) => { const randomColorWithOpacity = `rgba(${Math.floor( Math.random() * 256 )}, ${Math.floor(Math.random() * 256)}, ${Math.floor( @@ -264,7 +319,7 @@ export default function Home() { return ( { @@ -301,8 +356,76 @@ export default function Home() { ); } )} - {study_groups.map( - (student_status: subjectUserMapType, index: number) => { + {study_groups.map((studygroup: StudyGroupType, index: number) => { + const randomColorWithOpacity = `rgba(${Math.floor( + Math.random() * 256 + )}, ${Math.floor(Math.random() * 256)}, ${Math.floor( + Math.random() * 256 + )}, 0.7)`; + + return ( + + { + toast.hideAll(); + toast.show( + + + Subject: {studygroup.subject} + + + Students Studying: {studygroup.users.length} + + + , + { + type: "normal", + placement: "top", + duration: 2000, + animationType: "slide-in", + style: { + backgroundColor: colors.secondary_2, + borderWidth: 1, + borderColor: colors.primary_1, + }, + } + ); + }} + /> + + + ); + })} + {study_groups_global.map( + (studygroup: StudyGroupType, index: number) => { const randomColorWithOpacity = `rgba(${Math.floor( Math.random() * 256 )}, ${Math.floor(Math.random() * 256)}, ${Math.floor( @@ -312,7 +435,7 @@ export default function Home() { return ( { @@ -326,10 +449,10 @@ export default function Home() { }} > - Subject: {student_status.subject} + Subject: {studygroup.subject} - Students Studying: {student_status.users.length} + Students Studying: {studygroup.users.length}