From b43577870bb6b11a71b21a18d2ae2406a697b61b Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Wed, 26 Jul 2023 10:03:25 +0800 Subject: [PATCH 001/109] Homepage improvements --- src/components/Api/Api.tsx | 4 +++- src/routes/Home/Home.tsx | 48 +++++++++++++++++++++++++++----------- src/routes/Login/Login.tsx | 2 +- 3 files changed, 38 insertions(+), 16 deletions(-) diff --git a/src/components/Api/Api.tsx b/src/components/Api/Api.tsx index 20a3151..e1eb813 100644 --- a/src/components/Api/Api.tsx +++ b/src/components/Api/Api.tsx @@ -12,7 +12,7 @@ import { export let backendURL = ""; export let backendURLWebsocket = ""; let use_production = true; -if (__DEV__ || !use_production) { +if (__DEV__ && !use_production) { backendURL = "http://10.0.10.8:8000"; backendURLWebsocket = "ws://10.0.10.8:8000"; } else { @@ -25,6 +25,8 @@ const instance = axios.create({ timeout: 1000, }); +console.log(backendURL); + // App APIs // Token Handling diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index f80af2e..f18c804 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -19,8 +19,8 @@ export default function Home() { const ustpCoords = { latitude: 8.4857, longitude: 124.6565, - latitudeDelta: 0.000235, - longitudeDelta: 0.000067, + latitudeDelta: 0.4, + longitudeDelta: 0.4, }; async function requestLocation() { const { status } = await Location.requestForegroundPermissionsAsync(); @@ -62,27 +62,19 @@ export default function Home() { let dist = GetDistance( location.coords.latitude, location.coords.longitude, - 8.4857, // LatitudeDelta - 124.6565 // LongitudeDelta + 0.4, + 0.4 ); setDist(Math.round(dist)); } function CustomMap() { if (dist && location) { - if (dist <= 1.5) { + if (dist >= 2) { // Just switch this condition for map debugging return ( + onPress={() => console.log(location)} + pinColor={colors.primary_1} + > + + + You are here {"\n"} + X: {Math.round(location.coords.longitude) + "\n"} + Z: {Math.round(location.coords.latitude)} + + + ); } else { @@ -145,6 +163,7 @@ export default function Home() { latitudeDelta: 0.0922, longitudeDelta: 0.0421, }} + loadingBackgroundColor={colors.secondary_2} > + You are here {"\n"} X: {Math.round(location.coords.longitude) + "\n"} Z: {Math.round(location.coords.latitude)} diff --git a/src/routes/Login/Login.tsx b/src/routes/Login/Login.tsx index 34a3d6f..8789fad 100644 --- a/src/routes/Login/Login.tsx +++ b/src/routes/Login/Login.tsx @@ -94,7 +94,7 @@ export default function Login() { } console.log(JSON.stringify(user_info)); } else { - console.log("heh", ParseLoginError(JSON.stringify(result[1]))); + console.log(ParseLoginError(JSON.stringify(result[1]))); setError(ParseLoginError(JSON.stringify(result[1]))); } }); From cd85852c9b3b4f2100a68530e20a0e11196675b3 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Wed, 26 Jul 2023 10:04:15 +0800 Subject: [PATCH 002/109] Fixed condition in homepage --- src/routes/Home/Home.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index f18c804..7f146cd 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -70,7 +70,7 @@ export default function Home() { function CustomMap() { if (dist && location) { - if (dist >= 2) { + if (dist <= 2) { // Just switch this condition for map debugging return ( Date: Wed, 26 Jul 2023 12:52:24 +0800 Subject: [PATCH 003/109] Fixed homepage distance bug --- src/routes/Home/Home.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index 7f146cd..bbe1b6e 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -19,8 +19,8 @@ export default function Home() { const ustpCoords = { latitude: 8.4857, longitude: 124.6565, - latitudeDelta: 0.4, - longitudeDelta: 0.4, + latitudeDelta: 0.000235, + longitudeDelta: 0.000067, }; async function requestLocation() { const { status } = await Location.requestForegroundPermissionsAsync(); @@ -62,8 +62,8 @@ export default function Home() { let dist = GetDistance( location.coords.latitude, location.coords.longitude, - 0.4, - 0.4 + 8.4857, // LatitudeDelta + 124.6565 // LongitudeDelta ); setDist(Math.round(dist)); } From 3331ccb9745b52d2fea815991c4c988f6967e9e6 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Thu, 27 Jul 2023 00:01:44 +0800 Subject: [PATCH 004/109] Pray to the gods the duplicate subjects bug is fixed. Move irregular status toggle to user info page from subjects page --- src/components/Api/Api.tsx | 54 ++++----------- src/interfaces/Interfaces.tsx | 12 ++-- src/routes/Revalidation/Revalidation.tsx | 8 +-- src/routes/SubjectsPage/SubjectsPage.tsx | 88 +++++------------------- src/routes/UserInfoPage/UserInfoPage.tsx | 72 ++++++++++--------- 5 files changed, 79 insertions(+), 155 deletions(-) diff --git a/src/components/Api/Api.tsx b/src/components/Api/Api.tsx index e1eb813..58c3804 100644 --- a/src/components/Api/Api.tsx +++ b/src/components/Api/Api.tsx @@ -11,7 +11,7 @@ import { export let backendURL = ""; export let backendURLWebsocket = ""; -let use_production = true; +let use_production = false; if (__DEV__ && !use_production) { backendURL = "http://10.0.10.8:8000"; backendURLWebsocket = "ws://10.0.10.8:8000"; @@ -224,47 +224,19 @@ export async function GetYearLevels() { }); } -export async function GetSubjects( - byCourseOnly: boolean, - course: string, - year_level?: string, - semester?: string -) { +export async function GetSubjects() { const config = await GetConfig(); - console.log("by course only?", byCourseOnly); - // If year level and semester specified, - if (!byCourseOnly && year_level && semester) { - return instance - .get( - "/api/v1/subjects/" + course + "/" + year_level + "/" + semester, - config - ) - .then((response) => { - // console.log(JSON.stringify(response.data)); - return [true, response.data]; - }) - .catch((error) => { - let error_message = ""; - if (error.response) error_message = error.response.data; - else error_message = "Unable to reach servers"; - return [false, error_message]; - }); - } - // If only course is specified - else { - return instance - .get("/api/v1/subjects/" + course, config) - .then((response) => { - // console.log(JSON.stringify(response.data)); - return [true, response.data]; - }) - .catch((error) => { - let error_message = ""; - if (error.response) error_message = error.response.data; - else error_message = "Unable to reach servers"; - return [false, error_message]; - }); - } + return instance + .get("/api/v1/subjects/", config) + .then((response) => { + return [true, response.data]; + }) + .catch((error) => { + let error_message = ""; + if (error.response) error_message = error.response.data; + else error_message = "Unable to reach servers"; + return [false, error_message]; + }); } export async function OnboardingUpdateStudentInfo(info: OnboardingParams) { diff --git a/src/interfaces/Interfaces.tsx b/src/interfaces/Interfaces.tsx index 2b6e526..7c83a9b 100644 --- a/src/interfaces/Interfaces.tsx +++ b/src/interfaces/Interfaces.tsx @@ -85,11 +85,12 @@ export type CourseParams = [boolean, Courses]; // Subject export interface Subject { + id: number; name: string; code: string; - // courses: any[]; // To-do - // year_levels: any[]; // To-do - // semesters: any[]; // To-do + course: string; + year_level: string; + semester: string; } export type Subjects = Array; @@ -110,6 +111,7 @@ export interface PatchStudentData { semester?: string | null; subjects?: any[] | null; // To-do, replace 'any' with your actual type year_level?: string | null; + irregular?: boolean | null; } export interface StudentData { @@ -118,14 +120,14 @@ export interface StudentData { email: string; avatar: string; student_id_number: string; - is_banned: boolean; + irregular: boolean; semester: string; semester_shortname: string; course: string; course_shortname: string; year_level: string; yearlevel_shortname: string; - subjects: any[]; // To-do + subjects: Subject[]; // To-do username: string; } diff --git a/src/routes/Revalidation/Revalidation.tsx b/src/routes/Revalidation/Revalidation.tsx index ce5b1dc..c7d9869 100644 --- a/src/routes/Revalidation/Revalidation.tsx +++ b/src/routes/Revalidation/Revalidation.tsx @@ -28,11 +28,9 @@ export default function Revalidation() { dispatch(login()); dispatch(setUser(user_info[1])); if ( - !( - user_info[1].year_level || - user_info[1].course || - user_info[1].semester - ) + !user_info[1].year_level || + !user_info[1].course || + !user_info[1].semester ) { dispatch(setOnboarding()); await setTimeout(() => { diff --git a/src/routes/SubjectsPage/SubjectsPage.tsx b/src/routes/SubjectsPage/SubjectsPage.tsx index c95815b..1790663 100644 --- a/src/routes/SubjectsPage/SubjectsPage.tsx +++ b/src/routes/SubjectsPage/SubjectsPage.tsx @@ -33,9 +33,11 @@ import { import { colors } from "../../styles"; import DropDownPicker from "react-native-dropdown-picker"; import AnimatedContainerNoScroll from "../../components/AnimatedContainer/AnimatedContainerNoScroll"; -import BouncyCheckbox from "react-native-bouncy-checkbox"; +import { useSelector } from "react-redux"; +import { RootState } from "../../features/redux/Store/Store"; export default function SubjectsPage() { + const logged_in_user = useSelector((state: RootState) => state.user.user); const queryClient = useQueryClient(); // User Info const [user, setUser] = useState({ @@ -51,15 +53,10 @@ export default function SubjectsPage() { student_id_number: "", subjects: [] as Subjects, }); - const [displayName, setDisplayName] = useState({ - first_name: "", - last_name: "", - }); const StudentInfo = useQuery({ queryKey: ["user"], queryFn: UserInfo, onSuccess: (data: UserInfoParams) => { - // console.log(data[1]); setUser({ ...user, first_name: data[1].first_name, @@ -71,31 +68,18 @@ export default function SubjectsPage() { student_id_number: data[1].student_id_number, subjects: data[1].subjects, }); - setDisplayName({ - first_name: data[1].first_name, - last_name: data[1].last_name, - }); - setSelectedSubjects(user.subjects); + setSelectedSubjects(data[1].subjects); }, }); const mutation = useMutation({ mutationFn: PatchUserInfo, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["user"] }); - queryClient.invalidateQueries({ queryKey: ["subjects", viewAll] }); + queryClient.invalidateQueries({ queryKey: ["subjects"] }); setSelectedSubjects([]); }, }); - // View all Subjects or only view those under current course, year level, and semester - // This is for irregular students - const [viewAll, setViewAll] = useState(false); - - // If viewing all subjects, refresh the choices - useEffect(() => { - queryClient.invalidateQueries({ queryKey: ["subjects", viewAll] }); - }, [viewAll]); - // Subjects const [selected_subjects, setSelectedSubjects] = useState([]); @@ -104,42 +88,17 @@ export default function SubjectsPage() { const Subjects = useQuery({ enabled: StudentInfo.isFetched, - queryKey: ["subjects", viewAll], - queryFn: async () => { - let data; - if ( - StudentInfo.data && - StudentInfo.data[1].course_shortname && - StudentInfo.data[1].yearlevel_shortname && - StudentInfo.data[1].semester_shortname - ) { - data = await GetSubjects( - viewAll, - StudentInfo.data[1].course_shortname, - StudentInfo.data[1].yearlevel_shortname, - StudentInfo.data[1].semester_shortname - ); - console.log(JSON.stringify(data)); - } - if (data) { - if (!data[0]) { - throw new Error("Error with query" + data[1]); - } - if (!data[1]) { - throw new Error("User has no course, year level, or semester!"); - } - // console.log("Subjects available:", data[1]); - } - return data; - }, + queryKey: ["subjects"], + queryFn: GetSubjects, onSuccess: (data: SubjectParams) => { - let subjectsData = data[1].map((subject: Subject) => ({ - label: subject.name, - value: subject.name, - })); - // Update the 'subjects' state - setSelectedSubjects(user.subjects); - setSubjects(subjectsData); + if (data[1]) { + let subjects = data[1].map((subject: Subject) => ({ + label: subject.name, + value: subject.name, + })); + + setSubjects(subjects); + } }, }); @@ -163,9 +122,9 @@ export default function SubjectsPage() { - {(displayName.first_name || "Undefined") + + {(logged_in_user.first_name || "Undefined") + " " + - (displayName.last_name || "User") + + (logged_in_user.last_name || "User") + "\n" + user.student_id_number} @@ -211,22 +170,9 @@ export default function SubjectsPage() { - - - { - setViewAll(!viewAll); - setSubjectsOpen(false); - }} - fillColor={colors.secondary_3} - /> - Irregular - From e4278517bc59a18f4fcd0cd661654ab4df15cc20 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Thu, 27 Jul 2023 00:06:32 +0800 Subject: [PATCH 005/109] Code cleanup in api.tsx --- src/components/Api/Api.tsx | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/components/Api/Api.tsx b/src/components/Api/Api.tsx index 58c3804..eaa4b18 100644 --- a/src/components/Api/Api.tsx +++ b/src/components/Api/Api.tsx @@ -9,15 +9,11 @@ import { StudentData, } from "../../interfaces/Interfaces"; -export let backendURL = ""; -export let backendURLWebsocket = ""; -let use_production = false; -if (__DEV__ && !use_production) { +export let backendURL = "https://stude.keannu1.duckdns.org"; +export let backendURLWebsocket = "ws://stude.keannu1.duckdns.org"; +if (__DEV__) { backendURL = "http://10.0.10.8:8000"; backendURLWebsocket = "ws://10.0.10.8:8000"; -} else { - backendURL = "https://stude.keannu1.duckdns.org"; - backendURLWebsocket = "ws://stude.keannu1.duckdns.org"; } const instance = axios.create({ From 1a46945d1e4ad8d6ae59250e8fcc2bfb2e0e7094 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Thu, 27 Jul 2023 00:09:43 +0800 Subject: [PATCH 006/109] Code cleanup in api.tsx --- src/components/Api/Api.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/components/Api/Api.tsx b/src/components/Api/Api.tsx index eaa4b18..44f6e7d 100644 --- a/src/components/Api/Api.tsx +++ b/src/components/Api/Api.tsx @@ -16,6 +16,13 @@ if (__DEV__) { backendURLWebsocket = "ws://10.0.10.8:8000"; } +// Switch this on if you wanna run production URLs while in development +let use_production = false; +if (use_production) { + backendURL = "https://stude.keannu1.duckdns.org"; + backendURLWebsocket = "ws://stude.keannu1.duckdns.org"; +} + const instance = axios.create({ baseURL: backendURL, timeout: 1000, From a3b3bd887f43b06583811b1efcbb8fc2545fa344 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Thu, 27 Jul 2023 12:55:51 +0800 Subject: [PATCH 007/109] Add user feedback to user info and subjects page --- src/components/Api/Api.tsx | 2 +- src/routes/SubjectsPage/SubjectsPage.tsx | 12 +++++++++- src/routes/UserInfoPage/UserInfoPage.tsx | 30 ++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/components/Api/Api.tsx b/src/components/Api/Api.tsx index 44f6e7d..45701b9 100644 --- a/src/components/Api/Api.tsx +++ b/src/components/Api/Api.tsx @@ -17,7 +17,7 @@ if (__DEV__) { } // Switch this on if you wanna run production URLs while in development -let use_production = false; +let use_production = true; if (use_production) { backendURL = "https://stude.keannu1.duckdns.org"; backendURLWebsocket = "ws://stude.keannu1.duckdns.org"; diff --git a/src/routes/SubjectsPage/SubjectsPage.tsx b/src/routes/SubjectsPage/SubjectsPage.tsx index 1790663..b0429e0 100644 --- a/src/routes/SubjectsPage/SubjectsPage.tsx +++ b/src/routes/SubjectsPage/SubjectsPage.tsx @@ -39,6 +39,7 @@ import { RootState } from "../../features/redux/Store/Store"; export default function SubjectsPage() { const logged_in_user = useSelector((state: RootState) => state.user.user); const queryClient = useQueryClient(); + const [feedback, setFeedback] = useState(""); // User Info const [user, setUser] = useState({ first_name: "", @@ -70,6 +71,9 @@ export default function SubjectsPage() { }); setSelectedSubjects(data[1].subjects); }, + onError: () => { + setFeedback("Unable to query user info"); + }, }); const mutation = useMutation({ mutationFn: PatchUserInfo, @@ -77,6 +81,7 @@ export default function SubjectsPage() { queryClient.invalidateQueries({ queryKey: ["user"] }); queryClient.invalidateQueries({ queryKey: ["subjects"] }); setSelectedSubjects([]); + setFeedback("Changes applied successfully"); }, }); @@ -100,6 +105,9 @@ export default function SubjectsPage() { setSubjects(subjects); } }, + onError: () => { + setFeedback("Unable to query subject info"); + }, }); // Profile photo @@ -178,8 +186,10 @@ export default function SubjectsPage() { }); }} > - Save Change + Save Changes + + {feedback} diff --git a/src/routes/UserInfoPage/UserInfoPage.tsx b/src/routes/UserInfoPage/UserInfoPage.tsx index 6c16306..3ef6a8a 100644 --- a/src/routes/UserInfoPage/UserInfoPage.tsx +++ b/src/routes/UserInfoPage/UserInfoPage.tsx @@ -44,6 +44,7 @@ export default function UserInfoPage() { const logged_in_user = useSelector((state: RootState) => state.user.user); const dispatch = useDispatch(); const queryClient = useQueryClient(); + const [feedback, setFeedback] = useState(""); // User Info const [user, setUser] = useState({ first_name: "", @@ -79,14 +80,21 @@ export default function UserInfoPage() { setSelectedYearLevel(data[1].year_level); dispatch(setUserinState(data[1])); }, + onError: () => { + setFeedback("Unable to query user info"); + }, }); const mutation = useMutation({ mutationFn: PatchUserInfo, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["user"] }); queryClient.invalidateQueries({ queryKey: ["subjects"] }); + setFeedback("Changes applied successfully"); dispatch(setUserinState(user)); }, + onError: () => { + setFeedback("An error has occured\nChanges have not been saved"); + }, }); // Semester @@ -105,6 +113,9 @@ export default function UserInfoPage() { // Update the 'semesters' state setSemesters(semestersData); }, + onError: () => { + setFeedback("Unable to query semester info"); + }, }); // Year Level @@ -121,6 +132,9 @@ export default function UserInfoPage() { })); setYearLevels(year_levels); }, + onError: () => { + setFeedback("Unable to query year level info"); + }, }); // Course @@ -137,6 +151,9 @@ export default function UserInfoPage() { })); setCourses(courses); }, + onError: () => { + setFeedback("Unable to query course info"); + }, }); // Profile photo @@ -179,6 +196,7 @@ export default function UserInfoPage() { e: NativeSyntheticEvent ): void => { setUser({ ...user, first_name: e.nativeEvent.text }); + setFeedback(""); }} value={user.first_name} /> @@ -195,6 +213,7 @@ export default function UserInfoPage() { e: NativeSyntheticEvent ): void => { setUser({ ...user, last_name: e.nativeEvent.text }); + setFeedback(""); }} value={user.last_name} /> @@ -216,6 +235,9 @@ export default function UserInfoPage() { setCourseOpen(false); }} setValue={setSelectedYearLevel} + onChangeValue={() => { + setFeedback(""); + }} placeholder={user.year_level} placeholderStyle={{ ...styles.text_white_tiny_bold, @@ -251,6 +273,9 @@ export default function UserInfoPage() { setCourseOpen(false); }} setValue={setSelectedSemester} + onChangeValue={() => { + setFeedback(""); + }} placeholder={user.semester} placeholderStyle={{ ...styles.text_white_tiny_bold, @@ -286,6 +311,9 @@ export default function UserInfoPage() { setCourseOpen(open); }} setValue={setSelectedCourse} + onChangeValue={() => { + setFeedback(""); + }} placeholder={user.course} placeholderStyle={{ ...styles.text_white_tiny_bold, @@ -337,6 +365,8 @@ export default function UserInfoPage() { > Save Changes + + {feedback} From e4d64f365631410dc2dee0b8c7efcd2ab4aa30a5 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Thu, 27 Jul 2023 16:00:31 +0800 Subject: [PATCH 008/109] Added avatar uploading --- app.json | 10 ++++-- package-lock.json | 28 ++++++++++++++++ package.json | 3 ++ src/components/Api/Api.tsx | 5 +-- src/interfaces/Interfaces.tsx | 6 ++++ src/routes/UserInfoPage/UserInfoPage.tsx | 42 +++++++++++++++++++----- src/styles.tsx | 2 ++ 7 files changed, 84 insertions(+), 12 deletions(-) diff --git a/app.json b/app.json index 893a6ba..2456397 100644 --- a/app.json +++ b/app.json @@ -42,9 +42,15 @@ [ "expo-location", { - "locationAlwaysAndWhenInUsePermission": "Allow Stud-E to use your location." + "locationAlwaysAndWhenInUsePermission": "Allow StudE to use your location." } - ] + ], + [ + "expo-image-picker", + { + "photosPermission": "Allow StudE to take and send photos for sharing in-app" + } + ] ], "extra": { "eas": { diff --git a/package-lock.json b/package-lock.json index 2c02127..14006b9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,8 @@ "@tanstack/react-query": "^4.29.25", "axios": "^1.4.0", "expo": "~48.0.18", + "expo-file-system": "~15.2.2", + "expo-image-picker": "~14.1.1", "expo-intent-launcher": "~10.5.2", "expo-linking": "~4.0.1", "expo-location": "~15.1.1", @@ -41,6 +43,7 @@ "devDependencies": { "@babel/core": "^7.20.0", "@types/react": "~18.0.14", + "@types/react-native-fetch-blob": "^0.10.7", "typescript": "^4.9.4" } }, @@ -5311,6 +5314,12 @@ "csstype": "^3.0.2" } }, + "node_modules/@types/react-native-fetch-blob": { + "version": "0.10.7", + "resolved": "https://registry.npmjs.org/@types/react-native-fetch-blob/-/react-native-fetch-blob-0.10.7.tgz", + "integrity": "sha512-9UTvmUvArimShiENeR3xnRO71NcZjpTi7AcFAIbhdTIfqQOO2OK/I/DpUPXcZF/erffLxOoRkoXrZOxyBBWKRQ==", + "dev": true + }, "node_modules/@types/scheduler": { "version": "0.16.3", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", @@ -7458,6 +7467,25 @@ "expo": "*" } }, + "node_modules/expo-image-loader": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/expo-image-loader/-/expo-image-loader-4.1.1.tgz", + "integrity": "sha512-ciEHVokU0f6w0eTxdRxLCio6tskMsjxWIoV92+/ZD37qePUJYMfEphPhu1sruyvMBNR8/j5iyOvPFVGTfO8oxA==", + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-image-picker": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/expo-image-picker/-/expo-image-picker-14.1.1.tgz", + "integrity": "sha512-SvWtnkLW7jp5Ntvk3lVcRQmhFYja8psmiR7O6P/+7S6f4llt3vaFwb4I3+pUXqJxxpi7BHc2+95qOLf0SFOIag==", + "dependencies": { + "expo-image-loader": "~4.1.0" + }, + "peerDependencies": { + "expo": "*" + } + }, "node_modules/expo-intent-launcher": { "version": "10.5.2", "resolved": "https://registry.npmjs.org/expo-intent-launcher/-/expo-intent-launcher-10.5.2.tgz", diff --git a/package.json b/package.json index 5d4609b..5af9ec0 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,8 @@ "@tanstack/react-query": "^4.29.25", "axios": "^1.4.0", "expo": "~48.0.18", + "expo-file-system": "~15.2.2", + "expo-image-picker": "~14.1.1", "expo-intent-launcher": "~10.5.2", "expo-linking": "~4.0.1", "expo-location": "~15.1.1", @@ -42,6 +44,7 @@ "devDependencies": { "@babel/core": "^7.20.0", "@types/react": "~18.0.14", + "@types/react-native-fetch-blob": "^0.10.7", "typescript": "^4.9.4" }, "private": true diff --git a/src/components/Api/Api.tsx b/src/components/Api/Api.tsx index 45701b9..0f4e758 100644 --- a/src/components/Api/Api.tsx +++ b/src/components/Api/Api.tsx @@ -17,7 +17,7 @@ if (__DEV__) { } // Switch this on if you wanna run production URLs while in development -let use_production = true; +let use_production = false; if (use_production) { backendURL = "https://stude.keannu1.duckdns.org"; backendURLWebsocket = "ws://stude.keannu1.duckdns.org"; @@ -142,6 +142,7 @@ export async function UserInfo() { } export async function PatchUserInfo(info: PatchStudentData) { + console.log("API", JSON.stringify(info)); const config = await GetConfig(); return instance .patch("/api/v1/accounts/users/me/", info, config) @@ -153,7 +154,7 @@ export async function PatchUserInfo(info: PatchStudentData) { let error_message = ""; if (error.response) error_message = error.response.data; else error_message = "Unable to reach servers"; - // console.log(error_message); + console.log(error_message); return [false, error_message]; }); } diff --git a/src/interfaces/Interfaces.tsx b/src/interfaces/Interfaces.tsx index 7c83a9b..40b0348 100644 --- a/src/interfaces/Interfaces.tsx +++ b/src/interfaces/Interfaces.tsx @@ -96,6 +96,11 @@ export interface Subject { export type Subjects = Array; export type SubjectParams = [boolean, Subjects]; +export type avatar = { + uri: string; + type: string; + name: string; +}; // For dropdown menu export interface OnboardingParams { @@ -112,6 +117,7 @@ export interface PatchStudentData { subjects?: any[] | null; // To-do, replace 'any' with your actual type year_level?: string | null; irregular?: boolean | null; + avatar?: string | null; } export interface StudentData { diff --git a/src/routes/UserInfoPage/UserInfoPage.tsx b/src/routes/UserInfoPage/UserInfoPage.tsx index 3ef6a8a..0453bd6 100644 --- a/src/routes/UserInfoPage/UserInfoPage.tsx +++ b/src/routes/UserInfoPage/UserInfoPage.tsx @@ -6,6 +6,7 @@ import { TextInput, NativeSyntheticEvent, TextInputChangeEventData, + Pressable, } from "react-native"; import { useState } from "react"; import { @@ -32,13 +33,14 @@ import { } from "../../components/Api/Api"; import { colors } from "../../styles"; import DropDownPicker from "react-native-dropdown-picker"; -import { ValueType } from "react-native-dropdown-picker"; import AnimatedContainerNoScroll from "../../components/AnimatedContainer/AnimatedContainerNoScroll"; import BouncyCheckbox from "react-native-bouncy-checkbox"; import { useSelector } from "react-redux"; import { RootState } from "../../features/redux/Store/Store"; import { useDispatch } from "react-redux"; import { setUser as setUserinState } from "../../features/redux/slices/UserSlice/UserSlice"; +import * as ImagePicker from "expo-image-picker"; +import * as FileSystem from "expo-file-system"; export default function UserInfoPage() { const logged_in_user = useSelector((state: RootState) => state.user.user); @@ -71,9 +73,9 @@ export default function UserInfoPage() { year_level: data[1].year_level, semester: data[1].semester, course: data[1].course, - avatar: data[1].avatar, student_id_number: data[1].student_id_number, irregular: data[1].irregular, + avatar: data[1].avatar, }); setSelectedCourse(data[1].course); setSelectedSemester(data[1].semester); @@ -157,15 +159,39 @@ export default function UserInfoPage() { }); // Profile photo + const pickImage = async () => { + // No permissions request is necessary for launching the image library + let result = await ImagePicker.launchImageLibraryAsync({ + mediaTypes: ImagePicker.MediaTypeOptions.All, + allowsEditing: true, + aspect: [4, 3], + quality: 1, + }); + if (!result.canceled) { + const encodedImage = await FileSystem.readAsStringAsync( + result.assets[0].uri, + { encoding: "base64" } + ); + mutation.mutate({ + avatar: encodedImage, + }); + } + }; function Avatar() { if (user.avatar) { - return ; + return ( + + + + ); } else { return ( - + + + ); } } @@ -350,7 +376,7 @@ export default function UserInfoPage() { Irregular + ); } else { return ( diff --git a/src/routes/Loading/Loading.tsx b/src/routes/Loading/Loading.tsx new file mode 100644 index 0000000..9fb7c7c --- /dev/null +++ b/src/routes/Loading/Loading.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; +import styles from "../../styles"; +import { View, Text, ActivityIndicator } from "react-native"; +import { colors } from "../../styles"; +import AnimatedContainer from "../../components/AnimatedContainer/AnimatedContainer"; + +export default function Loading() { + return ( + + + + + Loading StudE... + + + ); +} diff --git a/src/routes/UserInfoPage/UserInfoPage.tsx b/src/routes/UserInfoPage/UserInfoPage.tsx index 0453bd6..d713a2f 100644 --- a/src/routes/UserInfoPage/UserInfoPage.tsx +++ b/src/routes/UserInfoPage/UserInfoPage.tsx @@ -361,7 +361,7 @@ export default function UserInfoPage() { - + { mutation.mutate({ diff --git a/src/styles.tsx b/src/styles.tsx index c0fb9e6..546847e 100644 --- a/src/styles.tsx +++ b/src/styles.tsx @@ -171,7 +171,8 @@ const styles = StyleSheet.create({ width: "70%", }, map: { - height: Viewport.height * 0.8, + marginVertical: 4, + height: Viewport.height * 0.7, width: Viewport.width * 0.8, alignSelf: "center", }, From 126223394dad11694fd9c8dd12c68d8821ce0f17 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Mon, 7 Aug 2023 14:22:47 +0800 Subject: [PATCH 012/109] Remove bottomsheet library and added homepage improvements --- package-lock.json | 38 ----------------------------------- package.json | 1 - src/components/Api/Api.tsx | 2 +- src/interfaces/Interfaces.tsx | 5 +++-- src/routes/Home/Home.tsx | 6 +++--- 5 files changed, 7 insertions(+), 45 deletions(-) diff --git a/package-lock.json b/package-lock.json index 078f13d..14006b9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,6 @@ "name": "stude_frontend", "version": "1.0.0", "dependencies": { - "@gorhom/bottom-sheet": "^4.4.7", "@react-native-async-storage/async-storage": "1.17.11", "@react-navigation/drawer": "^6.6.3", "@react-navigation/native": "^6.1.7", @@ -3112,43 +3111,6 @@ "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==" }, - "node_modules/@gorhom/bottom-sheet": { - "version": "4.4.7", - "resolved": "https://registry.npmjs.org/@gorhom/bottom-sheet/-/bottom-sheet-4.4.7.tgz", - "integrity": "sha512-ukTuTqDQi2heo68hAJsBpUQeEkdqP9REBcn47OpuvPKhdPuO1RBOOADjqXJNCnZZRcY+HqbnGPMSLFVc31zylQ==", - "dependencies": { - "@gorhom/portal": "1.0.14", - "invariant": "^2.2.4" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-native": "*", - "react": "*", - "react-native": "*", - "react-native-gesture-handler": ">=1.10.1", - "react-native-reanimated": ">=2.2.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-native": { - "optional": true - } - } - }, - "node_modules/@gorhom/portal": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/@gorhom/portal/-/portal-1.0.14.tgz", - "integrity": "sha512-MXyL4xvCjmgaORr/rtryDNFy3kU4qUbKlwtQqqsygd0xX3mhKjOLn6mQK8wfu0RkoE0pBE0nAasRoHua+/QZ7A==", - "dependencies": { - "nanoid": "^3.3.1" - }, - "peerDependencies": { - "react": "*", - "react-native": "*" - } - }, "node_modules/@graphql-typed-document-node/core": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz", diff --git a/package.json b/package.json index 37610e6..5af9ec0 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,6 @@ "web": "expo start --web" }, "dependencies": { - "@gorhom/bottom-sheet": "^4.4.7", "@react-native-async-storage/async-storage": "1.17.11", "@react-navigation/drawer": "^6.6.3", "@react-navigation/native": "^6.1.7", diff --git a/src/components/Api/Api.tsx b/src/components/Api/Api.tsx index e7df9e3..b8a8ace 100644 --- a/src/components/Api/Api.tsx +++ b/src/components/Api/Api.tsx @@ -262,7 +262,7 @@ export async function PostStudentStatus(info: StudentStatusParams) { const config = await GetConfig(); console.log(info); return instance - .post("/api/v1/student_status/self/", info, config) + .patch("/api/v1/student_status/self/", info, config) .then((response) => { console.log("heh1"); return [true, response.data]; diff --git a/src/interfaces/Interfaces.tsx b/src/interfaces/Interfaces.tsx index 2eeb8d0..d613b7c 100644 --- a/src/interfaces/Interfaces.tsx +++ b/src/interfaces/Interfaces.tsx @@ -145,6 +145,7 @@ interface Location { } export interface StudentStatusParams { - subject: string; - location: Location; + subject?: string; + location?: Location; + active?: boolean; } diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index 89b88c8..8672b7a 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -56,7 +56,7 @@ export default function Home() { return () => clearInterval(interval); }); - // Run when screen loads + // Refresh when screen loads useEffect(() => { requestLocation(); }, []); @@ -65,8 +65,8 @@ export default function Home() { let dist = GetDistance( location.coords.latitude, location.coords.longitude, - 8.4857, // LatitudeDelta - 124.6565 // LongitudeDelta + ustpCoords.latitude, + ustpCoords.longitude ); setDist(Math.round(dist)); } From c95e3e2d7953e8e30e8b6d480a56cd2a28a15297 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Mon, 7 Aug 2023 14:55:44 +0800 Subject: [PATCH 013/109] Added start studying page --- App.tsx | 2 + src/interfaces/Interfaces.tsx | 6 +- src/routes/Home/Home.tsx | 20 ++--- src/routes/StartStudying/StartStudying.tsx | 99 ++++++++++++++++++++++ 4 files changed, 115 insertions(+), 12 deletions(-) create mode 100644 src/routes/StartStudying/StartStudying.tsx diff --git a/App.tsx b/App.tsx index 86b7055..f381c9b 100644 --- a/App.tsx +++ b/App.tsx @@ -23,6 +23,7 @@ import { StatusBar } from "expo-status-bar"; import UserInfoPage from "./src/routes/UserInfoPage/UserInfoPage"; import SubjectsPage from "./src/routes/SubjectsPage/SubjectsPage"; import Loading from "./src/routes/Loading/Loading"; +import StartStudying from "./src/routes/StartStudying/StartStudying"; const Drawer = createDrawerNavigator(); @@ -75,6 +76,7 @@ export default function App() { + diff --git a/src/interfaces/Interfaces.tsx b/src/interfaces/Interfaces.tsx index d613b7c..76c7c8c 100644 --- a/src/interfaces/Interfaces.tsx +++ b/src/interfaces/Interfaces.tsx @@ -1,3 +1,5 @@ +import * as Location from "expo-location"; + export interface IconProps { size: number; } @@ -133,7 +135,7 @@ export interface StudentData { course_shortname: string; year_level: string; yearlevel_shortname: string; - subjects: Subject[]; // To-do + subjects: string[]; // To-do username: string; } @@ -149,3 +151,5 @@ export interface StudentStatusParams { location?: Location; active?: boolean; } + +export type LocationType = Location.LocationObject; diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index 8672b7a..a213472 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -7,9 +7,15 @@ import * as Location from "expo-location"; import GetDistance from "../../components/GetDistance/GetDistance"; import Button from "../../components/Button/Button"; import { PostStudentStatus } from "../../components/Api/Api"; -import { StudentStatusParams } from "../../interfaces/Interfaces"; -type LocationType = Location.LocationObject; +import { + RootDrawerParamList, + StudentStatusParams, +} from "../../interfaces/Interfaces"; +import { LocationType } from "../../interfaces/Interfaces"; +import { useNavigation } from "@react-navigation/native"; + export default function Home() { + const navigation = useNavigation(); const [location, setLocation] = useState(null); const [dist, setDist] = useState(null); const [feedback, setFeedback] = useState( @@ -158,15 +164,7 @@ export default function Home() { + + {feedback} + + + + ); + } + return ; +} From 33ffcde6bee91fbb75007660e340f7ea9ebf0aa0 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Mon, 7 Aug 2023 15:03:53 +0800 Subject: [PATCH 014/109] Added map preview to start studying page --- src/components/Api/Api.tsx | 3 + src/routes/Home/Home.tsx | 10 +-- src/routes/StartStudying/StartStudying.tsx | 78 ++++++++++++++++------ 3 files changed, 65 insertions(+), 26 deletions(-) diff --git a/src/components/Api/Api.tsx b/src/components/Api/Api.tsx index b8a8ace..55b410d 100644 --- a/src/components/Api/Api.tsx +++ b/src/components/Api/Api.tsx @@ -30,6 +30,9 @@ const instance = axios.create({ console.log(backendURL); +// 3rd Party APIs +export const urlProvider = + "https://tile.thunderforest.com/atlas/{z}/{x}/{y}.png?apikey=0f5cb5930d7642a8a921daea650754d9"; // App APIs // Token Handling diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index a213472..73eb82a 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -6,13 +6,10 @@ import MapView, { Callout, Marker, UrlTile } from "react-native-maps"; import * as Location from "expo-location"; import GetDistance from "../../components/GetDistance/GetDistance"; import Button from "../../components/Button/Button"; -import { PostStudentStatus } from "../../components/Api/Api"; -import { - RootDrawerParamList, - StudentStatusParams, -} from "../../interfaces/Interfaces"; +import { RootDrawerParamList } from "../../interfaces/Interfaces"; import { LocationType } from "../../interfaces/Interfaces"; import { useNavigation } from "@react-navigation/native"; +import { urlProvider } from "../../components/Api/Api"; export default function Home() { const navigation = useNavigation(); @@ -21,8 +18,7 @@ export default function Home() { const [feedback, setFeedback] = useState( "To continue, please allow Stud-E permission to location services" ); - const urlProvider = - "https://tile.thunderforest.com/atlas/{z}/{x}/{y}.png?apikey=0f5cb5930d7642a8a921daea650754d9"; + const ustpCoords = { latitude: 8.4857, longitude: 124.6565, diff --git a/src/routes/StartStudying/StartStudying.tsx b/src/routes/StartStudying/StartStudying.tsx index 56b9b37..4fadf35 100644 --- a/src/routes/StartStudying/StartStudying.tsx +++ b/src/routes/StartStudying/StartStudying.tsx @@ -1,20 +1,16 @@ import * as React from "react"; -import styles from "../../styles"; +import styles, { Viewport } from "../../styles"; import { View, Text } from "react-native"; import { useState } from "react"; -import { - UserInfoParams, - Subject, - OptionType, -} from "../../interfaces/Interfaces"; +import { UserInfoParams, OptionType } from "../../interfaces/Interfaces"; import Button from "../../components/Button/Button"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { UserInfo } from "../../components/Api/Api"; import { colors } from "../../styles"; import DropDownPicker from "react-native-dropdown-picker"; import AnimatedContainerNoScroll from "../../components/AnimatedContainer/AnimatedContainerNoScroll"; -import { useSelector } from "react-redux"; -import { RootState } from "../../features/redux/Store/Store"; +import { urlProvider } from "../../components/Api/Api"; +import MapView, { UrlTile, Marker } from "react-native-maps"; export default function StartStudying({ route }: any) { const { location } = route.params; @@ -43,6 +39,57 @@ export default function StartStudying({ route }: any) { return ( + + + + + + + + + {feedback} + Start Studying @@ -80,17 +127,10 @@ export default function StartStudying({ route }: any) { /> - - - - {location.coords.longitude + "\n" + location.coords.latitude} - - - - {feedback} - + + ); From 529a7a75fd3cdb7d73a3aa316c14f4056234ee8b Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Thu, 10 Aug 2023 17:23:12 +0800 Subject: [PATCH 015/109] Improved homepage --- src/components/Api/Api.tsx | 27 ++++- src/interfaces/Interfaces.tsx | 32 +++--- src/routes/Home/Home.tsx | 119 ++++++++++++++++--- src/routes/StartStudying/StartStudying.tsx | 128 +++++++++++++-------- src/routes/SubjectsPage/SubjectsPage.tsx | 2 +- src/routes/UserInfoPage/UserInfoPage.tsx | 20 ++++ 6 files changed, 246 insertions(+), 82 deletions(-) diff --git a/src/components/Api/Api.tsx b/src/components/Api/Api.tsx index 55b410d..54fb465 100644 --- a/src/components/Api/Api.tsx +++ b/src/components/Api/Api.tsx @@ -6,7 +6,7 @@ import { OnboardingParams, PatchStudentData, RegistrationParams, - StudentStatusParams, + StudentStatus, } from "../../interfaces/Interfaces"; export let backendURL = "https://stude.keannu1.duckdns.org"; @@ -261,20 +261,35 @@ export async function OnboardingUpdateStudentInfo(info: OnboardingParams) { }); } -export async function PostStudentStatus(info: StudentStatusParams) { +export async function GetStudentStatus() { const config = await GetConfig(); - console.log(info); return instance - .patch("/api/v1/student_status/self/", info, config) + .get("/api/v1/student_status/self/", config) .then((response) => { - console.log("heh1"); return [true, response.data]; }) .catch((error) => { let error_message = ""; if (error.response) error_message = error.response.data; else error_message = "Unable to reach servers"; - console.log("heh2", error); + console.log(error_message); + return [false, error_message]; + }); +} + +export async function PatchStudentStatus(info: StudentStatus) { + const config = await GetConfig(); + console.log(info); + return instance + .patch("/api/v1/student_status/self/", info, config) + .then((response) => { + return [true, response.data]; + }) + .catch((error) => { + let error_message = ""; + if (error.response) error_message = error.response.data; + else error_message = "Unable to reach servers"; + console.log(error_message); return [false, error_message]; }); } diff --git a/src/interfaces/Interfaces.tsx b/src/interfaces/Interfaces.tsx index 76c7c8c..eb6486c 100644 --- a/src/interfaces/Interfaces.tsx +++ b/src/interfaces/Interfaces.tsx @@ -122,6 +122,23 @@ export interface PatchStudentData { avatar?: string | null; } +interface Location { + latitude: number; + longitude: number; +} + +export interface StudentStatus { + user?: string; + subject?: string; + location?: Location; + landmark?: string | null; + active?: boolean; +} + +export type StudentStatusParams = [boolean, StudentStatus]; + +export type LocationType = Location.LocationObject; + export interface StudentData { first_name: string; last_name: string; @@ -135,21 +152,8 @@ export interface StudentData { course_shortname: string; year_level: string; yearlevel_shortname: string; - subjects: string[]; // To-do + subjects: string[]; username: string; } export type UserInfoParams = [boolean, StudentData]; - -interface Location { - latitude: number; - longtitude: number; -} - -export interface StudentStatusParams { - subject?: string; - location?: Location; - active?: boolean; -} - -export type LocationType = Location.LocationObject; diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index 73eb82a..0b79bae 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -1,23 +1,34 @@ import styles, { Viewport, colors } from "../../styles"; -import { View, Text } from "react-native"; +import { View, Text, ToastAndroid } from "react-native"; import AnimatedContainer from "../../components/AnimatedContainer/AnimatedContainer"; import { useState, useEffect } from "react"; import MapView, { Callout, Marker, UrlTile } from "react-native-maps"; import * as Location from "expo-location"; import GetDistance from "../../components/GetDistance/GetDistance"; import Button from "../../components/Button/Button"; -import { RootDrawerParamList } from "../../interfaces/Interfaces"; +import { + RootDrawerParamList, + StudentStatusParams, +} from "../../interfaces/Interfaces"; import { LocationType } from "../../interfaces/Interfaces"; import { useNavigation } from "@react-navigation/native"; -import { urlProvider } from "../../components/Api/Api"; +import { + GetStudentStatus, + PatchStudentStatus, + urlProvider, +} from "../../components/Api/Api"; +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; export default function Home() { + // Switch this condition to see the main map when debugging + const map_debug = true; const navigation = useNavigation(); const [location, setLocation] = useState(null); const [dist, setDist] = useState(null); const [feedback, setFeedback] = useState( "To continue, please allow Stud-E permission to location services" ); + const queryClient = useQueryClient(); const ustpCoords = { latitude: 8.4857, @@ -28,8 +39,10 @@ export default function Home() { async function requestLocation() { const { status } = await Location.requestForegroundPermissionsAsync(); if (status !== "granted") { - setFeedback( - "Permission to access location was denied. Please allow permission" + setFeedback("Allow location permissions to continue"); + ToastAndroid.show( + "Location permission was denied. Please allow in order to use StudE", + ToastAndroid.SHORT ); return; } @@ -71,12 +84,86 @@ export default function Home() { ustpCoords.longitude ); setDist(Math.round(dist)); + // Deactivate student status if too far away + if (dist >= 2 && !map_debug) + mutation.mutate({ + active: false, + }); } + // Student Status + const [studying, setStudying] = useState(false); + const [subject, setSubject] = useState(""); + const [buttonLabel, setButtonLabel] = useState("Start studying"); + const StudentStatus = useQuery({ + queryKey: ["user_status"], + queryFn: GetStudentStatus, + onSuccess: (data: StudentStatusParams) => { + if (data[1].active !== undefined) { + setStudying(data[1].active); + } + if (data[1].subject !== undefined) { + setSubject(data[1].subject); + } + if (data[1].active == true) { + setButtonLabel("Stop Studying"); + } else if (data[1].active == false) { + setButtonLabel("Start Studying"); + } + console.log(data[1]); + }, + onError: () => { + setFeedback("Unable to query available subjects"); + }, + }); + + const mutation = useMutation({ + mutationFn: PatchStudentStatus, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ["user"] }); + queryClient.invalidateQueries({ queryKey: ["user_status"] }); + ToastAndroid.show( + "You are no longer studying " + subject, + ToastAndroid.SHORT + ); + }, + onError: () => { + ToastAndroid.show( + "Server error. Unable to update student status", + ToastAndroid.SHORT + ); + }, + }); + function CustomCallout() { + if (location && location.coords) { + if (studying) { + return ( + + + You are here {"\n"} + X: {Math.round(location.coords.longitude) + "\n"} + Z: {Math.round(location.coords.latitude) + "\n"} + Studying: {subject} + + + ); + } else { + return ( + + + You are here {"\n"} + X: {Math.round(location.coords.longitude) + "\n"} + Z: {Math.round(location.coords.latitude)} + + + ); + } + } + return <>; + } function CustomMap() { if (dist && location) { - if (dist >= 2) { - // Just switch this condition for map debugging + if (dist <= 2 || map_debug) { return ( - - - You are here {"\n"} - X: {Math.round(location.coords.longitude) + "\n"} - Z: {Math.round(location.coords.latitude)} - - + ); diff --git a/src/routes/StartStudying/StartStudying.tsx b/src/routes/StartStudying/StartStudying.tsx index 4fadf35..562762d 100644 --- a/src/routes/StartStudying/StartStudying.tsx +++ b/src/routes/StartStudying/StartStudying.tsx @@ -1,21 +1,26 @@ import * as React from "react"; import styles, { Viewport } from "../../styles"; -import { View, Text } from "react-native"; +import { View, Text, ToastAndroid } from "react-native"; import { useState } from "react"; -import { UserInfoParams, OptionType } from "../../interfaces/Interfaces"; +import { + UserInfoParams, + OptionType, + RootDrawerParamList, +} from "../../interfaces/Interfaces"; import Button from "../../components/Button/Button"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; -import { UserInfo } from "../../components/Api/Api"; +import { PatchStudentStatus, UserInfo } from "../../components/Api/Api"; import { colors } from "../../styles"; import DropDownPicker from "react-native-dropdown-picker"; import AnimatedContainerNoScroll from "../../components/AnimatedContainer/AnimatedContainerNoScroll"; import { urlProvider } from "../../components/Api/Api"; import MapView, { UrlTile, Marker } from "react-native-maps"; +import { useNavigation } from "@react-navigation/native"; export default function StartStudying({ route }: any) { const { location } = route.params; const queryClient = useQueryClient(); - const [feedback, setFeedback] = useState(""); + const navigation = useNavigation(); // Subject choices const [selected_subject, setSelectedSubject] = useState(""); @@ -32,9 +37,32 @@ export default function StartStudying({ route }: any) { setSubjects(subjects); }, onError: () => { - setFeedback("Unable to query available subjects"); + ToastAndroid.show( + "Server error: Unable to query available subjects", + ToastAndroid.SHORT + ); }, }); + + const mutation = useMutation({ + mutationFn: PatchStudentStatus, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ["user"] }); + queryClient.invalidateQueries({ queryKey: ["user_status"] }); + ToastAndroid.show( + "You are now studying " + selected_subject, + ToastAndroid.SHORT + ); + navigation.navigate("Home"); + }, + onError: () => { + ToastAndroid.show( + "A server error has occured. Please try again", + ToastAndroid.SHORT + ); + }, + }); + if (location && location.coords) { return ( @@ -87,50 +115,60 @@ export default function StartStudying({ route }: any) { /> - - {feedback} - - - - Start Studying - - - { - setSubjectsOpen(open); - }} - setValue={setSelectedSubject} - placeholderStyle={{ - ...styles.text_white_tiny_bold, - ...{ textAlign: "left" }, - }} - placeholder="Select subject" - multipleText="Select subject" - style={styles.input} - textStyle={{ - ...styles.text_white_tiny_bold, - ...{ textAlign: "left" }, - }} - modalContentContainerStyle={{ - backgroundColor: colors.primary_2, - borderWidth: 0, - zIndex: 1000, - }} - autoScroll - dropDownDirection="BOTTOM" - listMode="MODAL" - /> - + { + setSubjectsOpen(open); + }} + setValue={setSelectedSubject} + placeholderStyle={{ + ...styles.text_white_tiny_bold, + ...{ textAlign: "left" }, + }} + placeholder="Select subject" + multipleText="Select subject" + style={styles.input} + textStyle={{ + ...styles.text_white_tiny_bold, + ...{ textAlign: "left" }, + }} + modalContentContainerStyle={{ + backgroundColor: colors.primary_2, + borderWidth: 0, + zIndex: 1000, + }} + autoScroll + dropDownDirection="BOTTOM" + listMode="MODAL" + /> - + ); diff --git a/src/routes/SubjectsPage/SubjectsPage.tsx b/src/routes/SubjectsPage/SubjectsPage.tsx index b0429e0..2db5e3b 100644 --- a/src/routes/SubjectsPage/SubjectsPage.tsx +++ b/src/routes/SubjectsPage/SubjectsPage.tsx @@ -52,7 +52,7 @@ export default function SubjectsPage() { course_shortname: "", avatar: "", student_id_number: "", - subjects: [] as Subjects, + subjects: [] as string[], }); const StudentInfo = useQuery({ queryKey: ["user"], diff --git a/src/routes/UserInfoPage/UserInfoPage.tsx b/src/routes/UserInfoPage/UserInfoPage.tsx index d713a2f..63d1b39 100644 --- a/src/routes/UserInfoPage/UserInfoPage.tsx +++ b/src/routes/UserInfoPage/UserInfoPage.tsx @@ -28,6 +28,7 @@ import { GetSemesters, GetSubjects, GetYearLevels, + PatchStudentStatus, PatchUserInfo, UserInfo, } from "../../components/Api/Api"; @@ -47,6 +48,20 @@ export default function UserInfoPage() { const dispatch = useDispatch(); const queryClient = useQueryClient(); const [feedback, setFeedback] = useState(""); + + // Student Status + const studentstatus_mutation = useMutation({ + mutationFn: PatchStudentStatus, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ["user"] }); + queryClient.invalidateQueries({ queryKey: ["user_status"] }); + setFeedback("Changes applied successfully"); + }, + onError: () => { + setFeedback("An error has occured\nChanges have not been saved"); + }, + }); + // User Info const [user, setUser] = useState({ first_name: "", @@ -86,11 +101,16 @@ export default function UserInfoPage() { setFeedback("Unable to query user info"); }, }); + const mutation = useMutation({ mutationFn: PatchUserInfo, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["user"] }); queryClient.invalidateQueries({ queryKey: ["subjects"] }); + // Reset student status when changing user info to prevent bugs + studentstatus_mutation.mutate({ + active: false, + }); setFeedback("Changes applied successfully"); dispatch(setUserinState(user)); }, From ff114b496c42b5b5ced4c213672b4c0bf8f5c226 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Mon, 14 Aug 2023 21:13:46 +0800 Subject: [PATCH 016/109] Move to modals for user feedback --- App.tsx | 48 ++++++++------- package-lock.json | 10 +++ package.json | 1 + src/routes/Home/Home.tsx | 33 ++++++---- src/routes/Login/Login.tsx | 24 ++++++-- src/routes/Onboarding/Onboarding.tsx | 22 +++++-- src/routes/Register/Register.tsx | 24 +++++--- src/routes/Revalidation/Revalidation.tsx | 20 ++++++ src/routes/StartStudying/StartStudying.tsx | 32 ++++++---- src/routes/UserInfoPage/UserInfoPage.tsx | 71 +++++++++++++++------- 10 files changed, 203 insertions(+), 82 deletions(-) diff --git a/App.tsx b/App.tsx index f381c9b..92d2b63 100644 --- a/App.tsx +++ b/App.tsx @@ -24,6 +24,8 @@ import UserInfoPage from "./src/routes/UserInfoPage/UserInfoPage"; import SubjectsPage from "./src/routes/SubjectsPage/SubjectsPage"; import Loading from "./src/routes/Loading/Loading"; import StartStudying from "./src/routes/StartStudying/StartStudying"; +import { ToastProvider } from "react-native-toast-notifications"; +import AppIcon from "./src/icons/AppIcon/AppIcon"; const Drawer = createDrawerNavigator(); @@ -58,28 +60,30 @@ export default function App() { } }, [initialRoute]); return ( - - - + }> + + + - }> - - - - - - - - - - - - - - + }> + + + + + + + + + + + + + + + ); } diff --git a/package-lock.json b/package-lock.json index 14006b9..e918be3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,6 +36,7 @@ "react-native-screens": "~3.20.0", "react-native-select-dropdown": "^3.3.4", "react-native-svg": "13.4.0", + "react-native-toast-notifications": "^3.3.1", "react-query": "^3.39.3", "react-redux": "^8.1.1", "redux": "^4.2.1" @@ -12453,6 +12454,15 @@ "react-native": "*" } }, + "node_modules/react-native-toast-notifications": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/react-native-toast-notifications/-/react-native-toast-notifications-3.3.1.tgz", + "integrity": "sha512-yc1Q2nOdIYvAf0GAIlmg8q42hiwpEHnLxkxJ6P+tN6jpcKZ1qzMXlgnmNdyF9cm9VOyHQexEP8952IKNAv1Olw==", + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, "node_modules/react-native/node_modules/promise": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", diff --git a/package.json b/package.json index 5af9ec0..df97e93 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "react-native-screens": "~3.20.0", "react-native-select-dropdown": "^3.3.4", "react-native-svg": "13.4.0", + "react-native-toast-notifications": "^3.3.1", "react-query": "^3.39.3", "react-redux": "^8.1.1", "redux": "^4.2.1" diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index 0b79bae..aad9597 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -18,6 +18,7 @@ import { urlProvider, } from "../../components/Api/Api"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; +import { useToast } from "react-native-toast-notifications"; export default function Home() { // Switch this condition to see the main map when debugging @@ -29,6 +30,7 @@ export default function Home() { "To continue, please allow Stud-E permission to location services" ); const queryClient = useQueryClient(); + const toast = useToast(); const ustpCoords = { latitude: 8.4857, @@ -40,9 +42,14 @@ export default function Home() { const { status } = await Location.requestForegroundPermissionsAsync(); if (status !== "granted") { setFeedback("Allow location permissions to continue"); - ToastAndroid.show( + toast.show( "Location permission was denied. Please allow in order to use StudE", - ToastAndroid.SHORT + { + type: "warning", + placement: "bottom", + duration: 4000, + animationType: "slide-in", + } ); return; } @@ -122,16 +129,20 @@ export default function Home() { onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["user"] }); queryClient.invalidateQueries({ queryKey: ["user_status"] }); - ToastAndroid.show( - "You are no longer studying " + subject, - ToastAndroid.SHORT - ); + toast.show("You are no longer studying " + subject, { + type: "success", + placement: "bottom", + duration: 4000, + animationType: "slide-in", + }); }, onError: () => { - ToastAndroid.show( - "Server error. Unable to update student status", - ToastAndroid.SHORT - ); + toast.show("Server error. Unable to update student status", { + type: "warning", + placement: "bottom", + duration: 4000, + animationType: "slide-in", + }); }, }); function CustomCallout() { @@ -139,7 +150,7 @@ export default function Home() { if (studying) { return ( - + You are here {"\n"} X: {Math.round(location.coords.longitude) + "\n"} Z: {Math.round(location.coords.latitude) + "\n"} diff --git a/src/routes/Login/Login.tsx b/src/routes/Login/Login.tsx index 8789fad..5050439 100644 --- a/src/routes/Login/Login.tsx +++ b/src/routes/Login/Login.tsx @@ -23,6 +23,7 @@ import { setOnboarding, unsetOnboarding, } from "../../features/redux/slices/StatusSlice/StatusSlice"; +import { useToast } from "react-native-toast-notifications"; export default function Login() { const navigation = useNavigation(); @@ -31,7 +32,7 @@ export default function Login() { username: "", password: "", }); - const [error, setError] = useState(""); + const toast = useToast(); return ( @@ -66,8 +67,6 @@ export default function Login() { setCreds({ ...creds, password: e.nativeEvent.text }); }} /> - - {error} - {feedback} From 2ca1dd13ca7f7d1892192aa265e88305de0fb267 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Mon, 14 Aug 2023 21:57:52 +0800 Subject: [PATCH 017/109] Finalize changes to using modals for user feedback --- App.tsx | 7 +++- src/components/Api/Api.tsx | 2 +- src/routes/Activation/Activation.tsx | 28 ++++++++----- src/routes/Home/Home.tsx | 16 +++---- src/routes/Login/Login.tsx | 13 +++--- src/routes/Onboarding/Onboarding.tsx | 32 ++++++++++++-- src/routes/Register/Register.tsx | 4 +- src/routes/Revalidation/Revalidation.tsx | 12 +++--- src/routes/StartStudying/StartStudying.tsx | 18 ++++---- src/routes/SubjectsPage/SubjectsPage.tsx | 49 ++++++++++------------ src/routes/UserInfoPage/UserInfoPage.tsx | 28 ++++++------- 11 files changed, 119 insertions(+), 90 deletions(-) diff --git a/App.tsx b/App.tsx index 92d2b63..7130bbe 100644 --- a/App.tsx +++ b/App.tsx @@ -1,5 +1,5 @@ import "react-native-gesture-handler"; -import { Text } from "react-native"; +import styles from "./src/styles"; import { NavigationContainer } from "@react-navigation/native"; import { createDrawerNavigator } from "@react-navigation/drawer"; import { Provider } from "react-redux"; @@ -60,7 +60,10 @@ export default function App() { } }, [initialRoute]); return ( - }> + } + textStyle={{ ...styles.text_white_tiny_bold }} + > diff --git a/src/components/Api/Api.tsx b/src/components/Api/Api.tsx index 54fb465..4564ee4 100644 --- a/src/components/Api/Api.tsx +++ b/src/components/Api/Api.tsx @@ -28,7 +28,7 @@ const instance = axios.create({ timeout: 1000, }); -console.log(backendURL); +console.log("Using backend API:", backendURL); // 3rd Party APIs export const urlProvider = diff --git a/src/routes/Activation/Activation.tsx b/src/routes/Activation/Activation.tsx index 10aab6a..c2846c2 100644 --- a/src/routes/Activation/Activation.tsx +++ b/src/routes/Activation/Activation.tsx @@ -6,6 +6,7 @@ import { useNavigation, useRoute } from "@react-navigation/native"; import { useEffect, useState } from "react"; import { UserActivate } from "../../components/Api/Api"; import { RootDrawerParamList } from "../../interfaces/Interfaces"; +import { useToast } from "react-native-toast-notifications"; interface ActivationRouteParams { uid?: string; @@ -16,9 +17,7 @@ export default function Activation() { const route = useRoute(); const { uid, token } = (route.params as ActivationRouteParams) || ""; const navigation = useNavigation(); - const [state, setState] = useState( - "Activating with UID " + uid + " and Token " + token - ); + const toast = useToast(); const [loading, setLoading] = useState(true); useEffect(() => { @@ -28,16 +27,22 @@ export default function Activation() { token: String(token), }); if (result) { - setTimeout(() => { - setState("Activation successful!"); - }, 1000); + toast.show("Activation successful", { + type: "success", + placement: "top", + duration: 4000, + animationType: "slide-in", + }); setTimeout(() => { navigation.navigate("Login"); }, 2000); } else { - setTimeout(() => { - setState("Activation unsuccessful\nPlease contact support"); - }, 1000); + toast.show("Activation unsuccessful. Please contact support", { + type: "warning", + placement: "top", + duration: 4000, + animationType: "slide-in", + }); } setLoading(false); } @@ -63,8 +68,9 @@ export default function Activation() { size={96} color={colors.secondary_1} /> - {state} - {uid + "\n" + token} + + {"Activating with UID: " + uid + "\nToken: " + token} + ); diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index aad9597..759eef4 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -1,5 +1,5 @@ import styles, { Viewport, colors } from "../../styles"; -import { View, Text, ToastAndroid } from "react-native"; +import { View, Text } from "react-native"; import AnimatedContainer from "../../components/AnimatedContainer/AnimatedContainer"; import { useState, useEffect } from "react"; import MapView, { Callout, Marker, UrlTile } from "react-native-maps"; @@ -46,8 +46,8 @@ export default function Home() { "Location permission was denied. Please allow in order to use StudE", { type: "warning", - placement: "bottom", - duration: 4000, + placement: "top", + duration: 2000, animationType: "slide-in", } ); @@ -129,18 +129,18 @@ export default function Home() { onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["user"] }); queryClient.invalidateQueries({ queryKey: ["user_status"] }); - toast.show("You are no longer studying " + subject, { + toast.show("You are no longer studying \n" + subject, { type: "success", - placement: "bottom", - duration: 4000, + placement: "top", + duration: 2000, animationType: "slide-in", }); }, onError: () => { toast.show("Server error. Unable to update student status", { type: "warning", - placement: "bottom", - duration: 4000, + placement: "top", + duration: 2000, animationType: "slide-in", }); }, diff --git a/src/routes/Login/Login.tsx b/src/routes/Login/Login.tsx index 5050439..aad5f4c 100644 --- a/src/routes/Login/Login.tsx +++ b/src/routes/Login/Login.tsx @@ -8,7 +8,6 @@ import { TextInputChangeEventData, } from "react-native"; import { useDispatch } from "react-redux"; -import { colors } from "../../styles"; import { useState } from "react"; import LoginIcon from "../../icons/LoginIcon/LoginIcon"; import Button from "../../components/Button/Button"; @@ -89,16 +88,16 @@ export default function Login() { navigation.navigate("Onboarding"); toast.show("Successfully logged in", { type: "success", - placement: "bottom", - duration: 4000, + placement: "top", + duration: 2000, animationType: "slide-in", }); } else { dispatch(unsetOnboarding()); toast.show("Successfully logged in", { type: "success", - placement: "bottom", - duration: 4000, + placement: "top", + duration: 2000, animationType: "slide-in", }); navigation.navigate("Home"); @@ -108,8 +107,8 @@ export default function Login() { console.log(ParseLoginError(JSON.stringify(result[1]))); toast.show(JSON.stringify(result[1]), { type: "warning", - placement: "bottom", - duration: 4000, + placement: "top", + duration: 2000, animationType: "slide-in", }); } diff --git a/src/routes/Onboarding/Onboarding.tsx b/src/routes/Onboarding/Onboarding.tsx index 9aef47e..0d52063 100644 --- a/src/routes/Onboarding/Onboarding.tsx +++ b/src/routes/Onboarding/Onboarding.tsx @@ -48,6 +48,14 @@ export default function Onboarding() { })); setSemesters(semesters); }, + onError: () => { + toast.show("Server error: Unable to query available semesters", { + type: "warning", + placement: "top", + duration: 2000, + animationType: "slide-in", + }); + }, }); // Year Level const [selected_yearlevel, setSelectedYearLevel] = useState(""); @@ -66,6 +74,14 @@ export default function Onboarding() { })); setYearLevels(year_levels); }, + onError: () => { + toast.show("Server error: Unable to query available year levels", { + type: "warning", + placement: "top", + duration: 2000, + animationType: "slide-in", + }); + }, }); // Course const [selected_course, setSelectedCourse] = useState(""); @@ -87,6 +103,14 @@ export default function Onboarding() { })); setCourses(courses); }, + onError: () => { + toast.show("Server error: Unable to query available courses", { + type: "warning", + placement: "top", + duration: 2000, + animationType: "slide-in", + }); + }, }); if (yearlevel_query.error || semester_query.error || course_query.error) { return ( @@ -230,8 +254,8 @@ export default function Onboarding() { dispatch(setUser(result[1])); toast.show("Changes applied successfully", { type: "success", - placement: "bottom", - duration: 6000, + placement: "top", + duration: 2000, animationType: "slide-in", }); navigation.navigate("Home"); @@ -241,8 +265,8 @@ export default function Onboarding() { "An error has occured\nChanges have not been saved", { type: "warning", - placement: "bottom", - duration: 6000, + placement: "top", + duration: 2000, animationType: "slide-in", } ); diff --git a/src/routes/Register/Register.tsx b/src/routes/Register/Register.tsx index f9d50cf..37f3a0f 100644 --- a/src/routes/Register/Register.tsx +++ b/src/routes/Register/Register.tsx @@ -146,7 +146,7 @@ export default function Register() { "Success! An email has been sent to activate your account", { type: "success", - placement: "bottom", + placement: "top", duration: 6000, animationType: "slide-in", } @@ -157,7 +157,7 @@ export default function Register() { } else { toast.show(JSON.stringify(result[1]), { type: "warning", - placement: "bottom", + placement: "top", duration: 6000, animationType: "slide-in", }); diff --git a/src/routes/Revalidation/Revalidation.tsx b/src/routes/Revalidation/Revalidation.tsx index 9d8bd93..c633f99 100644 --- a/src/routes/Revalidation/Revalidation.tsx +++ b/src/routes/Revalidation/Revalidation.tsx @@ -37,8 +37,8 @@ export default function Revalidation() { dispatch(setOnboarding()); toast.show("Previous session restored", { type: "success", - placement: "bottom", - duration: 4000, + placement: "top", + duration: 2000, animationType: "slide-in", }); await setTimeout(() => { @@ -48,8 +48,8 @@ export default function Revalidation() { dispatch(unsetOnboarding()); toast.show("Previous session restored", { type: "success", - placement: "bottom", - duration: 4000, + placement: "top", + duration: 2000, animationType: "slide-in", }); await setTimeout(() => { @@ -60,8 +60,8 @@ export default function Revalidation() { await setState("Session expired"); toast.show("Session expired. Please login again", { type: "warning", - placement: "bottom", - duration: 4000, + placement: "top", + duration: 2000, animationType: "slide-in", }); await setTimeout(() => { diff --git a/src/routes/StartStudying/StartStudying.tsx b/src/routes/StartStudying/StartStudying.tsx index 265b23e..fb46b29 100644 --- a/src/routes/StartStudying/StartStudying.tsx +++ b/src/routes/StartStudying/StartStudying.tsx @@ -40,9 +40,9 @@ export default function StartStudying({ route }: any) { }, onError: () => { toast.show("Server error: Unable to query available subjects", { - type: "error", - placement: "bottom", - duration: 4000, + type: "warning", + placement: "top", + duration: 2000, animationType: "slide-in", }); }, @@ -53,19 +53,19 @@ export default function StartStudying({ route }: any) { onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["user"] }); queryClient.invalidateQueries({ queryKey: ["user_status"] }); - toast.show("You are now studying " + selected_subject, { + toast.show("You are now studying \n" + selected_subject, { type: "success", - placement: "bottom", - duration: 4000, + placement: "top", + duration: 2000, animationType: "slide-in", }); navigation.navigate("Home"); }, onError: () => { toast.show("A server error has occured. Please try again", { - type: "error", - placement: "bottom", - duration: 4000, + type: "warning", + placement: "top", + duration: 2000, animationType: "slide-in", }); }, diff --git a/src/routes/SubjectsPage/SubjectsPage.tsx b/src/routes/SubjectsPage/SubjectsPage.tsx index 2db5e3b..68b5bd5 100644 --- a/src/routes/SubjectsPage/SubjectsPage.tsx +++ b/src/routes/SubjectsPage/SubjectsPage.tsx @@ -1,45 +1,28 @@ import * as React from "react"; import styles from "../../styles"; +import { View, Text } from "react-native"; +import { useState } from "react"; import { - View, - Text, - TextInput, - NativeSyntheticEvent, - TextInputChangeEventData, -} from "react-native"; -import { useEffect, useState } from "react"; -import { - SemesterParams, UserInfoParams, - Semester, SubjectParams, Subject, - YearLevel, - Course, OptionType, - Subjects, } from "../../interfaces/Interfaces"; import Button from "../../components/Button/Button"; import { Image } from "react-native"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; -import { - GetCourses, - GetSemesters, - GetSubjects, - GetYearLevels, - PatchUserInfo, - UserInfo, -} from "../../components/Api/Api"; +import { GetSubjects, PatchUserInfo, UserInfo } from "../../components/Api/Api"; import { colors } from "../../styles"; import DropDownPicker from "react-native-dropdown-picker"; import AnimatedContainerNoScroll from "../../components/AnimatedContainer/AnimatedContainerNoScroll"; import { useSelector } from "react-redux"; import { RootState } from "../../features/redux/Store/Store"; +import { useToast } from "react-native-toast-notifications"; export default function SubjectsPage() { const logged_in_user = useSelector((state: RootState) => state.user.user); const queryClient = useQueryClient(); - const [feedback, setFeedback] = useState(""); + const toast = useToast(); // User Info const [user, setUser] = useState({ first_name: "", @@ -72,7 +55,12 @@ export default function SubjectsPage() { setSelectedSubjects(data[1].subjects); }, onError: () => { - setFeedback("Unable to query user info"); + toast.show("Server Error: Unable to query user info", { + type: "warning", + placement: "top", + duration: 2000, + animationType: "slide-in", + }); }, }); const mutation = useMutation({ @@ -81,7 +69,12 @@ export default function SubjectsPage() { queryClient.invalidateQueries({ queryKey: ["user"] }); queryClient.invalidateQueries({ queryKey: ["subjects"] }); setSelectedSubjects([]); - setFeedback("Changes applied successfully"); + toast.show("Changes applied successfully", { + type: "success", + placement: "top", + duration: 2000, + animationType: "slide-in", + }); }, }); @@ -106,7 +99,12 @@ export default function SubjectsPage() { } }, onError: () => { - setFeedback("Unable to query subject info"); + toast.show("Server Error: Unable to query subject info", { + type: "warning", + placement: "top", + duration: 2000, + animationType: "slide-in", + }); }, }); @@ -189,7 +187,6 @@ export default function SubjectsPage() { Save Changes - {feedback} diff --git a/src/routes/UserInfoPage/UserInfoPage.tsx b/src/routes/UserInfoPage/UserInfoPage.tsx index 3be501b..6292c11 100644 --- a/src/routes/UserInfoPage/UserInfoPage.tsx +++ b/src/routes/UserInfoPage/UserInfoPage.tsx @@ -58,16 +58,16 @@ export default function UserInfoPage() { queryClient.invalidateQueries({ queryKey: ["user_status"] }); toast.show("Changes applied successfully", { type: "success", - placement: "bottom", - duration: 4000, + placement: "top", + duration: 2000, animationType: "slide-in", }); }, onError: () => { toast.show("An error has occured\nChanges have not been saved", { type: "warning", - placement: "bottom", - duration: 4000, + placement: "top", + duration: 2000, animationType: "slide-in", }); }, @@ -112,7 +112,7 @@ export default function UserInfoPage() { toast.show("Server Error: Unable to query user info", { type: "warning", placement: "bottom", - duration: 4000, + duration: 2000, animationType: "slide-in", }); }, @@ -130,7 +130,7 @@ export default function UserInfoPage() { toast.show("Changes applied successfully", { type: "success", placement: "bottom", - duration: 4000, + duration: 2000, animationType: "slide-in", }); dispatch(setUserinState(user)); @@ -139,7 +139,7 @@ export default function UserInfoPage() { toast.show("An error has occured\nChanges have not been saved", { type: "warning", placement: "bottom", - duration: 4000, + duration: 2000, animationType: "slide-in", }); }, @@ -164,8 +164,8 @@ export default function UserInfoPage() { onError: () => { toast.show("Server Error: Unable to query semester info", { type: "warning", - placement: "bottom", - duration: 4000, + placement: "top", + duration: 2000, animationType: "slide-in", }); }, @@ -188,8 +188,8 @@ export default function UserInfoPage() { onError: () => { toast.show("Server Error: Unable to query year level info", { type: "warning", - placement: "bottom", - duration: 4000, + placement: "top", + duration: 2000, animationType: "slide-in", }); }, @@ -212,8 +212,8 @@ export default function UserInfoPage() { onError: () => { toast.show("Server Error: Unable to query course info", { type: "warning", - placement: "bottom", - duration: 4000, + placement: "top", + duration: 2000, animationType: "slide-in", }); }, @@ -426,7 +426,7 @@ export default function UserInfoPage() { Irregular From 040ffb622c7a6616f6e8653060b9c5ae6311a1ec Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Tue, 15 Aug 2023 14:53:58 +0800 Subject: [PATCH 023/109] Moved callouts to a separate component --- .../CustomMapCallout/CustomMapCallout.tsx | 41 +++++++++++++++++++ src/routes/Home/Home.tsx | 35 +++------------- 2 files changed, 47 insertions(+), 29 deletions(-) create mode 100644 src/components/CustomMapCallout/CustomMapCallout.tsx diff --git a/src/components/CustomMapCallout/CustomMapCallout.tsx b/src/components/CustomMapCallout/CustomMapCallout.tsx new file mode 100644 index 0000000..26cea15 --- /dev/null +++ b/src/components/CustomMapCallout/CustomMapCallout.tsx @@ -0,0 +1,41 @@ +import { Callout } from "react-native-maps"; +import { LocationType } from "../../interfaces/Interfaces"; +import styles from "../../styles"; +import { Text } from "react-native"; + +// Map popup for user's location + +type props = { + location: LocationType; + studying: boolean; + subject?: string; +}; + +export default function CustomMapCallout(props: props) { + let { location, studying, subject } = props; + if (location && location.coords) { + if (studying) { + return ( + + + You are here {"\n"} + X: {Math.round(location.coords.longitude) + "\n"} + Z: {Math.round(location.coords.latitude) + "\n"} + Studying: {subject} + + + ); + } else { + return ( + + + You are here {"\n"} + X: {Math.round(location.coords.longitude) + "\n"} + Z: {Math.round(location.coords.latitude)} + + + ); + } + } + return <>; +} diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index 8328f3a..2b910e2 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -22,6 +22,7 @@ import { } from "../../components/Api/Api"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { useToast } from "react-native-toast-notifications"; +import CustomMapCallout from "../../components/CustomMapCallout/CustomMapCallout"; export default function Home() { // Switch this condition to see the main map when debugging @@ -188,34 +189,6 @@ export default function Home() { }, }); - // Map popup for user's location - function CustomCallout() { - if (location && location.coords) { - if (studying) { - return ( - - - You are here {"\n"} - X: {Math.round(location.coords.longitude) + "\n"} - Z: {Math.round(location.coords.latitude) + "\n"} - Studying: {subject} - - - ); - } else { - return ( - - - You are here {"\n"} - X: {Math.round(location.coords.longitude) + "\n"} - Z: {Math.round(location.coords.latitude)} - - - ); - } - } - return <>; - } function CustomMap() { if (dist && location) { if (dist <= 2 || map_debug) { @@ -289,7 +262,11 @@ export default function Home() { }} pinColor={colors.primary_1} > - + + , + { + type: "normal", + placement: "top", + duration: 2000, + animationType: "slide-in", + style: { + backgroundColor: colors.secondary_2, + borderWidth: 1, + borderColor: colors.primary_1, + }, + } + ); + }} + /> + ); + })} + Date: Fri, 8 Sep 2023 21:41:46 +0800 Subject: [PATCH 027/109] Changed to circle rendering for student status --- src/routes/Home/Home.tsx | 183 ++++++++++++++++++++++++--------------- 1 file changed, 115 insertions(+), 68 deletions(-) diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index 951045e..e1fc2d8 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -176,6 +176,7 @@ export default function Home() { }, }); + // Can probably just get the max distance from the array and use it as radius const [student_statuses, setStudentStatuses] = useState([]); // Student Status List const StudentStatusList = useQuery({ @@ -190,6 +191,7 @@ export default function Home() { }, onSuccess: (data: StudentStatusListReturnType) => { if (data[1]) { + // Circle generation for students in a study group // We first flatten the data to remove nested entries let flattened_data = data[1].map((item) => ({ active: item.active, @@ -200,30 +202,77 @@ export default function Home() { study_group: "", subject: item.subject, user: item.user, + weight: 1, })); + // Dummy data flattened_data.push({ active: true, distance: 50, landmark: "", - latitude: 9.498298904115586, - longitude: 125.59552381187677, + latitude: 8.498837, + longitude: 124.595422, study_group: "", subject: "Introduction to Computing", - user: "Keannu", + user: "Dummy", + weight: 1, }); // We get each unique subject let unique_subjects = [ ...new Set(flattened_data.map((item) => item.subject)), ]; - console.log("Unique Subjects:", unique_subjects); let result: any[] = []; // Then append all entries belonging to that subject to its own array - unique_subjects.forEach((subject) => { + unique_subjects.forEach((subject, index: number) => { + index++; let filteredData = flattened_data.filter( (item) => item.subject === subject && item.study_group === "" ); - // We then concatenate this into the final array - result = result.concat([filteredData]); + /*console.log( + "Subject #", + index, + "-", + filteredData[0].subject, + filteredData + );*/ + // We get the circle radius based on the furthest point + let circle_radius = Math.max( + ...filteredData.map((item) => item.distance) + ); + console.log( + "Radius of circle:", + Math.max(...filteredData.map((item) => item.distance)) + ); + // We get the circle's center by averaging all the points + // Calculate the average latitude and longitude + const totalLat = filteredData.reduce( + (sum, point) => sum + point.latitude, + 0 + ); + const totalLng = filteredData.reduce( + (sum, point) => sum + point.longitude, + 0 + ); + + const avgLat = totalLat / filteredData.length; + const avgLng = totalLng / filteredData.length; + + console.log("Center Latitude:", avgLat); + console.log("Center Longitude:", avgLng); + // We now build the object + const subjectUserMap: any = {}; + filteredData.forEach((item) => { + 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); @@ -258,7 +307,6 @@ export default function Home() { ], }, ]} - mapType="none" scrollEnabled={true} zoomEnabled={true} toolbarEnabled={false} @@ -275,73 +323,72 @@ export default function Home() { loadingBackgroundColor={colors.secondary_2} > {student_statuses.map((student_status: any, index: number) => { - console.log("TEST INDEX", index, student_status); + const randomColorWithOpacity = `rgba(${Math.floor( + Math.random() * 256 + )}, ${Math.floor(Math.random() * 256)}, ${Math.floor( + Math.random() * 256 + )}, 0.7)`; + return ( - { - const users = student_statuses.map((item: any) => ({ - user: item.user, - })); - toast.hideAll(); - toast.show( - - - Subject: {student_status[0].subject} - - - Students Studying: {student_status.length} - - - , - { - type: "normal", - placement: "top", - duration: 2000, - animationType: "slide-in", - style: { - backgroundColor: colors.secondary_2, - borderWidth: 1, - borderColor: colors.primary_1, - }, - } - ); - }} - /> + + Students Studying: {student_status.users.length} + + + , + { + type: "normal", + placement: "top", + duration: 2000, + animationType: "slide-in", + style: { + backgroundColor: colors.secondary_2, + borderWidth: 1, + borderColor: colors.primary_1, + }, + } + ); + }} + /> + + ); })} - - Date: Sat, 9 Sep 2023 20:45:29 +0800 Subject: [PATCH 028/109] Added Haversine Formula calculation to get the radius of circles for study groups required for rendering --- .../CustomMapCallout/CustomMapCallout.tsx | 4 +- .../ParseStudyGroupList.tsx | 125 ++++++++++ src/interfaces/Interfaces.tsx | 29 ++- src/routes/Home/Home.tsx | 226 ++++++------------ 4 files changed, 225 insertions(+), 159 deletions(-) create mode 100644 src/components/ParseStudyGroupList/ParseStudyGroupList.tsx diff --git a/src/components/CustomMapCallout/CustomMapCallout.tsx b/src/components/CustomMapCallout/CustomMapCallout.tsx index 26cea15..23661e3 100644 --- a/src/components/CustomMapCallout/CustomMapCallout.tsx +++ b/src/components/CustomMapCallout/CustomMapCallout.tsx @@ -1,12 +1,12 @@ import { Callout } from "react-native-maps"; -import { LocationType } from "../../interfaces/Interfaces"; +import { RawLocationType } from "../../interfaces/Interfaces"; import styles from "../../styles"; import { Text } from "react-native"; // Map popup for user's location type props = { - location: LocationType; + location: RawLocationType; studying: boolean; subject?: string; }; diff --git a/src/components/ParseStudyGroupList/ParseStudyGroupList.tsx b/src/components/ParseStudyGroupList/ParseStudyGroupList.tsx new file mode 100644 index 0000000..492b649 --- /dev/null +++ b/src/components/ParseStudyGroupList/ParseStudyGroupList.tsx @@ -0,0 +1,125 @@ +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) { + let result: any[] = []; + // Circle generation for students in a study group + // We first flatten the data to remove nested entries + console.log("Initial Data:", data); + let flattened_data = data + .filter((item: StudentStatusFilterType) => item.study_group !== "") + .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("Filtered Data:", flattened_data); + + // We get each unique subject + let unique_subjects = [ + ...new Set( + flattened_data.map((item: StudentStatusFilterType) => item.subject) + ), + ]; + + // Then append all entries belonging to that subject to its own array + unique_subjects.forEach((subject, index: number) => { + index++; + let filteredData = flattened_data.filter( + (item: StudentStatusFilterTypeFlattened) => item.subject === subject + ); + console.log("Subject #", index, "-", filteredData[0].subject, filteredData); + // We get the circle's center by averaging all the points + // Calculate the average latitude and longitude + const totalLat = filteredData.reduce( + (sum: Double, point: LocationType) => sum + point.latitude, + 0 + ); + const totalLng = filteredData.reduce( + (sum: Double, point: LocationType) => sum + point.longitude, + 0 + ); + + const avgLat = totalLat / filteredData.length; + const avgLng = totalLng / filteredData.length; + + console.log("Center Latitude:", avgLat); + console.log("Center Longitude:", avgLng); + + // We now calculate the radius of the circle using the Haversine Distance Formula + + function haversineDistance( + lat1: number, + lon1: number, + lat2: number, + lon2: number + ) { + function toRad(x: number) { + return (x * Math.PI) / 180; + } + + var R = 6371; // km + var x1 = lat2 - lat1; + var dLat = toRad(x1); + var x2 = lon2 - lon1; + var dLon = toRad(x2); + var a = + Math.sin(dLat / 2) * Math.sin(dLat / 2) + + Math.cos(toRad(lat1)) * + Math.cos(toRad(lat2)) * + Math.sin(dLon / 2) * + Math.sin(dLon / 2); + var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + var d = R * c; + return d; + } + + let circle_radius = + Math.max( + ...filteredData.map((item: StudentStatusFilterTypeFlattened) => + haversineDistance(avgLat, avgLng, item.latitude, item.longitude) + ) + ) * 1000; + console.log("Radius:", circle_radius); + + // We now build the object + const subjectUserMap: subjectUserMapType = { + subject: "", + users: [], + latitude: 0, + longitude: 0, + radius: 0, + }; + filteredData.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 a21360e..ac42a41 100644 --- a/src/interfaces/Interfaces.tsx +++ b/src/interfaces/Interfaces.tsx @@ -124,7 +124,7 @@ export interface PatchUserInfoType { avatar?: string; } -interface Location { +export interface LocationType { latitude: Float; longitude: Float; } @@ -132,7 +132,7 @@ interface Location { export interface StudentStatusType { user?: string; subject?: string; - location?: Location; + location?: LocationType; landmark?: string | null; active?: boolean; } @@ -141,10 +141,23 @@ export interface StudentStatusFilterType { active: boolean; distance: number; landmark: string | null; - location: Location; + location: LocationType; study_group?: string; subject: string; user: string; + weight?: number; +} + +export interface StudentStatusFilterTypeFlattened { + active: boolean; + distance: number; + landmark: string | null; + latitude: Float; + longitude: Float; + study_group?: string; + subject: string; + user: string; + weight?: number; } export type StudentStatusReturnType = [boolean, StudentStatusType]; @@ -152,7 +165,7 @@ export type StudentStatusReturnType = [boolean, StudentStatusType]; export type StudentStatusListType = Array; export type StudentStatusListReturnType = [boolean, StudentStatusListType]; -export type LocationType = Location.LocationObject; +export type RawLocationType = Location.LocationObject; export interface UserInfoType { first_name: string; @@ -172,3 +185,11 @@ export interface UserInfoType { } export type UserInfoReturnType = [boolean, UserInfoType]; + +export type subjectUserMapType = { + subject: string; + users: string[]; + latitude: Float; + longitude: Float; + radius: Float; +}; diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index e1fc2d8..cf8332a 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -17,10 +17,11 @@ import Button from "../../components/Button/Button"; import { RootDrawerParamList, StudentStatusReturnType, - LocationType, + RawLocationType, StudentStatusType, StudentStatusListReturnType, StudentStatusListType, + subjectUserMapType, } from "../../interfaces/Interfaces"; import { useNavigation } from "@react-navigation/native"; import { @@ -33,12 +34,14 @@ import { import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { useToast } from "react-native-toast-notifications"; import CustomMapCallout from "../../components/CustomMapCallout/CustomMapCallout"; +import ParseStudentStatusList from "../../components/ParseStudyGroupList/ParseStudyGroupList"; +import React from "react"; export default function Home() { // Switch this condition to see the main map when debugging const map_debug = true; const navigation = useNavigation(); - const [location, setLocation] = useState(null); + const [location, setLocation] = useState(null); const [dist, setDist] = useState(null); const [feedback, setFeedback] = useState( "To continue, please allow Stud-E permission to location services" @@ -97,7 +100,7 @@ export default function Home() { requestLocation(); }, []); - async function GetDistanceRoundedOff(location: LocationType) { + async function GetDistanceRoundedOff(location: RawLocationType) { let dist = GetDistance( location.coords.latitude, location.coords.longitude, @@ -176,8 +179,8 @@ export default function Home() { }, }); - // Can probably just get the max distance from the array and use it as radius const [student_statuses, setStudentStatuses] = useState([]); + const [study_groups, setStudyGroups] = useState([]); // Student Status List const StudentStatusList = useQuery({ enabled: studying, @@ -191,93 +194,7 @@ export default function Home() { }, onSuccess: (data: StudentStatusListReturnType) => { if (data[1]) { - // Circle generation for students in a study group - // We first flatten the data to remove nested entries - let flattened_data = data[1].map((item) => ({ - active: item.active, - distance: item.distance, - landmark: item.landmark, - latitude: item.location.latitude, - longitude: item.location.longitude, - study_group: "", - subject: item.subject, - user: item.user, - weight: 1, - })); - // Dummy data - flattened_data.push({ - active: true, - distance: 50, - landmark: "", - latitude: 8.498837, - longitude: 124.595422, - study_group: "", - subject: "Introduction to Computing", - user: "Dummy", - weight: 1, - }); - // We get each unique subject - let unique_subjects = [ - ...new Set(flattened_data.map((item) => item.subject)), - ]; - let result: any[] = []; - // Then append all entries belonging to that subject to its own array - unique_subjects.forEach((subject, index: number) => { - index++; - let filteredData = flattened_data.filter( - (item) => item.subject === subject && item.study_group === "" - ); - /*console.log( - "Subject #", - index, - "-", - filteredData[0].subject, - filteredData - );*/ - // We get the circle radius based on the furthest point - let circle_radius = Math.max( - ...filteredData.map((item) => item.distance) - ); - console.log( - "Radius of circle:", - Math.max(...filteredData.map((item) => item.distance)) - ); - // We get the circle's center by averaging all the points - // Calculate the average latitude and longitude - const totalLat = filteredData.reduce( - (sum, point) => sum + point.latitude, - 0 - ); - const totalLng = filteredData.reduce( - (sum, point) => sum + point.longitude, - 0 - ); - - const avgLat = totalLat / filteredData.length; - const avgLng = totalLng / filteredData.length; - - console.log("Center Latitude:", avgLat); - console.log("Center Longitude:", avgLng); - // We now build the object - const subjectUserMap: any = {}; - filteredData.forEach((item) => { - 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); - - setStudentStatuses(result); + setStudyGroups(ParseStudentStatusList(data[1])); } }, onError: (error: Error) => { @@ -322,73 +239,76 @@ export default function Home() { }} loadingBackgroundColor={colors.secondary_2} > - {student_statuses.map((student_status: any, index: number) => { - const randomColorWithOpacity = `rgba(${Math.floor( - Math.random() * 256 - )}, ${Math.floor(Math.random() * 256)}, ${Math.floor( - Math.random() * 256 - )}, 0.7)`; + {study_groups.map( + (student_status: subjectUserMapType, 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: {student_status.subject} - - - Students Studying: {student_status.users.length} - - - , - { - type: "normal", - placement: "top", - duration: 2000, - animationType: "slide-in", - style: { - backgroundColor: colors.secondary_2, - borderWidth: 1, - borderColor: colors.primary_1, - }, - } - ); - }} - /> - - - ); - })} + + Students Studying: {student_status.users.length} + + + , + { + type: "normal", + placement: "top", + duration: 2000, + animationType: "slide-in", + style: { + backgroundColor: colors.secondary_2, + borderWidth: 1, + borderColor: colors.primary_1, + }, + } + ); + }} + /> + + + ); + } + )} Date: Mon, 11 Sep 2023 19:02:11 +0800 Subject: [PATCH 029/109] Fixed and made changes to the Haversine distance formula calculation. We now point it to the user's location as intended --- .../ParseStudyGroupList.tsx | 150 ++++++++++++------ src/routes/Home/Home.tsx | 9 +- 2 files changed, 106 insertions(+), 53 deletions(-) diff --git a/src/components/ParseStudyGroupList/ParseStudyGroupList.tsx b/src/components/ParseStudyGroupList/ParseStudyGroupList.tsx index 492b649..b6685e9 100644 --- a/src/components/ParseStudyGroupList/ParseStudyGroupList.tsx +++ b/src/components/ParseStudyGroupList/ParseStudyGroupList.tsx @@ -9,59 +9,82 @@ import { } from "../../interfaces/Interfaces"; import { Double, Float } from "react-native/Libraries/Types/CodegenTypes"; -export default function ParseStudyGroupList(data: any) { - let result: any[] = []; +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 - console.log("Initial Data:", data); - let flattened_data = data - .filter((item: StudentStatusFilterType) => item.study_group !== "") - .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("Filtered Data:", flattened_data); + 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 get each unique subject + // We take from the array all unique subject names let unique_subjects = [ ...new Set( - flattened_data.map((item: StudentStatusFilterType) => item.subject) + data_flattened.map((item: StudentStatusFilterType) => item.subject) ), ]; - // Then append all entries belonging to that subject to its own array + // Then we create arrays unique to each subject unique_subjects.forEach((subject, index: number) => { - index++; - let filteredData = flattened_data.filter( + // 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 ); - console.log("Subject #", index, "-", filteredData[0].subject, filteredData); + */ + // We get the circle's center by averaging all the points // Calculate the average latitude and longitude - const totalLat = filteredData.reduce( + const totalLat = unique_subject_list.reduce( (sum: Double, point: LocationType) => sum + point.latitude, 0 ); - const totalLng = filteredData.reduce( + const totalLng = unique_subject_list.reduce( (sum: Double, point: LocationType) => sum + point.longitude, 0 ); - const avgLat = totalLat / filteredData.length; - const avgLng = totalLng / filteredData.length; + let avgLat = totalLat / unique_subject_list.length; + let avgLng = totalLng / unique_subject_list.length; - console.log("Center Latitude:", avgLat); - console.log("Center Longitude:", avgLng); - - // We now calculate the radius of the circle using the Haversine Distance Formula + // console.log("Center Latitude:", avgLat); + // console.log("Center Longitude:", avgLng); + // Haversine Distance Function function haversineDistance( lat1: number, lon1: number, @@ -72,31 +95,56 @@ export default function ParseStudyGroupList(data: any) { return (x * Math.PI) / 180; } - var R = 6371; // km - var x1 = lat2 - lat1; - var dLat = toRad(x1); - var x2 = lon2 - lon1; - var dLon = toRad(x2); - var a = + 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(toRad(lat1)) * - Math.cos(toRad(lat2)) * + Math.cos(lat1) * + Math.cos(lat2) * Math.sin(dLon / 2) * Math.sin(dLon / 2); - var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); - var d = R * c; - return d; + 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; } - let circle_radius = - Math.max( - ...filteredData.map((item: StudentStatusFilterTypeFlattened) => - haversineDistance(avgLat, avgLng, item.latitude, item.longitude) - ) - ) * 1000; - console.log("Radius:", circle_radius); + // 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 - // We now build the object + 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: [], @@ -104,7 +152,7 @@ export default function ParseStudyGroupList(data: any) { longitude: 0, radius: 0, }; - filteredData.forEach((item: StudentStatusFilterType) => { + unique_subject_list.forEach((item: StudentStatusFilterType) => { if (!subjectUserMap["users"]) { subjectUserMap["users"] = []; } diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index cf8332a..095cd95 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -193,8 +193,13 @@ export default function Home() { return data; }, onSuccess: (data: StudentStatusListReturnType) => { - if (data[1]) { - setStudyGroups(ParseStudentStatusList(data[1])); + if (data[1] && location) { + setStudyGroups( + ParseStudentStatusList(data[1], { + latitude: location.coords.latitude, + longitude: location.coords.longitude, + }) + ); } }, onError: (error: Error) => { From 980d1e636e2a8c471c7b4ea9666bc7abf5b78cdd Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Mon, 11 Sep 2023 19:16:48 +0800 Subject: [PATCH 030/109] Added student status point rendering --- .../ParseStudentStatusList.tsx | 35 ++++++++++ .../ParseStudyGroupList.tsx | 4 +- src/routes/Home/Home.tsx | 64 +++++++++++++++++-- 3 files changed, 97 insertions(+), 6 deletions(-) create mode 100644 src/components/ParseStudentStatusList/ParseStudentStatusList.tsx diff --git a/src/components/ParseStudentStatusList/ParseStudentStatusList.tsx b/src/components/ParseStudentStatusList/ParseStudentStatusList.tsx new file mode 100644 index 0000000..4e673c9 --- /dev/null +++ b/src/components/ParseStudentStatusList/ParseStudentStatusList.tsx @@ -0,0 +1,35 @@ +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 index b6685e9..93c70cb 100644 --- a/src/components/ParseStudyGroupList/ParseStudyGroupList.tsx +++ b/src/components/ParseStudyGroupList/ParseStudyGroupList.tsx @@ -132,12 +132,12 @@ export default function ParseStudyGroupList( user_location.longitude ); - console.log( + /*console.log( "Haversine Distance for entry #", index + 1, ":", distance - ); + );*/ return distance; } ) diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index 095cd95..f8bdf57 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -22,6 +22,7 @@ import { StudentStatusListReturnType, StudentStatusListType, subjectUserMapType, + StudentStatusFilterTypeFlattened, } from "../../interfaces/Interfaces"; import { useNavigation } from "@react-navigation/native"; import { @@ -34,8 +35,9 @@ import { import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { useToast } from "react-native-toast-notifications"; import CustomMapCallout from "../../components/CustomMapCallout/CustomMapCallout"; -import ParseStudentStatusList from "../../components/ParseStudyGroupList/ParseStudyGroupList"; import React from "react"; +import ParseStudyGroupList from "../../components/ParseStudyGroupList/ParseStudyGroupList"; +import ParseStudentStatusList from "../../components/ParseStudentStatusList/ParseStudentStatusList"; export default function Home() { // Switch this condition to see the main map when debugging @@ -179,7 +181,9 @@ export default function Home() { }, }); - const [student_statuses, setStudentStatuses] = useState([]); + const [student_statuses, setStudentStatuses] = useState< + StudentStatusFilterTypeFlattened[] + >([]); const [study_groups, setStudyGroups] = useState([]); // Student Status List const StudentStatusList = useQuery({ @@ -195,11 +199,12 @@ export default function Home() { onSuccess: (data: StudentStatusListReturnType) => { if (data[1] && location) { setStudyGroups( - ParseStudentStatusList(data[1], { + ParseStudyGroupList(data[1], { latitude: location.coords.latitude, longitude: location.coords.longitude, }) ); + setStudentStatuses(ParseStudentStatusList(data[1])); } }, onError: (error: Error) => { @@ -244,6 +249,57 @@ export default function Home() { }} loadingBackgroundColor={colors.secondary_2} > + {student_statuses.map( + ( + student_status: StudentStatusFilterTypeFlattened, + 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( + + + Student: {student_status.user} + + + Studying Subject: {student_status.subject} + + , + { + type: "normal", + placement: "top", + duration: 2000, + animationType: "slide-in", + style: { + backgroundColor: colors.secondary_2, + borderWidth: 1, + borderColor: colors.primary_1, + }, + } + ); + }} + /> + ); + } + )} {study_groups.map( (student_status: subjectUserMapType, index: number) => { const randomColorWithOpacity = `rgba(${Math.floor( @@ -285,7 +341,7 @@ export default function Home() { }} > - Create Group & Invite + Join Group , From 511f293ff1aa4766d67a17fc283cb9946734b53f Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Wed, 20 Sep 2023 17:42:37 +0800 Subject: [PATCH 031/109] Changed debug backend url --- src/components/Api/Api.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Api/Api.tsx b/src/components/Api/Api.tsx index f518496..c3faa04 100644 --- a/src/components/Api/Api.tsx +++ b/src/components/Api/Api.tsx @@ -12,8 +12,8 @@ import { export let backendURL = "https://stude.keannu1.duckdns.org"; export let backendURLWebsocket = "ws://stude.keannu1.duckdns.org"; if (__DEV__) { - backendURL = "http://10.0.10.8:8000"; - backendURLWebsocket = "ws://10.0.10.8:8000"; + backendURL = "http://10.0.10.8:8083"; + backendURLWebsocket = "ws://10.0.10.8:8083"; } // Switch this on if you wanna run production URLs while in development From 12e3d2982209007bd6c4100db96aa1adb47776c9 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Wed, 20 Sep 2023 17:44:58 +0800 Subject: [PATCH 032/109] Do not autocapitalize password fields --- src/routes/Login/Login.tsx | 1 + src/routes/Register/Register.tsx | 1 + 2 files changed, 2 insertions(+) diff --git a/src/routes/Login/Login.tsx b/src/routes/Login/Login.tsx index b141a3d..5a72b1a 100644 --- a/src/routes/Login/Login.tsx +++ b/src/routes/Login/Login.tsx @@ -59,6 +59,7 @@ export default function Login() { placeholderTextColor="white" secureTextEntry={true} value={creds.password} + autoCapitalize={"none"} onChange={( e: NativeSyntheticEvent ): void => { diff --git a/src/routes/Register/Register.tsx b/src/routes/Register/Register.tsx index 09633a5..c563f26 100644 --- a/src/routes/Register/Register.tsx +++ b/src/routes/Register/Register.tsx @@ -113,6 +113,7 @@ export default function Register() { placeholderTextColor={colors.text_default} secureTextEntry={true} value={user.password} + autoCapitalize={"none"} onChange={( e: NativeSyntheticEvent ): void => { From 790574daee95dd5b9a9b33ba7de7cf039584879a Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Wed, 20 Sep 2023 19:36:06 +0800 Subject: [PATCH 033/109] Separated distance calculation and far map renderer into own components --- src/components/Api/Api.tsx | 3 +- .../GetDistance/GetDistanceFromUSTP.tsx | 20 +++++ src/components/MapRenderer/MapRendererFar.tsx | 79 ++++++++++++++++++ src/interfaces/Interfaces.tsx | 8 +- src/routes/Home/Home.tsx | 81 ++----------------- 5 files changed, 116 insertions(+), 75 deletions(-) create mode 100644 src/components/GetDistance/GetDistanceFromUSTP.tsx create mode 100644 src/components/MapRenderer/MapRendererFar.tsx diff --git a/src/components/Api/Api.tsx b/src/components/Api/Api.tsx index c3faa04..74b86d5 100644 --- a/src/components/Api/Api.tsx +++ b/src/components/Api/Api.tsx @@ -6,6 +6,7 @@ import { OnboardingType, PatchUserInfoType, RegistrationType, + StudentStatusPatchType, StudentStatusType, } from "../../interfaces/Interfaces"; @@ -243,7 +244,7 @@ export async function GetStudentStatus() { }); } -export async function PatchStudentStatus(info: StudentStatusType) { +export async function PatchStudentStatus(info: StudentStatusPatchType) { const config = await GetConfig(); console.log(info); return instance diff --git a/src/components/GetDistance/GetDistanceFromUSTP.tsx b/src/components/GetDistance/GetDistanceFromUSTP.tsx new file mode 100644 index 0000000..391df27 --- /dev/null +++ b/src/components/GetDistance/GetDistanceFromUSTP.tsx @@ -0,0 +1,20 @@ +import { LocationType } from "../../interfaces/Interfaces"; +import GetDistance from "./GetDistance"; + +export default function GetDistanceFromUSTP(location: LocationType) { + const ustpCoords = { + latitude: 8.4857, + longitude: 124.6565, + latitudeDelta: 0.000235, + longitudeDelta: 0.000067, + }; + + let dist = GetDistance( + location.latitude, + location.longitude, + ustpCoords.latitude, + ustpCoords.longitude + ); + dist = Math.round(dist); + return dist; +} diff --git a/src/components/MapRenderer/MapRendererFar.tsx b/src/components/MapRenderer/MapRendererFar.tsx new file mode 100644 index 0000000..776df86 --- /dev/null +++ b/src/components/MapRenderer/MapRendererFar.tsx @@ -0,0 +1,79 @@ +import * as React from "react"; +import { View, Text } from "react-native"; +import MapView, { UrlTile, Callout, Marker } from "react-native-maps"; +import styles, { Viewport, colors } from "../../styles"; +import { urlProvider } from "../Api/Api"; +import { LocationType, RawLocationType } from "../../interfaces/Interfaces"; +import GetDistance from "../../components/GetDistance/GetDistance"; + +type props = { + location: LocationType; + dist: any; +}; + +export default function MapRendererFar(props: props) { + return ( + + + You are too far from USTP {"\n"} + Get closer to use Stud-E + + + + + + + You are here {"\n"} + X: {Math.round(props.location.longitude) + "\n"} + Z: {Math.round(props.location.latitude)} + + + + + + {props.dist}km away from USTP {"\n"} + + + ); +} diff --git a/src/interfaces/Interfaces.tsx b/src/interfaces/Interfaces.tsx index ac42a41..7623b88 100644 --- a/src/interfaces/Interfaces.tsx +++ b/src/interfaces/Interfaces.tsx @@ -130,7 +130,13 @@ export interface LocationType { } export interface StudentStatusType { - user?: string; + subject: string; + location: LocationType; + landmark: string | null; + active: boolean; +} + +export interface StudentStatusPatchType { subject?: string; location?: LocationType; landmark?: string | null; diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index f8bdf57..2a9cd8d 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -23,6 +23,7 @@ import { StudentStatusListType, subjectUserMapType, StudentStatusFilterTypeFlattened, + StudentStatusPatchType, } from "../../interfaces/Interfaces"; import { useNavigation } from "@react-navigation/native"; import { @@ -34,14 +35,16 @@ import { } from "../../components/Api/Api"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { useToast } from "react-native-toast-notifications"; -import CustomMapCallout from "../../components/CustomMapCallout/CustomMapCallout"; 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"; export default function Home() { // Switch this condition to see the main map when debugging - const map_debug = true; + const map_debug = false; const navigation = useNavigation(); const [location, setLocation] = useState(null); const [dist, setDist] = useState(null); @@ -103,12 +106,7 @@ export default function Home() { }, []); async function GetDistanceRoundedOff(location: RawLocationType) { - let dist = GetDistance( - location.coords.latitude, - location.coords.longitude, - ustpCoords.latitude, - ustpCoords.longitude - ); + let dist = GetDistanceFromUSTP(location.coords); setDist(Math.round(dist)); // Deactivate student status if too far away if (dist >= 2 && !map_debug) @@ -154,7 +152,7 @@ export default function Home() { }); const mutation = useMutation({ - mutationFn: async (info: StudentStatusType) => { + mutationFn: async (info: StudentStatusPatchType) => { const data = await PatchStudentStatus(info); if (data[0] != true) { return Promise.reject(new Error()); @@ -426,70 +424,7 @@ export default function Home() { ); } else { - return ( - - - You are too far from USTP {"\n"} - Get closer to use Stud-E - - - - - - - You are here {"\n"} - X: {Math.round(location.coords.longitude) + "\n"} - Z: {Math.round(location.coords.latitude)} - - - - - - {dist}km away from USTP {"\n"} - - - ); + return ; } } else { requestLocation(); From 14e14b8bb6deba6076b6b43e5d852572b9ecee97 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Wed, 20 Sep 2023 19:53:25 +0800 Subject: [PATCH 034/109] Code cleanup --- src/routes/Home/Home.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index 2a9cd8d..c8f9718 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -85,7 +85,7 @@ export default function Home() { newLocation.coords.longitude !== location.coords.longitude ) { setLocation(newLocation); - GetDistanceRoundedOff(newLocation); + DistanceHandler(newLocation); } } } @@ -105,9 +105,9 @@ export default function Home() { requestLocation(); }, []); - async function GetDistanceRoundedOff(location: RawLocationType) { + async function DistanceHandler(location: RawLocationType) { let dist = GetDistanceFromUSTP(location.coords); - setDist(Math.round(dist)); + setDist(dist); // Deactivate student status if too far away if (dist >= 2 && !map_debug) mutation.mutate({ From 68778cea7aa23745b95c6615e57d18e62e0aa380 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Wed, 20 Sep 2023 21:16:54 +0800 Subject: [PATCH 035/109] Code cleanup for multiple pages and components --- .../CustomMapCallout/CustomMapCallout.tsx | 14 +++++++------- src/routes/Home/Home.tsx | 12 +++++++++--- src/routes/StartStudying/StartStudying.tsx | 3 ++- src/routes/SubjectsPage/SubjectsPage.tsx | 3 ++- src/routes/UserInfoPage/UserInfoPage.tsx | 3 ++- 5 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/components/CustomMapCallout/CustomMapCallout.tsx b/src/components/CustomMapCallout/CustomMapCallout.tsx index 23661e3..6184c9a 100644 --- a/src/components/CustomMapCallout/CustomMapCallout.tsx +++ b/src/components/CustomMapCallout/CustomMapCallout.tsx @@ -1,26 +1,26 @@ import { Callout } from "react-native-maps"; -import { RawLocationType } from "../../interfaces/Interfaces"; +import { LocationType, RawLocationType } from "../../interfaces/Interfaces"; import styles from "../../styles"; import { Text } from "react-native"; // Map popup for user's location type props = { - location: RawLocationType; + location: LocationType; studying: boolean; subject?: string; }; export default function CustomMapCallout(props: props) { let { location, studying, subject } = props; - if (location && location.coords) { + if (location && location.latitude && location.longitude) { if (studying) { return ( You are here {"\n"} - X: {Math.round(location.coords.longitude) + "\n"} - Z: {Math.round(location.coords.latitude) + "\n"} + X: {Math.round(location.longitude) + "\n"} + Z: {Math.round(location.latitude) + "\n"} Studying: {subject} @@ -30,8 +30,8 @@ export default function CustomMapCallout(props: props) { You are here {"\n"} - X: {Math.round(location.coords.longitude) + "\n"} - Z: {Math.round(location.coords.latitude)} + X: {Math.round(location.longitude) + "\n"} + Z: {Math.round(location.latitude)} ); diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index c8f9718..3a0317a 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -44,7 +44,7 @@ import GetDistanceFromUSTP from "../../components/GetDistance/GetDistanceFromUST export default function Home() { // Switch this condition to see the main map when debugging - const map_debug = false; + const map_debug = true; const navigation = useNavigation(); const [location, setLocation] = useState(null); const [dist, setDist] = useState(null); @@ -119,6 +119,7 @@ export default function Home() { const [studying, setStudying] = useState(false); const [subject, setSubject] = useState(""); const [buttonLabel, setButtonLabel] = useState("Start studying"); + const [student_status, setStudentStatus] = useState(); const StudentStatus = useQuery({ queryKey: ["user_status"], queryFn: async () => { @@ -140,6 +141,8 @@ export default function Home() { } else if (data[1].active == false) { setButtonLabel("Start Studying"); } + setStudentStatus(data[1]); + console.log(student_status); }, onError: (error: Error) => { toast.show(String(error), { @@ -373,7 +376,7 @@ export default function Home() { latitude: location.coords.latitude, longitude: location.coords.longitude, }} - draggable + draggable={student_status?.active} onDragEnd={(e) => { const newLocation = e.nativeEvent.coordinate; const distance = GetDistance( @@ -402,7 +405,10 @@ export default function Home() { pinColor={colors.primary_1} > diff --git a/src/routes/StartStudying/StartStudying.tsx b/src/routes/StartStudying/StartStudying.tsx index 9f420d2..2aa8677 100644 --- a/src/routes/StartStudying/StartStudying.tsx +++ b/src/routes/StartStudying/StartStudying.tsx @@ -8,6 +8,7 @@ import { RootDrawerParamList, StudentStatusType, StudentStatusReturnType, + StudentStatusPatchType, } from "../../interfaces/Interfaces"; import Button from "../../components/Button/Button"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; @@ -61,7 +62,7 @@ export default function StartStudying({ route }: any) { }); const mutation = useMutation({ - mutationFn: async (info: StudentStatusType) => { + mutationFn: async (info: StudentStatusPatchType) => { const data = await PatchStudentStatus(info); if (data[0] == false) { return Promise.reject(new Error(JSON.stringify(data[1]))); diff --git a/src/routes/SubjectsPage/SubjectsPage.tsx b/src/routes/SubjectsPage/SubjectsPage.tsx index 76c841d..cfee8f7 100644 --- a/src/routes/SubjectsPage/SubjectsPage.tsx +++ b/src/routes/SubjectsPage/SubjectsPage.tsx @@ -9,6 +9,7 @@ import { OptionType, StudentStatusType, PatchUserInfoType, + StudentStatusPatchType, } from "../../interfaces/Interfaces"; import Button from "../../components/Button/Button"; import { Image } from "react-native"; @@ -33,7 +34,7 @@ export default function SubjectsPage() { // Student Status const studentstatus_mutation = useMutation({ - mutationFn: async (info: StudentStatusType) => { + mutationFn: async (info: StudentStatusPatchType) => { const data = await PatchStudentStatus(info); if (data[0] != true) { return Promise.reject(new Error()); diff --git a/src/routes/UserInfoPage/UserInfoPage.tsx b/src/routes/UserInfoPage/UserInfoPage.tsx index 512ea89..5d8a49b 100644 --- a/src/routes/UserInfoPage/UserInfoPage.tsx +++ b/src/routes/UserInfoPage/UserInfoPage.tsx @@ -18,6 +18,7 @@ import { OptionType, StudentStatusType, PatchUserInfoType, + StudentStatusPatchType, } from "../../interfaces/Interfaces"; import Button from "../../components/Button/Button"; import { Image } from "react-native"; @@ -50,7 +51,7 @@ export default function UserInfoPage() { // Student Status const studentstatus_mutation = useMutation({ - mutationFn: async (info: StudentStatusType) => { + mutationFn: async (info: StudentStatusPatchType) => { const data = await PatchStudentStatus(info); if (data[0] != true) { return Promise.reject(new Error()); From 81bead43ff7b090b13cb100864830c44a3c86dda Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Fri, 22 Sep 2023 22:55:36 +0800 Subject: [PATCH 036/109] Fixed filtering for study groups --- .../ParseStudyGroupList.tsx | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/components/ParseStudyGroupList/ParseStudyGroupList.tsx b/src/components/ParseStudyGroupList/ParseStudyGroupList.tsx index 93c70cb..fdd1ddc 100644 --- a/src/components/ParseStudyGroupList/ParseStudyGroupList.tsx +++ b/src/components/ParseStudyGroupList/ParseStudyGroupList.tsx @@ -17,7 +17,8 @@ export default function ParseStudyGroupList( 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 !== "" + (item: StudentStatusFilterType) => + item.study_group !== undefined && item.study_group.length > 0 ); // console.log("Filtered Data:", data_filtered); // Then we flatten the data so that all attributes are in the first layer @@ -35,19 +36,20 @@ export default function ParseStudyGroupList( })); // console.log("Flattened Data:", data_flattened); - // We take from the array all unique subject names - let unique_subjects = [ + // We take from the array all unique study groups + let unique_studygroups = [ ...new Set( - data_flattened.map((item: StudentStatusFilterType) => item.subject) + data_flattened.map((item: StudentStatusFilterType) => item.study_group) ), ]; // Then we create arrays unique to each subject - unique_subjects.forEach((subject, index: number) => { + unique_studygroups.forEach((studygroup, 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 + (item: StudentStatusFilterTypeFlattened) => + item.study_group === studygroup ) .map((item: StudentStatusFilterTypeFlattened) => ({ active: item.active, @@ -147,6 +149,7 @@ export default function ParseStudyGroupList( // We now build the object that we will return const subjectUserMap: subjectUserMapType = { subject: "", + study_group: "", users: [], latitude: 0, longitude: 0, @@ -156,6 +159,9 @@ export default function ParseStudyGroupList( if (!subjectUserMap["users"]) { subjectUserMap["users"] = []; } + if (!subjectUserMap["study_group"]) { + subjectUserMap["study_group"] = unique_subject_list[0].study_group; + } subjectUserMap["subject"] = item.subject; subjectUserMap["latitude"] = avgLat; subjectUserMap["longitude"] = avgLng; @@ -167,7 +173,7 @@ export default function ParseStudyGroupList( result = result.concat([subjectUserMap]); }); - // console.log("Final Result:", result); + console.log("Final Result:", result); return result; } From c4413a185d8b01107a3c6bb3a0772a18f831d35c Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Fri, 22 Sep 2023 23:08:06 +0800 Subject: [PATCH 037/109] Hidden unused console.log --- .../ParseStudentStatusList/ParseStudentStatusList.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ParseStudentStatusList/ParseStudentStatusList.tsx b/src/components/ParseStudentStatusList/ParseStudentStatusList.tsx index 4e673c9..1f0b16e 100644 --- a/src/components/ParseStudentStatusList/ParseStudentStatusList.tsx +++ b/src/components/ParseStudentStatusList/ParseStudentStatusList.tsx @@ -16,7 +16,7 @@ export default function ParseStudentStatusList(data: any) { let data_filtered = data.filter( (item: StudentStatusFilterType) => item.study_group == "" ); - console.log("Filtered Data:", data_filtered); + // 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) => ({ From 7da7d0f2175ff03ac1c741c0f4dcb9d000486278 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Fri, 22 Sep 2023 23:08:20 +0800 Subject: [PATCH 038/109] Hidden unused console.log in api --- src/components/Api/Api.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/Api/Api.tsx b/src/components/Api/Api.tsx index 74b86d5..9d9f826 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) => { From 19d19c3dd5ccece39cbb7a93f83d1bb40e7cbd8c Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Fri, 22 Sep 2023 23:08:54 +0800 Subject: [PATCH 039/109] Reflect user pin location change if user manually overrides location --- src/routes/Home/Home.tsx | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index 3a0317a..10f15ca 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -243,8 +243,12 @@ 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, }} @@ -372,11 +376,16 @@ export default function Home() { } )} { const newLocation = e.nativeEvent.coordinate; const distance = GetDistance( From 1bd07f9edd83964b260cc6d3907e750bb383ca42 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Sun, 24 Sep 2023 21:02:34 +0800 Subject: [PATCH 040/109] Optimized homepage rendering and removed overly complicated components --- src/components/Api/Api.tsx | 14 ++ .../ParseStudentStatusList.tsx | 35 ---- .../ParseStudyGroupList.tsx | 179 ----------------- src/interfaces/Interfaces.tsx | 11 + src/routes/Home/Home.tsx | 188 ++++++++++-------- 5 files changed, 129 insertions(+), 298 deletions(-) delete mode 100644 src/components/ParseStudentStatusList/ParseStudentStatusList.tsx delete mode 100644 src/components/ParseStudyGroupList/ParseStudyGroupList.tsx diff --git a/src/components/Api/Api.tsx b/src/components/Api/Api.tsx index 9d9f826..195b8cf 100644 --- a/src/components/Api/Api.tsx +++ b/src/components/Api/Api.tsx @@ -296,3 +296,17 @@ 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) => { + console.log("Data:", 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 1f0b16e..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 fdd1ddc..0000000 --- a/src/components/ParseStudyGroupList/ParseStudyGroupList.tsx +++ /dev/null @@ -1,179 +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 !== undefined && item.study_group.length > 0 - ); - // 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 study groups - let unique_studygroups = [ - ...new Set( - data_flattened.map((item: StudentStatusFilterType) => item.study_group) - ), - ]; - - // Then we create arrays unique to each subject - unique_studygroups.forEach((studygroup, 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.study_group === studygroup - ) - .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: "", - study_group: "", - users: [], - latitude: 0, - longitude: 0, - radius: 0, - }; - unique_subject_list.forEach((item: StudentStatusFilterType) => { - if (!subjectUserMap["users"]) { - subjectUserMap["users"] = []; - } - if (!subjectUserMap["study_group"]) { - subjectUserMap["study_group"] = unique_subject_list[0].study_group; - } - 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 10f15ca..7e19e6e 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -24,20 +24,22 @@ import { subjectUserMapType, StudentStatusFilterTypeFlattened, StudentStatusPatchType, + StudyGroupType, + StudyGroupReturnType, + StudentStatusFilterType, } from "../../interfaces/Interfaces"; import { useNavigation } from "@react-navigation/native"; import { GetStudentStatus, GetStudentStatusList, GetStudentStatusListFiltered, + 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 +122,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 +184,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 +199,38 @@ 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) => { @@ -255,10 +280,7 @@ export default function Home() { 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( @@ -268,7 +290,7 @@ export default function Home() { return ( { @@ -305,76 +327,74 @@ export default function Home() { ); } )} - {study_groups.map( - (student_status: subjectUserMapType, index: number) => { - const randomColorWithOpacity = `rgba(${Math.floor( - Math.random() * 256 - )}, ${Math.floor(Math.random() * 256)}, ${Math.floor( - Math.random() * 256 - )}, 0.7)`; + {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( - + { + 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, - }, - } - ); - }} - /> - - - ); - } - )} + + , + { + type: "normal", + placement: "top", + duration: 2000, + animationType: "slide-in", + style: { + backgroundColor: colors.secondary_2, + borderWidth: 1, + borderColor: colors.primary_1, + }, + } + ); + }} + /> + + + ); + })} Date: Sun, 24 Sep 2023 21:26:15 +0800 Subject: [PATCH 041/109] Added global study groups rendering --- src/components/Api/Api.tsx | 15 +++++- src/routes/Home/Home.tsx | 99 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 1 deletion(-) diff --git a/src/components/Api/Api.tsx b/src/components/Api/Api.tsx index 195b8cf..430124f 100644 --- a/src/components/Api/Api.tsx +++ b/src/components/Api/Api.tsx @@ -302,7 +302,20 @@ export async function GetStudyGroupListFiltered() { return instance .get("/api/v1/study_groups/near/", config) .then((response) => { - console.log("Data:", response.data); + 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) => { diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index 7e19e6e..f926c26 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -33,6 +33,7 @@ import { GetStudentStatus, GetStudentStatusList, GetStudentStatusListFiltered, + GetStudyGroupList, GetStudyGroupListFiltered, PatchStudentStatus, urlProvider, @@ -242,6 +243,34 @@ export default function Home() { }); }, }); + 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) => { + toast.show(String(error), { + type: "warning", + placement: "top", + duration: 2000, + animationType: "slide-in", + }); + }, + }); function CustomMap() { if (dist && location) { @@ -395,6 +424,76 @@ export default function Home() { ); })} + {study_groups_global.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, + }, + } + ); + }} + /> + + + ); + } + )} Date: Tue, 26 Sep 2023 20:29:21 +0800 Subject: [PATCH 042/109] Added study group creation --- src/components/Api/Api.tsx | 18 +++++- src/interfaces/Interfaces.tsx | 7 +++ src/routes/Home/Home.tsx | 110 ++++++++++++++++++++++++++++++---- 3 files changed, 124 insertions(+), 11 deletions(-) diff --git a/src/components/Api/Api.tsx b/src/components/Api/Api.tsx index 430124f..3130d12 100644 --- a/src/components/Api/Api.tsx +++ b/src/components/Api/Api.tsx @@ -8,6 +8,8 @@ import { RegistrationType, StudentStatusPatchType, StudentStatusType, + StudyGroupCreateType, + StudyGroupType, } from "../../interfaces/Interfaces"; export let backendURL = "https://stude.keannu1.duckdns.org"; @@ -275,6 +277,7 @@ export async function GetStudentStatusListFiltered() { return instance .get("/api/v1/student_status/filter/near_student_status", config) .then((response) => { + console.log("test", response.data); return [true, response.data]; }) .catch((error) => { @@ -315,7 +318,20 @@ export async function GetStudyGroupList() { 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]; + }); +} + +export async function CreateStudyGroup(info: StudyGroupCreateType) { + const config = await GetConfig(); + console.log("Payload:", info); + return instance + .post("/api/v1/study_groups/create/", info, config) + .then((response) => { return [true, response.data]; }) .catch((error) => { diff --git a/src/interfaces/Interfaces.tsx b/src/interfaces/Interfaces.tsx index be6d983..33844eb 100644 --- a/src/interfaces/Interfaces.tsx +++ b/src/interfaces/Interfaces.tsx @@ -175,6 +175,13 @@ export interface StudyGroupType { subject: string; radius: number; } + +export interface StudyGroupCreateType { + name: string; + location: LocationType; + subject: string; +} + export type StudyGroupReturnType = [boolean, StudyGroupType[]]; export type StudentStatusReturnType = [boolean, StudentStatusType]; diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index f926c26..b3465b3 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -27,9 +27,11 @@ import { StudyGroupType, StudyGroupReturnType, StudentStatusFilterType, + StudyGroupCreateType, } from "../../interfaces/Interfaces"; import { useNavigation } from "@react-navigation/native"; import { + CreateStudyGroup, GetStudentStatus, GetStudentStatusList, GetStudentStatusListFiltered, @@ -44,10 +46,13 @@ import React from "react"; import CustomMapCallout from "../../components/CustomMapCallout/CustomMapCallout"; import MapRendererFar from "../../components/MapRenderer/MapRendererFar"; import GetDistanceFromUSTP from "../../components/GetDistance/GetDistanceFromUSTP"; +import { useSelector } from "react-redux"; +import { RootState } from "../../features/redux/Store/Store"; export default function Home() { // Switch this condition to see the main map when debugging const map_debug = true; + const user_state = useSelector((state: RootState) => state.user); const navigation = useNavigation(); const [location, setLocation] = useState(null); const [dist, setDist] = useState(null); @@ -185,6 +190,34 @@ export default function Home() { }, }); + const study_group_create = useMutation({ + mutationFn: async (info: StudyGroupCreateType) => { + const data = await CreateStudyGroup(info); + if (data[0] != true) { + return Promise.reject(new Error()); + } + return data; + }, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ["user"] }); + queryClient.invalidateQueries({ queryKey: ["user_status"] }); + toast.show("Created successfully", { + type: "success", + placement: "top", + duration: 2000, + animationType: "slide-in", + }); + }, + onError: (error: Error) => { + toast.show(String(error), { + type: "warning", + placement: "top", + duration: 2000, + animationType: "slide-in", + }); + }, + }); + const [student_statuses, setStudentStatuses] = useState([]); // Student Status List @@ -531,16 +564,73 @@ export default function Home() { } }} pinColor={colors.primary_1} - > - - + onPress={() => { + toast.hideAll(); + toast.show( + + + You are here + + + + {"x: " + + (student_status?.location?.longitude != 0 + ? student_status?.location?.longitude.toFixed(4) + : location.coords.longitude.toFixed(4))} + + + {"y: " + + (student_status?.location?.latitude != 0 + ? student_status?.location?.latitude.toFixed(4) + : location.coords.latitude.toFixed(4))} + + {studying ? ( + <> + + {studying + ? "Studying " + student_status?.subject + : ""} + + + + ) : ( + <> + )} + , + { + type: "normal", + placement: "top", + duration: 2000, + animationType: "slide-in", + style: { + backgroundColor: colors.secondary_2, + borderWidth: 1, + borderColor: colors.primary_1, + }, + } + ); + }} + > + + + + ); + } + return ; +} diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index b3465b3..8adfa3f 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -416,7 +416,7 @@ export default function Home() { Subject: {studygroup.subject} - Students Studying: {studygroup.users.length} + Students Studying: {studygroup.students.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( - Math.random() * 256 - )}, 0.7)`; - - return ( - - { - toast.hideAll(); - toast.show( - - - Subject: {studygroup.subject} - - - Students Studying: {studygroup.students.length} - - - , - { - type: "normal", - placement: "top", - duration: 2000, - animationType: "slide-in", - style: { - backgroundColor: colors.secondary_2, - borderWidth: 1, - borderColor: colors.primary_1, - }, - } - ); - }} - /> - - - ); - } - )} - { - const newLocation = e.nativeEvent.coordinate; - const distance = GetDistance( - newLocation.latitude, - newLocation.longitude, - location.coords.latitude, - location.coords.longitude - ); - if (distance <= 0.1) { - // If the new location is within 100 meters of the actual location, update the location state - setLocation({ - ...location, - coords: { - ...location.coords, - latitude: newLocation.latitude, - longitude: newLocation.longitude, - }, - }); - } else { - // If the new location is more than 100 meters away from the actual location, reset the marker to the actual location - setLocation({ - ...location, - }); - } - }} - pinColor={colors.primary_1} - onPress={() => { - toast.hideAll(); - toast.show( - - - You are here - - - - {"x: " + - (student_status?.location?.longitude != undefined - ? student_status?.location?.longitude.toFixed(4) - : location.coords.longitude.toFixed(4))} - - - {"y: " + - (student_status?.location?.latitude != undefined - ? student_status?.location?.latitude.toFixed(4) - : location.coords.latitude.toFixed(4))} - - {student_status?.active && - !student_status?.study_group ? ( - <> - - {student_status?.active - ? "Studying " + student_status?.subject - : ""} - - + ) : ( + <> + )} + {student_status?.study_group == + studygroup.name ? ( + + ) : ( + <> + )} + , + { + type: "normal", + placement: "top", + duration: 2000, + animationType: "slide-in", + style: { + backgroundColor: colors.secondary_2, + borderWidth: 1, + borderColor: colors.primary_1, + }, } - }} - > - - Create Group - - - - ) : ( - <> - )} - {student_status?.study_group ? ( - <> - - {`Studying ${student_status?.subject}`} - - - {`In group ${student_status?.study_group}`} - - - ) : ( - <> - )} - , - { - type: "normal", - placement: "top", - duration: 2000, - animationType: "slide-in", - style: { - backgroundColor: colors.secondary_2, - borderWidth: 1, - borderColor: colors.primary_1, - }, + ); + }} + /> + + + ); + } + ) + ) : ( + <> + )} + {!studying ? ( + study_groups_global.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} + + + Name: {studygroup.name} + + + Students Studying:{" "} + {studygroup.students.length} + + {student_status?.study_group != + studygroup.name ? ( + + Get closer to join + + ) : ( + <> + )} + , + { + type: "normal", + placement: "top", + duration: 2000, + animationType: "slide-in", + style: { + backgroundColor: colors.secondary_2, + borderWidth: 1, + borderColor: colors.primary_1, + }, + } + ); + }} + /> + + + ); + } + ) + ) : ( + <> + )} + {!studying || !student_status?.study_group ? ( + { + const newLocation = e.nativeEvent.coordinate; + const distance = GetDistance( + newLocation.latitude, + newLocation.longitude, + location.coords.latitude, + location.coords.longitude + ); + if (distance <= 0.1) { + // If the new location is within 100 meters of the actual location, update the location state + setLocation({ + ...location, + coords: { + ...location.coords, + latitude: newLocation.latitude, + longitude: newLocation.longitude, + }, + }); + } else { + // If the new location is more than 100 meters away from the actual location, reset the marker to the actual location + setLocation({ + ...location, + }); } - ); - }} - > + }} + pinColor={colors.primary_1} + onPress={() => { + toast.hideAll(); + toast.show( + + + You are here + + {student_status?.active && + !student_status?.study_group ? ( + <> + + {student_status?.active + ? "Studying " + student_status?.subject + : ""} + + + + ) : ( + <> + )} + {student_status?.study_group ? ( + <> + + {`Studying: ${student_status?.subject}`} + + + {`In group: ${student_status?.study_group}`} + + + ) : ( + <> + )} + , + { + type: "normal", + placement: "top", + duration: 2000, + animationType: "slide-in", + style: { + backgroundColor: colors.secondary_2, + borderWidth: 1, + borderColor: colors.primary_1, + }, + } + ); + }} + > + ) : ( + <> + )} ); - } else if (dist && location && locationFetched) { + } else if (dist && location) { if (dist <= 1 || map_distance_override) { if ( (StudentStatusQuery.isFetching && studying) || From 8867306bd055b68d213cdcd4b32dd9f6efcd9099 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Sun, 15 Oct 2023 11:44:31 +0800 Subject: [PATCH 084/109] Made button visually responsive on pressing --- src/components/Button/Button.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/Button/Button.tsx b/src/components/Button/Button.tsx index ee36630..dce7823 100644 --- a/src/components/Button/Button.tsx +++ b/src/components/Button/Button.tsx @@ -17,7 +17,10 @@ export default function Button({ disabled = false, ...props }: props) { [ + styles.button_template, + { backgroundColor: pressed ? colors.primary_2 : props.color }, + ]} > {props.children} From be216896393efd4595f2adf8db47329ecebdbb70 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Sun, 15 Oct 2023 11:54:48 +0800 Subject: [PATCH 085/109] Added confirm password field --- src/routes/Register/Register.tsx | 98 +++++++++++++++++++++----------- 1 file changed, 64 insertions(+), 34 deletions(-) diff --git a/src/routes/Register/Register.tsx b/src/routes/Register/Register.tsx index c563f26..03ed006 100644 --- a/src/routes/Register/Register.tsx +++ b/src/routes/Register/Register.tsx @@ -23,6 +23,7 @@ export default function Register() { const toast = useToast(); // const dispatch = useDispatch(); // const creds = useSelector((state: RootState) => state.auth.creds); + const [registering, setRegistering] = useState(false); const [user, setUser] = useState({ first_name: "", last_name: "", @@ -30,6 +31,7 @@ export default function Register() { username: "", email: "", password: "", + confirm_password: "", }); return ( @@ -121,49 +123,77 @@ export default function Register() { }} /> + + ): void => { + setUser({ ...user, confirm_password: e.nativeEvent.text }); + }} + /> + ); + } else if ( + (StudentStatusQuery.isFetching && studying) || + StudentStatusListQuery.isFetching || + StudyGroupQuery.isFetching || + (StudentStatusQuery.isFetching && !studying) || + StudentStatusListGlobalQuery.isFetching || + StudyGroupGlobalQuery.isFetching + ) { + return ( + <> + + + Loading... + + ); } else if (dist && location) { - if ( - (StudentStatusQuery.isFetching && studying) || - StudentStatusListQuery.isFetching || - StudyGroupQuery.isFetching || - (StudentStatusQuery.isFetching && !studying) || - StudentStatusListGlobalQuery.isFetching || - StudyGroupGlobalQuery.isFetching - ) { - return ( - <> - - - Loading... - - ); - } else if (dist <= 1 || map_distance_override) { + if (dist <= 1 || map_distance_override) { return ( <> From e501bc2c91a28e9aebc8055b40d407404c84b138 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Sun, 15 Oct 2023 12:57:44 +0800 Subject: [PATCH 089/109] Hotfix on incorrect condition on login button --- src/routes/Login/Login.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/Login/Login.tsx b/src/routes/Login/Login.tsx index 9aa4422..7ff7900 100644 --- a/src/routes/Login/Login.tsx +++ b/src/routes/Login/Login.tsx @@ -77,7 +77,7 @@ export default function Login() { + ) : ( + <> + )} ); From a0d27aaa38be71e3aa2e529b9b94c344fb825e7f Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Thu, 19 Oct 2023 18:53:54 +0800 Subject: [PATCH 091/109] Convert onboarding dropdown menus into modals --- src/routes/Onboarding/Onboarding.tsx | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/routes/Onboarding/Onboarding.tsx b/src/routes/Onboarding/Onboarding.tsx index 89952de..cd42ee4 100644 --- a/src/routes/Onboarding/Onboarding.tsx +++ b/src/routes/Onboarding/Onboarding.tsx @@ -195,7 +195,13 @@ export default function Onboarding() { ...styles.text_white_small_bold, ...{ textAlign: "center" }, }} - dropDownContainerStyle={{ backgroundColor: colors.primary_2 }} + modalContentContainerStyle={{ + backgroundColor: colors.primary_2, + borderWidth: 0, + zIndex: 1000, + }} + dropDownDirection="BOTTOM" + listMode="MODAL" /> Date: Thu, 19 Oct 2023 20:03:41 +0800 Subject: [PATCH 092/109] Move refresh button to the bottom alongside studying and group create buttons --- src/routes/Home/Home.tsx | 48 ++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index 26102d6..4473887 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -398,22 +398,6 @@ export default function Home() { if (dist <= 1 || map_distance_override) { return ( <> - - { - queryClient.invalidateQueries({ queryKey: ["user"] }); - queryClient.invalidateQueries({ queryKey: ["user_status"] }); - queryClient.invalidateQueries({ - queryKey: ["user_status_list"], - }); - queryClient.invalidateQueries({ - queryKey: ["study_group_list"], - }); - }} - > - - - {buttonLabel} + + { + queryClient.invalidateQueries({ queryKey: ["user"] }); + queryClient.invalidateQueries({ + queryKey: ["user_status"], + }); + queryClient.invalidateQueries({ + queryKey: ["user_status_list"], + }); + queryClient.invalidateQueries({ + queryKey: ["study_group_list"], + }); + toast.show("Refreshed", { + type: "success", + placement: "top", + duration: 2000, + animationType: "slide-in", + }); + }} + > + + + Date: Thu, 19 Oct 2023 20:04:37 +0800 Subject: [PATCH 093/109] Add spacing between entries in list view --- src/routes/Home/Home.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index 4473887..9ee173d 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -986,6 +986,7 @@ export default function Home() { borderWidth: 1, borderRadius: 16, width: 256, + marginVertical: 4, }} > @@ -1018,6 +1019,7 @@ export default function Home() { borderWidth: 1, borderRadius: 16, width: 256, + marginVertical: 4, }} > From 6564b52dc0bfa87f50ba78df765ab5034382550f Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Sun, 22 Oct 2023 00:57:01 +0800 Subject: [PATCH 094/109] Bump expo version --- package-lock.json | 1403 ++------------------------------------------- package.json | 2 +- 2 files changed, 35 insertions(+), 1370 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4090833..9820066 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "moment": "^2.29.4", "moti": "^0.25.3", "react": "18.2.0", - "react-native": "0.71.13", + "react-native": "0.71.14", "react-native-bouncy-checkbox": "^3.0.7", "react-native-dropdown-picker": "^5.4.6", "react-native-gesture-handler": "~2.9.0", @@ -393,9 +393,9 @@ } }, "node_modules/@babel/helper-validator-option": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", - "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", + "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", "engines": { "node": ">=6.9.0" } @@ -1866,12 +1866,12 @@ } }, "node_modules/@babel/preset-flow": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.22.5.tgz", - "integrity": "sha512-ta2qZ+LSiGCrP5pgcGt8xMnnkXQrq8Sa4Ulhy06BOlF5QbLw9q5hIx7bn5MrsvyTGAfh6kTOo07Q+Pfld/8Y5Q==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.22.15.tgz", + "integrity": "sha512-dB5aIMqpkgbTfN5vDdTRPzjqtWiZcRESNR88QYnoPR+bmdYoluOzMX9tQerTv0XzSgZYctPfO1oc0N5zdog1ew==", "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-validator-option": "^7.22.5", + "@babel/helper-validator-option": "^7.22.15", "@babel/plugin-transform-flow-strip-types": "^7.22.5" }, "engines": { @@ -1915,9 +1915,9 @@ } }, "node_modules/@babel/register": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.22.5.tgz", - "integrity": "sha512-vV6pm/4CijSQ8Y47RH5SopXzursN35RQINfGJkmOlcpAtGuf94miFvIPhCKGQN7WGIcsgG1BHEX2KVdTYwTwUQ==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.22.15.tgz", + "integrity": "sha512-V3Q3EqoQdn65RCgTLwauZaTfd1ShhwPmbBv+1dkZV/HpCGMKVyn6oFcRlI7RaKqiDQjX2Qd3AuoEguBgdjIKlg==", "dependencies": { "clone-deep": "^4.0.1", "find-cache-dir": "^2.0.0", @@ -5436,30 +5436,6 @@ "sprintf-js": "~1.0.2" } }, - "node_modules/arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -5468,14 +5444,6 @@ "node": ">=8" } }, - "node_modules/array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", @@ -5493,18 +5461,10 @@ "util": "^0.12.5" } }, - "node_modules/assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/ast-types": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.14.2.tgz", - "integrity": "sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==", + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.15.2.tgz", + "integrity": "sha512-c27loCv9QkZinsa5ProX751khO9DJl/AcB5c2KNtA6NRvHKS0PgLfcftz72KVq504vB0Gku5s2kUZzDBvQWvHg==", "dependencies": { "tslib": "^2.0.1" }, @@ -5543,17 +5503,6 @@ "node": ">= 4.0.0" } }, - "node_modules/atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "bin": { - "atob": "bin/atob.js" - }, - "engines": { - "node": ">= 4.5.0" - } - }, "node_modules/available-typed-arrays": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", @@ -5718,34 +5667,6 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, - "node_modules/base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dependencies": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -6089,25 +6010,6 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, - "node_modules/cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dependencies": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -6223,96 +6125,6 @@ "node": ">=8" } }, - "node_modules/class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dependencies": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -6428,18 +6240,6 @@ "node": ">=6" } }, - "node_modules/collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", - "dependencies": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/color": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", @@ -6529,11 +6329,6 @@ "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz", "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==" }, - "node_modules/component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" - }, "node_modules/component-type": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/component-type/-/component-type-1.2.1.tgz", @@ -6633,14 +6428,6 @@ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" }, - "node_modules/copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/core-js-compat": { "version": "3.31.0", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.31.0.tgz", @@ -6896,18 +6683,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/del": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", @@ -7223,131 +6998,6 @@ "node": ">=6" } }, - "node_modules/expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", - "dependencies": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/expand-brackets/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, "node_modules/expo": { "version": "48.0.19", "resolved": "https://registry.npmjs.org/expo/-/expo-48.0.19.tgz", @@ -7691,66 +7341,6 @@ "expo": "*" } }, - "node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dependencies": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -8004,14 +7594,6 @@ "is-callable": "^1.1.3" } }, - "node_modules/for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/form-data": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", @@ -8025,17 +7607,6 @@ "node": ">= 6" } }, - "node_modules/fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", - "dependencies": { - "map-cache": "^0.2.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/framer-motion": { "version": "6.5.1", "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-6.5.1.tgz", @@ -8176,14 +7747,6 @@ "node": ">=6" } }, - "node_modules/get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/getenv": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/getenv/-/getenv-1.0.0.tgz", @@ -8353,64 +7916,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", - "dependencies": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", - "dependencies": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values/node_modules/kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/hermes-estree": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.8.0.tgz", @@ -8674,17 +8179,6 @@ "node": ">= 0.10" } }, - "node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-arguments": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", @@ -8732,30 +8226,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-directory": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", @@ -8778,17 +8248,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -8978,14 +8437,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -9658,9 +9109,9 @@ "integrity": "sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q==" }, "node_modules/jscodeshift": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.13.1.tgz", - "integrity": "sha512-lGyiEbGOvmMRKgWk4vf+lUrCWO/8YR8sUR3FKF1Cq5fovjZDlIcw3Hu5ppLHAnEXshVffvaM0eyuY/AbOeYpnQ==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.14.0.tgz", + "integrity": "sha512-7eCC1knD7bLUPuSCwXsMZUH51O8jIcoVyKtI6P0XM0IVzlGjckPy3FIwQlorzbN0Sg79oK+RlohN32Mqf/lrYA==", "dependencies": { "@babel/core": "^7.13.16", "@babel/parser": "^7.13.16", @@ -9675,10 +9126,10 @@ "chalk": "^4.1.2", "flow-parser": "0.*", "graceful-fs": "^4.2.4", - "micromatch": "^3.1.10", + "micromatch": "^4.0.4", "neo-async": "^2.5.0", "node-dir": "^0.1.17", - "recast": "^0.20.4", + "recast": "^0.21.0", "temp": "^0.8.4", "write-file-atomic": "^2.3.0" }, @@ -9703,37 +9154,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jscodeshift/node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dependencies": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jscodeshift/node_modules/braces/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/jscodeshift/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -9765,31 +9185,6 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "node_modules/jscodeshift/node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", - "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jscodeshift/node_modules/fill-range/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/jscodeshift/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -9798,59 +9193,6 @@ "node": ">=8" } }, - "node_modules/jscodeshift/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jscodeshift/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jscodeshift/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jscodeshift/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/jscodeshift/node_modules/rimraf": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", @@ -9884,18 +9226,6 @@ "node": ">=6.0.0" } }, - "node_modules/jscodeshift/node_modules/to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", - "dependencies": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -10078,9 +9408,9 @@ } }, "node_modules/make-dir/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "bin": { "semver": "bin/semver" } @@ -10093,25 +9423,6 @@ "tmpl": "1.0.5" } }, - "node_modules/map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", - "dependencies": { - "object-visit": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/match-sorter": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/match-sorter/-/match-sorter-6.3.1.tgz", @@ -11172,18 +10483,6 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, - "node_modules/mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dependencies": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/mkdirp": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", @@ -11296,27 +10595,6 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/ncp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", @@ -11484,84 +10762,6 @@ "node": ">=0.10.0" } }, - "node_modules/object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", - "dependencies": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/is-descriptor/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/object-inspect": { "version": "1.12.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", @@ -11593,17 +10793,6 @@ "node": ">= 0.4" } }, - "node_modules/object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", - "dependencies": { - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/object.assign": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", @@ -11621,17 +10810,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/oblivious-set": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/oblivious-set/-/oblivious-set-1.0.0.tgz", @@ -11821,14 +10999,6 @@ "node": ">= 0.8" } }, - "node_modules/pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/password-prompt": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/password-prompt/-/password-prompt-1.1.2.tgz", @@ -12069,14 +11239,6 @@ "tslib": "^2.1.0" } }, - "node_modules/posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/pretty-bytes": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", @@ -12368,9 +11530,9 @@ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, "node_modules/react-native": { - "version": "0.71.13", - "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.71.13.tgz", - "integrity": "sha512-zEa69YQNLdv8Sf5Pn0CNDB1K9eGuNy1KoMNxXlrZ89JZ8d02b5hihZIoOCCIwhH+iPgslYwr3ZoGd3AY6FMrgw==", + "version": "0.71.14", + "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.71.14.tgz", + "integrity": "sha512-7uhzas8aKpU2EARhlONt7yiclh+7PXEOJk469ewpQyId8Owq5WNtZvQm/z3k4mHUriMeQ37vgSGkOInSKcCazw==", "dependencies": { "@jest/create-cache-key-function": "^29.2.1", "@react-native-community/cli": "10.2.4", @@ -12397,7 +11559,7 @@ "pretty-format": "^26.5.2", "promise": "^8.3.0", "react-devtools-core": "^4.26.1", - "react-native-codegen": "^0.71.5", + "react-native-codegen": "^0.71.6", "react-native-gradle-plugin": "^0.71.19", "react-refresh": "^0.4.0", "react-shallow-renderer": "^16.15.0", @@ -12436,13 +11598,13 @@ } }, "node_modules/react-native-codegen": { - "version": "0.71.5", - "resolved": "https://registry.npmjs.org/react-native-codegen/-/react-native-codegen-0.71.5.tgz", - "integrity": "sha512-rfsuc0zkuUuMjFnrT55I1mDZ+pBRp2zAiRwxck3m6qeGJBGK5OV5JH66eDQ4aa+3m0of316CqrJDRzVlYufzIg==", + "version": "0.71.6", + "resolved": "https://registry.npmjs.org/react-native-codegen/-/react-native-codegen-0.71.6.tgz", + "integrity": "sha512-e5pR4VldIhEaFctfSAEgxbng0uG4gjBQxAHes3EKLdosH/Av90pQfSe9IDVdFIngvNPzt8Y14pNjrtqov/yNIg==", "dependencies": { "@babel/parser": "^7.14.0", "flow-parser": "^0.185.0", - "jscodeshift": "^0.13.1", + "jscodeshift": "^0.14.0", "nullthrows": "^1.1.1" } }, @@ -12708,11 +11870,11 @@ "integrity": "sha512-k2d6ACCkiNYz222Fs/iNze30rRJ1iIicW7JuX/7/cozvih6YCkFZH+J6mAFDVgv0dRBaAyr4jDqC95R2y4IADg==" }, "node_modules/recast": { - "version": "0.20.5", - "resolved": "https://registry.npmjs.org/recast/-/recast-0.20.5.tgz", - "integrity": "sha512-E5qICoPoNL4yU0H0NoBDntNB0Q5oMSNh9usFctYniLBluTthi3RsQVBXIJNbApOlvSwW/RGxIuokPcAc59J5fQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.21.5.tgz", + "integrity": "sha512-hjMmLaUXAm1hIuTqOdeYObMslq/q+Xff6QE3Y2P+uoHAg2nmVlLBps2hzh1UJDdMtDTMXOFewK6ky51JQIeECg==", "dependencies": { - "ast-types": "0.14.2", + "ast-types": "0.15.2", "esprima": "~4.0.0", "source-map": "~0.6.1", "tslib": "^2.0.1" @@ -12774,18 +11936,6 @@ "@babel/runtime": "^7.8.4" } }, - "node_modules/regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dependencies": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/regexpu-core": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", @@ -12831,22 +11981,6 @@ "resolved": "https://registry.npmjs.org/remove-trailing-slash/-/remove-trailing-slash-0.1.1.tgz", "integrity": "sha512-o4S4Qh6L2jpnCy83ysZDau+VORNvnFw07CKSAymkd6ICNVEPisMyzlc00KlvvicsxKck94SEwhDnMNdICzO+tA==" }, - "node_modules/repeat-element": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", - "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", - "engines": { - "node": ">=0.10" - } - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -12923,12 +12057,6 @@ "node": ">=8" } }, - "node_modules/resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", - "deprecated": "https://github.com/lydell/resolve-url#deprecated" - }, "node_modules/restore-cursor": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", @@ -12941,14 +12069,6 @@ "node": ">=4" } }, - "node_modules/ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "engines": { - "node": ">=0.12" - } - }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -13002,14 +12122,6 @@ "integrity": "sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==", "optional": true }, - "node_modules/safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", - "dependencies": { - "ret": "~0.1.10" - } - }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -13129,39 +12241,6 @@ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" }, - "node_modules/set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dependencies": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/set-value/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/set-value/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", @@ -13296,186 +12375,6 @@ "node": ">=8.0.0" } }, - "node_modules/snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dependencies": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dependencies": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dependencies": { - "kind-of": "^3.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-util/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/snapdragon/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/snapdragon/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/source-map": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", @@ -13484,19 +12383,6 @@ "node": ">= 8" } }, - "node_modules/source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", - "dependencies": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, "node_modules/source-map-support": { "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", @@ -13514,12 +12400,6 @@ "node": ">=0.10.0" } }, - "node_modules/source-map-url": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", - "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", - "deprecated": "See https://github.com/lydell/source-map-url#deprecated" - }, "node_modules/split": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", @@ -13539,17 +12419,6 @@ "node": ">=6" } }, - "node_modules/split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dependencies": { - "extend-shallow": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -13609,94 +12478,6 @@ "node": ">=8" } }, - "node_modules/static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", - "dependencies": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -14144,42 +12925,6 @@ "node": ">=4" } }, - "node_modules/to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-object-path/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dependencies": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -14354,28 +13099,6 @@ "resolved": "https://registry.npmjs.org/unimodules-app-loader/-/unimodules-app-loader-4.1.2.tgz", "integrity": "sha512-DLYUCjNpguFhNpxNsBf47NWZi2OjIfWCVQY4f+r4/bwIqFfR7qQd6lXwCFA8EhHS1ti87CBzjMSbIC5bB0J/0Q==" }, - "node_modules/union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dependencies": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/union-value/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/unique-filename": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", @@ -14428,50 +13151,6 @@ "node": ">= 0.8" } }, - "node_modules/unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", - "dependencies": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", - "dependencies": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", - "dependencies": { - "isarray": "1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/update-browserslist-db": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", @@ -14501,12 +13180,6 @@ "browserslist": ">= 4.21.0" } }, - "node_modules/urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==", - "deprecated": "Please see https://github.com/lydell/urix#deprecated" - }, "node_modules/url-join": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.0.tgz", @@ -14521,14 +13194,6 @@ "requires-port": "^1.0.0" } }, - "node_modules/use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/use-latest-callback": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/use-latest-callback/-/use-latest-callback-0.1.6.tgz", diff --git a/package.json b/package.json index a6f2646..0dd96da 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "moment": "^2.29.4", "moti": "^0.25.3", "react": "18.2.0", - "react-native": "0.71.13", + "react-native": "0.71.14", "react-native-bouncy-checkbox": "^3.0.7", "react-native-dropdown-picker": "^5.4.6", "react-native-gesture-handler": "~2.9.0", From 3891f12f5d6fde16d4df7adc6a2b186bbd6592e0 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Fri, 27 Oct 2023 20:52:49 +0800 Subject: [PATCH 095/109] Redirect to conversations page instead of homepage when joining or creating a study group --- src/routes/CreateGroup/CreateGroup.tsx | 4 ++-- src/routes/Home/Home.tsx | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/routes/CreateGroup/CreateGroup.tsx b/src/routes/CreateGroup/CreateGroup.tsx index 904d472..aee9326 100644 --- a/src/routes/CreateGroup/CreateGroup.tsx +++ b/src/routes/CreateGroup/CreateGroup.tsx @@ -82,9 +82,9 @@ export default function CreateGroup({ route }: any) { duration: 2000, animationType: "slide-in", }); - // Set a delay before going back to homepage to hopefully let the queries refresh in time + // Set a delay before going back to conversation page to hopefully let the queries refresh in time setTimeout(() => { - navigation.navigate("Home"); + navigation.navigate("Conversation"); }, 200); }, onError: (error: Error) => { diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index 9ee173d..063b8b3 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -47,7 +47,7 @@ import RefreshIcon from "../../icons/RefreshIcon/RefreshIcon"; export default function Home() { // Switch this condition to see the main map when debugging - const map_distance_override = false; + const map_distance_override = true; const navigation = useNavigation(); const [location, setLocation] = useState(null); const [locationPermitted, setLocationPermitted] = useState(false); @@ -228,6 +228,7 @@ export default function Home() { duration: 2000, animationType: "slide-in", }); + navigation.navigate("Conversation"); } queryClient.invalidateQueries({ queryKey: ["user_status"] }); From bd42b5418e734913ded42bbed9542b2ae350e539 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Fri, 27 Oct 2023 21:16:43 +0800 Subject: [PATCH 096/109] Allow register and create group page to be scrollable when onscreen keyboard is open --- src/routes/CreateGroup/CreateGroup.tsx | 5 +++-- src/routes/Register/Register.tsx | 1 + src/styles.tsx | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/routes/CreateGroup/CreateGroup.tsx b/src/routes/CreateGroup/CreateGroup.tsx index aee9326..26b30de 100644 --- a/src/routes/CreateGroup/CreateGroup.tsx +++ b/src/routes/CreateGroup/CreateGroup.tsx @@ -24,6 +24,7 @@ import MapView, { UrlTile, Marker } from "react-native-maps"; import { useNavigation } from "@react-navigation/native"; import { useToast } from "react-native-toast-notifications"; import CaretLeftIcon from "../../icons/CaretLeftIcon/CaretLeftIcon"; +import AnimatedContainer from "../../components/AnimatedContainer/AnimatedContainer"; export default function CreateGroup({ route }: any) { const { location, subject } = route.params; @@ -100,7 +101,7 @@ export default function CreateGroup({ route }: any) { if (location) { return ( - + @@ -183,7 +184,7 @@ export default function CreateGroup({ route }: any) { - + ); } diff --git a/src/routes/Register/Register.tsx b/src/routes/Register/Register.tsx index f9ac188..98a46ce 100644 --- a/src/routes/Register/Register.tsx +++ b/src/routes/Register/Register.tsx @@ -17,6 +17,7 @@ import { UserRegister } from "../../components/Api/Api"; import IsNumber from "../../components/IsNumber/IsNumber"; import AnimatedContainer from "../../components/AnimatedContainer/AnimatedContainer"; import { useToast } from "react-native-toast-notifications"; +import { ScrollView } from "react-native-gesture-handler"; export default function Register() { const navigation = useNavigation(); diff --git a/src/styles.tsx b/src/styles.tsx index af0d3fa..71beda4 100644 --- a/src/styles.tsx +++ b/src/styles.tsx @@ -44,8 +44,9 @@ const styles = StyleSheet.create({ justifyContent: "center", display: "flex", flexDirection: "column", - flex: 1, + flexGrow: 1, paddingHorizontal: 4, + paddingVertical: 32, }, flex_row: { display: "flex", From 88d8ce05b88719937b212d049b1d27a8ad7fea34 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Fri, 27 Oct 2023 21:43:34 +0800 Subject: [PATCH 097/109] Possible fix to race conditions between queries in homepage which resulted in laggy rerenders of map --- src/routes/Home/Home.tsx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index 063b8b3..1cbcdc2 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -381,12 +381,14 @@ export default function Home() { ); } else if ( - (StudentStatusQuery.isFetching && studying) || - StudentStatusListQuery.isFetching || - StudyGroupQuery.isFetching || - (StudentStatusQuery.isFetching && !studying) || - StudentStatusListGlobalQuery.isFetching || - StudyGroupGlobalQuery.isFetching + (!StudentStatusQuery.isSuccess && + studying && + !StudentStatusListQuery.isSuccess && + !StudyGroupQuery.isSuccess && + !StudentStatusQuery.isSuccess) || + (!studying && + !StudentStatusListGlobalQuery.isSuccess && + !StudyGroupGlobalQuery.isSuccess) ) { return ( <> From a65a3a84aad94ccff4b07eb26a7989ce79774476 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Fri, 27 Oct 2023 22:03:46 +0800 Subject: [PATCH 098/109] Added enter button to conversation page and fixed error not properly displaying when sending an invalid message. Also added refresh interval of 20 seconds to study group query in conversations page to automatically refresh students count --- src/icons/CaretLeftIcon/CaretLeftIcon.tsx | 6 +- src/icons/CaretRightIcon/CaretLeftIcon.tsx | 28 +++++++++ .../ConversationPage/ConversationPage.tsx | 58 +++++++++++++------ 3 files changed, 70 insertions(+), 22 deletions(-) create mode 100644 src/icons/CaretRightIcon/CaretLeftIcon.tsx diff --git a/src/icons/CaretLeftIcon/CaretLeftIcon.tsx b/src/icons/CaretLeftIcon/CaretLeftIcon.tsx index e2caaa5..d6f2c5c 100644 --- a/src/icons/CaretLeftIcon/CaretLeftIcon.tsx +++ b/src/icons/CaretLeftIcon/CaretLeftIcon.tsx @@ -3,7 +3,7 @@ import { IconProps } from "../../interfaces/Interfaces"; import { Svg, Path } from "react-native-svg"; import { colors } from "../../styles"; -export default function CaretLeftIcon(props: IconProps) { +export default function CaretRightIcon(props: IconProps) { return ( <> diff --git a/src/icons/CaretRightIcon/CaretLeftIcon.tsx b/src/icons/CaretRightIcon/CaretLeftIcon.tsx new file mode 100644 index 0000000..e2caaa5 --- /dev/null +++ b/src/icons/CaretRightIcon/CaretLeftIcon.tsx @@ -0,0 +1,28 @@ +import * as React from "react"; +import { IconProps } from "../../interfaces/Interfaces"; +import { Svg, Path } from "react-native-svg"; +import { colors } from "../../styles"; + +export default function CaretLeftIcon(props: IconProps) { + return ( + <> + + + + + + ); +} diff --git a/src/routes/ConversationPage/ConversationPage.tsx b/src/routes/ConversationPage/ConversationPage.tsx index b2fd297..5f433ef 100644 --- a/src/routes/ConversationPage/ConversationPage.tsx +++ b/src/routes/ConversationPage/ConversationPage.tsx @@ -1,5 +1,5 @@ import * as React from "react"; -import { ActivityIndicator, Image } from "react-native"; +import { ActivityIndicator, Image, Pressable } from "react-native"; import styles from "../../styles"; import { View, @@ -36,6 +36,7 @@ import AnimatedContainer from "../../components/AnimatedContainer/AnimatedContai import AsyncStorage from "@react-native-async-storage/async-storage"; import { useSelector } from "react-redux"; import { RootState } from "../../features/redux/Store/Store"; +import CaretRightIcon from "../../icons/CaretLeftIcon/CaretLeftIcon"; export default function ConversationPage() { const toast = useToast(); @@ -70,6 +71,7 @@ export default function ConversationPage() { enabled: student_status?.study_group != "" && student_status?.study_group != null, queryKey: ["study_group"], + refetchInterval: 20, queryFn: async () => { const data = await GetStudyGroup(student_status?.study_group || ""); if (data[0] == false) { @@ -162,7 +164,7 @@ export default function ConversationPage() { mutationFn: async (info: MessagePostType) => { const data = await PostMessage(info); if (data[0] != true) { - return Promise.reject(new Error()); + return Promise.reject(new Error(data[1])); } return data; }, @@ -293,23 +295,41 @@ export default function ConversationPage() { There are no messages )} - - ): void => { - setMessage(e.nativeEvent.text); - }} - onSubmitEditing={() => { - send_message.mutate({ - message_content: message, - }); - setMessage(""); - }} - /> + + + ): void => { + setMessage(e.nativeEvent.text); + }} + onSubmitEditing={() => { + send_message.mutate({ + message_content: message, + }); + setMessage(""); + }} + /> + { + send_message.mutate({ + message_content: message, + }); + setMessage(""); + }} + > + + + ); From 8a32d2b32ce0cb8aa2f9bd373a57c240b64dfc03 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Fri, 27 Oct 2023 22:06:52 +0800 Subject: [PATCH 099/109] Fixed left and right caret icons --- src/icons/CaretLeftIcon/CaretLeftIcon.tsx | 4 ++-- .../{CaretLeftIcon.tsx => CaretRightIcon.tsx} | 2 +- src/routes/ConversationPage/ConversationPage.tsx | 8 +++++--- 3 files changed, 8 insertions(+), 6 deletions(-) rename src/icons/CaretRightIcon/{CaretLeftIcon.tsx => CaretRightIcon.tsx} (94%) diff --git a/src/icons/CaretLeftIcon/CaretLeftIcon.tsx b/src/icons/CaretLeftIcon/CaretLeftIcon.tsx index d6f2c5c..eb5655e 100644 --- a/src/icons/CaretLeftIcon/CaretLeftIcon.tsx +++ b/src/icons/CaretLeftIcon/CaretLeftIcon.tsx @@ -18,9 +18,9 @@ export default function CaretRightIcon(props: IconProps) { > diff --git a/src/icons/CaretRightIcon/CaretLeftIcon.tsx b/src/icons/CaretRightIcon/CaretRightIcon.tsx similarity index 94% rename from src/icons/CaretRightIcon/CaretLeftIcon.tsx rename to src/icons/CaretRightIcon/CaretRightIcon.tsx index e2caaa5..eb5655e 100644 --- a/src/icons/CaretRightIcon/CaretLeftIcon.tsx +++ b/src/icons/CaretRightIcon/CaretRightIcon.tsx @@ -3,7 +3,7 @@ import { IconProps } from "../../interfaces/Interfaces"; import { Svg, Path } from "react-native-svg"; import { colors } from "../../styles"; -export default function CaretLeftIcon(props: IconProps) { +export default function CaretRightIcon(props: IconProps) { return ( <> { const data = await GetStudyGroup(student_status?.study_group || ""); if (data[0] == false) { @@ -129,7 +129,7 @@ export default function ConversationPage() { // Avatar List const [users, setUsers] = useState([]); const AvatarsQuery = useQuery({ - refetchInterval: 3000, + refetchInterval: 10000, enabled: student_status?.study_group != null || (student_status?.study_group != "" && @@ -211,7 +211,9 @@ export default function ConversationPage() { paddingRight: 4, }} > - {studygroup.students.length} studying + {!StudyGroupQuery.isFetching + ? studygroup.students.length + " studying" + : "Loading"} {users.map((user: GroupMessageAvatarType, index: number) => { if (index > 6) { From 856621fe06b1916746b4429658ca9e46b042aee3 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Fri, 27 Oct 2023 22:16:23 +0800 Subject: [PATCH 100/109] Remove a redundant refresh on load as it prevented users from overriding their location --- src/routes/Home/Home.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index 1cbcdc2..bf65cfd 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -97,7 +97,6 @@ export default function Home() { } // Refresh every 10 seconds - requestLocation(); useEffect(() => { const interval = setInterval(() => { requestLocation(); From 5d7327ef267dee69bcc5e7a60c560ae75ec8f9c6 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Fri, 27 Oct 2023 23:13:41 +0800 Subject: [PATCH 101/109] Do not redirect to conversations page if leaving a group --- .../DrawerSettings/CustomDrawerContent.tsx | 4 +- src/routes/Home/Home.tsx | 43 +++++++++---------- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/src/components/DrawerSettings/CustomDrawerContent.tsx b/src/components/DrawerSettings/CustomDrawerContent.tsx index 48c31e2..61ec820 100644 --- a/src/components/DrawerSettings/CustomDrawerContent.tsx +++ b/src/components/DrawerSettings/CustomDrawerContent.tsx @@ -27,7 +27,7 @@ import { useToast } from "react-native-toast-notifications"; import MessageIcon from "../../icons/MessageIcon/MessageIcon"; export default function CustomDrawerContent(props: {}) { - const debug = false; + const debug = true; const navigation = useNavigation(); const status = useSelector((state: RootState) => state.status); const dispatch = useDispatch(); @@ -143,7 +143,7 @@ export default function CustomDrawerContent(props: {}) { { // We don't clear student statuses when logging out on debug - if (!debug) { + if (debug) { queryClient.clear(); dispatch(logout()); await AsyncStorage.clear(); diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index bf65cfd..b7c6e12 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -61,7 +61,7 @@ export default function Home() { const [modalOpen, setModalOpen] = useState(false); const [modalByGroup, setModalByGroup] = useState(false); - async function requestLocation() { + async function requestLocationPermission() { const { status } = await Location.requestForegroundPermissionsAsync(); if (status !== "granted") { setFeedback("Allow location permissions to continue"); @@ -75,12 +75,13 @@ export default function Home() { } ); return; + } else { + setLocationPermitted(true); } - if (status == "granted") { - if (locationPermitted === false) { - setLocationPermitted(true); - } + } + async function requestLocation() { + if (locationPermitted) { let newLocation = await Location.getCurrentPositionAsync(); if (newLocation) { // Only update location state if user's location has changed @@ -96,22 +97,18 @@ export default function Home() { } } - // Refresh every 10 seconds useEffect(() => { + console.log("changed"); + console.log(locationPermitted); + requestLocation(); + }, [locationPermitted]); + + useEffect(() => { + requestLocationPermission(); + // Refresh every 30 seconds const interval = setInterval(() => { requestLocation(); }, 30000); - setTimeout(() => { - queryClient.invalidateQueries({ queryKey: ["user"] }); - queryClient.invalidateQueries({ queryKey: ["user_status"] }); - queryClient.invalidateQueries({ - queryKey: ["user_status_list"], - }); - queryClient.invalidateQueries({ - queryKey: ["study_group_list"], - }); - requestLocation(); - }, 2000); return () => clearInterval(interval); }, []); @@ -219,7 +216,7 @@ export default function Home() { return data; }, onSuccess: () => { - if (student_status?.study_group) { + if (student_status?.study_group == "") { // Display separate toast if you stop studying while in a study group toast.show("You left study group \n" + student_status?.study_group, { type: "success", @@ -227,8 +224,8 @@ export default function Home() { duration: 2000, animationType: "slide-in", }); - navigation.navigate("Conversation"); } + queryClient.invalidateQueries({ queryKey: ["user_status"] }); // Delay refetching for study groups since backend still needs to delete groups without students after leaving a study group @@ -383,9 +380,9 @@ export default function Home() { (!StudentStatusQuery.isSuccess && studying && !StudentStatusListQuery.isSuccess && - !StudyGroupQuery.isSuccess && - !StudentStatusQuery.isSuccess) || - (!studying && + !StudyGroupQuery.isSuccess) || + (!StudentStatusQuery.isSuccess && + !studying && !StudentStatusListGlobalQuery.isSuccess && !StudyGroupGlobalQuery.isSuccess) ) { @@ -600,6 +597,7 @@ export default function Home() { study_group: studygroup.name, subject: studygroup.subject, }); + navigation.navigate("Conversation"); }} > @@ -1051,6 +1049,7 @@ export default function Home() { study_group: studygroup.name, subject: studygroup.subject, }); + navigation.navigate("Conversation"); setModalOpen(!modalOpen); }} > From 2603741aabf83baa1bbecac59747bc310504d670 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Sat, 28 Oct 2023 00:22:17 +0800 Subject: [PATCH 102/109] Turn off debug flags and clear study group messages notification cache when switching study groups --- src/components/DrawerSettings/CustomDrawerContent.tsx | 2 +- src/routes/Home/Home.tsx | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/components/DrawerSettings/CustomDrawerContent.tsx b/src/components/DrawerSettings/CustomDrawerContent.tsx index 61ec820..578d429 100644 --- a/src/components/DrawerSettings/CustomDrawerContent.tsx +++ b/src/components/DrawerSettings/CustomDrawerContent.tsx @@ -27,7 +27,7 @@ import { useToast } from "react-native-toast-notifications"; import MessageIcon from "../../icons/MessageIcon/MessageIcon"; export default function CustomDrawerContent(props: {}) { - const debug = true; + const debug = false; const navigation = useNavigation(); const status = useSelector((state: RootState) => state.status); const dispatch = useDispatch(); diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index b7c6e12..3769c06 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -44,10 +44,11 @@ import Modal from "react-native-modal"; import DropdownIcon from "../../icons/CaretDownIcon/CaretDownIcon"; import CaretUpIcon from "../../icons/CaretUpIcon/CaretUpIcon"; import RefreshIcon from "../../icons/RefreshIcon/RefreshIcon"; +import AsyncStorage from "@react-native-async-storage/async-storage"; export default function Home() { // Switch this condition to see the main map when debugging - const map_distance_override = true; + const map_distance_override = false; const navigation = useNavigation(); const [location, setLocation] = useState(null); const [locationPermitted, setLocationPermitted] = useState(false); @@ -125,6 +126,9 @@ export default function Home() { } } + async function clear_messages_notification_cache() { + AsyncStorage.setItem("messages", ""); + } // Student Status const [studying, setStudying] = useState(false); const [subject, setSubject] = useState(""); @@ -163,7 +167,7 @@ export default function Home() { mutationFn: async (info: StudentStatusPatchType) => { const data = await PatchStudentStatus(info); if (data[0] != true) { - return Promise.reject(new Error()); + return Promise.reject(new Error(JSON.stringify(data[1]))); } return data; }, @@ -224,6 +228,7 @@ export default function Home() { duration: 2000, animationType: "slide-in", }); + clear_messages_notification_cache(); } queryClient.invalidateQueries({ queryKey: ["user_status"] }); @@ -932,6 +937,8 @@ export default function Home() { return ; } } else { + requestLocationPermission(); + requestLocation(); return ( <> From 7cd549cad7cbfeb18458cec445083e4cc57fe667 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Thu, 23 Nov 2023 23:27:38 +0800 Subject: [PATCH 103/109] Refetch user location when refreshing and added code snippet to stop user from studying if they stray too far from where they set their studying locatio. Also allow modal to be shown even when not currently studying --- src/routes/Home/Home.tsx | 132 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 125 insertions(+), 7 deletions(-) diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index 3769c06..aa29b01 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -48,7 +48,7 @@ import AsyncStorage from "@react-native-async-storage/async-storage"; export default function Home() { // Switch this condition to see the main map when debugging - const map_distance_override = false; + const map_distance_override = true; const navigation = useNavigation(); const [location, setLocation] = useState(null); const [locationPermitted, setLocationPermitted] = useState(false); @@ -117,7 +117,7 @@ export default function Home() { async function DistanceHandler(location: RawLocationType) { let dist = GetDistanceFromUSTP(location.coords); setDist(dist); - // Deactivate student status if too far away and still studying + // Deactivate student status if too far away from USTP and still studying if (dist >= 2 && !map_distance_override && studying && !stopping_toofar) { stop_studying.mutate({ active: false, @@ -152,6 +152,28 @@ export default function Home() { setSubject(data[1].subject); setStudying(data[1].active); setStudentStatus(data[1]); + // Deactivate student status if too far away from current location you are studying in + if(student_status && location){ + const dist = GetDistance( + student_status.location.latitude, + student_status.location.longitude, + location.coords.latitude, + location.coords.longitude + ); + console.log('Distance:',dist) + console.log(student_status.location.latitude, + student_status.location.longitude, + location.coords.latitude, + location.coords.longitude) + if (dist > 0.02 && studying && !stopping_toofar) { + console.log('Too far from current studying location') + stop_studying.mutate({ + active: false, + }); + setStopping(true); + } + } + }, onError: (error: Error) => { toast.show(String(error), { @@ -197,9 +219,7 @@ export default function Home() { }, 500); setStudyGroups([]); setStudying(false); - if (stopping_toofar) { setStopping(false); - } }, onError: (error: Error) => { toast.show(String(error), { @@ -893,6 +913,7 @@ export default function Home() { duration: 2000, animationType: "slide-in", }); + requestLocation() }} > @@ -908,7 +929,7 @@ export default function Home() { setModalOpen(true); }} > - {studying ? : <>} + {student_status?.active && !student_status?.study_group ? ( @@ -967,14 +988,16 @@ export default function Home() { > - + + + List View { setModalByGroup(!modalByGroup); }} + style={{alignSelf:'center'}} /> - List View @@ -1096,7 +1119,102 @@ export default function Home() { + + + setModalOpen(false)} + > + + + + List View + { + setModalByGroup(!modalByGroup); + }} + style={{alignSelf:'center'}} + /> + + + + {!modalByGroup ? ( + student_statuses_global.map( + (student_status: StudentStatusFilterType, index: number) => { + return ( + + + Student: {student_status.user} + + + {`Studying ${student_status.subject}`} + + + ); + } + ) + ) : ( + <> + )} + {modalByGroup ? ( + study_groups_global.map((studygroup: StudyGroupType, index: number) => { + return ( + + + Group Name: {studygroup.name} + + + {`Studying ${studygroup.subject}`} + + + Students Studying: {studygroup.students.length} + + + ); + }) + ) : ( + <> + )} + + + From c0a8a8efc8bd6a554253c98d0df7f8fd110dafea Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Thu, 23 Nov 2023 23:29:27 +0800 Subject: [PATCH 104/109] Always refresh location when pressing refresh button --- src/routes/Home/Home.tsx | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index aa29b01..21ee76a 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -85,15 +85,8 @@ export default function Home() { if (locationPermitted) { let newLocation = await Location.getCurrentPositionAsync(); if (newLocation) { - // Only update location state if user's location has changed - if ( - !location || - newLocation.coords.latitude !== location.coords.latitude || - newLocation.coords.longitude !== location.coords.longitude - ) { setLocation(newLocation); - await DistanceHandler(newLocation); - } + await DistanceHandler(newLocation); } } } From 51b7b24430ca4b4817b0ac1833051b477a681f8b Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Fri, 24 Nov 2023 00:22:14 +0800 Subject: [PATCH 105/109] Show landmarks if it exists in homepage and in conversation page --- src/components/Api/Api.tsx | 2 +- .../ConversationPage/ConversationPage.tsx | 10 +- src/routes/Home/Home.tsx | 113 +++++++++++------- 3 files changed, 81 insertions(+), 44 deletions(-) diff --git a/src/components/Api/Api.tsx b/src/components/Api/Api.tsx index f5dc3d2..e6111a9 100644 --- a/src/components/Api/Api.tsx +++ b/src/components/Api/Api.tsx @@ -22,7 +22,7 @@ if (__DEV__) { } // Switch this on if you wanna run production URLs while in development -let use_production = true; +let use_production = false; if (__DEV__ && use_production) { backendURL = "https://stude.keannu1.duckdns.org"; backendURLWebsocket = "ws://stude.keannu1.duckdns.org"; diff --git a/src/routes/ConversationPage/ConversationPage.tsx b/src/routes/ConversationPage/ConversationPage.tsx index 6bec280..94cae27 100644 --- a/src/routes/ConversationPage/ConversationPage.tsx +++ b/src/routes/ConversationPage/ConversationPage.tsx @@ -200,9 +200,17 @@ export default function ConversationPage() { > - {`Group: ${studygroup?.name ? studygroup.name : ""}`} + {`Group: ${studygroup?.name ? studygroup.name : "Loading..."}`} + {studygroup.landmark ? ( + + {studygroup.landmark} + + ) : ( + <> + )} + 0.02 && studying && !stopping_toofar) { - console.log('Too far from current studying location') + console.log("Too far from current studying location"); stop_studying.mutate({ active: false, }); setStopping(true); } } - }, onError: (error: Error) => { toast.show(String(error), { @@ -212,7 +213,7 @@ export default function Home() { }, 500); setStudyGroups([]); setStudying(false); - setStopping(false); + setStopping(false); }, onError: (error: Error) => { toast.show(String(error), { @@ -591,6 +592,13 @@ export default function Home() { Study Group: {studygroup.name} + {studygroup.landmark ? ( + + {studygroup.landmark} + + ) : ( + <> + )} {`Studying ${studygroup.subject}`} @@ -698,6 +706,13 @@ export default function Home() { Study Group: {studygroup.name} + {studygroup.landmark ? ( + + {studygroup.landmark} + + ) : ( + <> + )} {`Studying ${studygroup.subject}`} @@ -906,7 +921,7 @@ export default function Home() { duration: 2000, animationType: "slide-in", }); - requestLocation() + requestLocation(); }} > @@ -982,14 +997,13 @@ export default function Home() { - List View { setModalByGroup(!modalByGroup); }} - style={{alignSelf:'center'}} + style={{ alignSelf: "center" }} /> @@ -1048,6 +1062,13 @@ export default function Home() { Group Name: {studygroup.name} + {studygroup.landmark ? ( + + {studygroup.landmark} + + ) : ( + <> + )} {`Studying ${studygroup.subject}`} @@ -1130,14 +1151,13 @@ export default function Home() { - List View { setModalByGroup(!modalByGroup); }} - style={{alignSelf:'center'}} + style={{ alignSelf: "center" }} /> @@ -1174,34 +1194,43 @@ export default function Home() { <> )} {modalByGroup ? ( - study_groups_global.map((studygroup: StudyGroupType, index: number) => { - return ( - - - Group Name: {studygroup.name} - - - {`Studying ${studygroup.subject}`} - - - Students Studying: {studygroup.students.length} - - - ); - }) + study_groups_global.map( + (studygroup: StudyGroupType, index: number) => { + return ( + + + Group Name: {studygroup.name} + + {studygroup.landmark ? ( + + {studygroup.landmark} + + ) : ( + <> + )} + + {`Studying ${studygroup.subject}`} + + + Students Studying: {studygroup.students.length} + + + ); + } + ) ) : ( <> )} From d2aecbd89cb90dc9b6ca9592e72223c601faf61d Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Fri, 24 Nov 2023 00:26:02 +0800 Subject: [PATCH 106/109] Turn off debug flags --- src/components/Api/Api.tsx | 2 +- src/routes/Home/Home.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Api/Api.tsx b/src/components/Api/Api.tsx index e6111a9..f5dc3d2 100644 --- a/src/components/Api/Api.tsx +++ b/src/components/Api/Api.tsx @@ -22,7 +22,7 @@ if (__DEV__) { } // Switch this on if you wanna run production URLs while in development -let use_production = false; +let use_production = true; if (__DEV__ && use_production) { backendURL = "https://stude.keannu1.duckdns.org"; backendURLWebsocket = "ws://stude.keannu1.duckdns.org"; diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index e27fdbf..d854b88 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -48,7 +48,7 @@ import AsyncStorage from "@react-native-async-storage/async-storage"; export default function Home() { // Switch this condition to see the main map when debugging - const map_distance_override = true; + const map_distance_override = false; const navigation = useNavigation(); const [location, setLocation] = useState(null); const [locationPermitted, setLocationPermitted] = useState(false); From cbd82a05f9423944d243182e6fb68856c98c812d Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Fri, 24 Nov 2023 21:14:33 +0800 Subject: [PATCH 107/109] Added callout information for study groups when pressing on maps and improved responsiveness of the homepage map renderer --- src/routes/Home/Home.tsx | 178 ++++++++++++++++++++++++++++++++++----- 1 file changed, 159 insertions(+), 19 deletions(-) diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index d854b88..efec988 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -6,10 +6,11 @@ import { ScrollView, Switch, ActivityIndicator, + TouchableHighlight, } from "react-native"; import AnimatedContainer from "../../components/AnimatedContainer/AnimatedContainer"; import { useState, useEffect } from "react"; -import MapView, { Circle, Marker, UrlTile } from "react-native-maps"; +import MapView, { Callout, Circle, Marker, UrlTile } from "react-native-maps"; import * as Location from "expo-location"; import GetDistance from "../../components/GetDistance/GetDistance"; import Button from "../../components/Button/Button"; @@ -45,10 +46,11 @@ import DropdownIcon from "../../icons/CaretDownIcon/CaretDownIcon"; import CaretUpIcon from "../../icons/CaretUpIcon/CaretUpIcon"; import RefreshIcon from "../../icons/RefreshIcon/RefreshIcon"; import AsyncStorage from "@react-native-async-storage/async-storage"; +import AnimatedContainerNoScroll from "../../components/AnimatedContainer/AnimatedContainerNoScroll"; export default function Home() { // Switch this condition to see the main map when debugging - const map_distance_override = false; + const map_distance_override = true; const navigation = useNavigation(); const [location, setLocation] = useState(null); const [locationPermitted, setLocationPermitted] = useState(false); @@ -84,10 +86,10 @@ export default function Home() { async function requestLocation() { if (locationPermitted) { let newLocation = await Location.getCurrentPositionAsync(); - if (newLocation) { + setLocation(newLocation); await DistanceHandler(newLocation); - } + } } @@ -412,6 +414,19 @@ export default function Home() { Loading... ); + } else if ( + study_groups == undefined || + study_groups_global == undefined || + student_statuses == undefined|| + student_statuses_global == undefined + ) { + return ( + <> + + + Loading... + + ); } else if (dist && location) { if (dist <= 1 || map_distance_override) { return ( @@ -472,6 +487,7 @@ export default function Home() { zIndex={1000} onPress={() => { toast.hideAll(); + toast.show( + > + + + Student: {student_status.user} + + + {`Studying ${student_status.subject}`} + + + {`${Math.round( + GetDistance( + student_status.location.latitude, + student_status.location.longitude, + location.coords.latitude, + location.coords.longitude + ) * 1000 + )}m away`} + + + ); } ) @@ -581,6 +616,7 @@ export default function Home() { zIndex={1000} onPress={() => { toast.hideAll(); + toast.show( + > + + + Study Group: {studygroup.name} + + + Studying: {studygroup.subject} + + {studygroup.landmark ? ( + + {studygroup.landmark} + + ) : ( + <> + )} + + {`${studygroup.students.length} ${ + studygroup.students.length > 1 + ? "students" + : "student" + } studying`} + + + {`${Math.round( + studygroup.distance * 1000 + )}m away`} + + + + > + + + Study Group: {studygroup.name} + + + Studying: {studygroup.subject} + + {studygroup.landmark ? ( + + {studygroup.landmark} + + ) : ( + <> + )} + + {`${studygroup.students.length} ${ + studygroup.students.length > 1 + ? "students" + : "student" + } studying`} + + + {`${Math.round( + GetDistance( + studygroup.location.latitude, + studygroup.location.longitude, + location.coords.latitude, + location.coords.longitude + ) + )}m away`} + + + {`${Math.round(student_status.distance * 1000)}m away`} + {location && location.coords ? ( + + {`${Math.round( + GetDistance( + student_status.location.latitude, + student_status.location.longitude, + location.coords.latitude, + location.coords.longitude + ) + )}m away`} + + ) : ( + <> + )} ); } @@ -1063,12 +1174,12 @@ export default function Home() { Group Name: {studygroup.name} {studygroup.landmark ? ( - - {studygroup.landmark} - - ) : ( - <> - )} + + {studygroup.landmark} + + ) : ( + <> + )} {`Studying ${studygroup.subject}`} @@ -1186,6 +1297,20 @@ export default function Home() { {`Studying ${student_status.subject}`} + {location && location.coords ? ( + + {`${Math.round( + GetDistance( + student_status.location.latitude, + student_status.location.longitude, + location.coords.latitude, + location.coords.longitude + ) + )}m away`} + + ) : ( + <> + )} ); } @@ -1215,18 +1340,32 @@ export default function Home() { Group Name: {studygroup.name} {studygroup.landmark ? ( - - {studygroup.landmark} - - ) : ( - <> - )} + + {studygroup.landmark} + + ) : ( + <> + )} {`Studying ${studygroup.subject}`} Students Studying: {studygroup.students.length} + {location && location.coords ? ( + + {`${Math.round( + GetDistance( + studygroup.location.latitude, + studygroup.location.longitude, + location.coords.latitude, + location.coords.longitude + ) + )}m away`} + + ) : ( + <> + )} ); } @@ -1237,6 +1376,7 @@ export default function Home() { + From 05cee78d31ca07bf8dea431b78a7b9b333744621 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Fri, 24 Nov 2023 21:15:47 +0800 Subject: [PATCH 108/109] Format with Prettier and turn off debug flag --- src/routes/Home/Home.tsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index efec988..4197170 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -50,7 +50,7 @@ import AnimatedContainerNoScroll from "../../components/AnimatedContainer/Animat export default function Home() { // Switch this condition to see the main map when debugging - const map_distance_override = true; + const map_distance_override = false; const navigation = useNavigation(); const [location, setLocation] = useState(null); const [locationPermitted, setLocationPermitted] = useState(false); @@ -87,9 +87,8 @@ export default function Home() { if (locationPermitted) { let newLocation = await Location.getCurrentPositionAsync(); - setLocation(newLocation); - await DistanceHandler(newLocation); - + setLocation(newLocation); + await DistanceHandler(newLocation); } } @@ -417,7 +416,7 @@ export default function Home() { } else if ( study_groups == undefined || study_groups_global == undefined || - student_statuses == undefined|| + student_statuses == undefined || student_statuses_global == undefined ) { return ( From 0b3af716a5fecc97df1a63a1b4625567316f6a1f Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Sun, 10 Dec 2023 22:50:53 +0800 Subject: [PATCH 109/109] limit studying to within 250m of the center of ustp --- src/routes/Home/Home.tsx | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx index 4197170..ea7a5a1 100644 --- a/src/routes/Home/Home.tsx +++ b/src/routes/Home/Home.tsx @@ -93,8 +93,8 @@ export default function Home() { } useEffect(() => { - console.log("changed"); - console.log(locationPermitted); + // console.log("Location Update"); + // console.log(locationPermitted); requestLocation(); }, [locationPermitted]); @@ -112,7 +112,7 @@ export default function Home() { let dist = GetDistanceFromUSTP(location.coords); setDist(dist); // Deactivate student status if too far away from USTP and still studying - if (dist >= 2 && !map_distance_override && studying && !stopping_toofar) { + if (dist >= 1 && !map_distance_override && studying && !stopping_toofar) { stop_studying.mutate({ active: false, }); @@ -154,14 +154,7 @@ export default function Home() { location.coords.latitude, location.coords.longitude ); - console.log("Distance:", dist); - console.log( - student_status.location.latitude, - student_status.location.longitude, - location.coords.latitude, - location.coords.longitude - ); - if (dist > 0.02 && studying && !stopping_toofar) { + if (dist > 0.5 && studying && !stopping_toofar) { console.log("Too far from current studying location"); stop_studying.mutate({ active: false, @@ -427,7 +420,7 @@ export default function Home() { ); } else if (dist && location) { - if (dist <= 1 || map_distance_override) { + if (dist <= 0.25 || map_distance_override) { return ( <>