Code improvements, clear react query cache on logout and added joining/changing study group functionality on homepage

This commit is contained in:
Keannu Bernasol 2023-09-29 12:23:44 +08:00
parent 709125a344
commit c2c589a3fe
4 changed files with 358 additions and 303 deletions

View file

@ -2,6 +2,7 @@ import axios from "axios";
import AsyncStorage from "@react-native-async-storage/async-storage"; import AsyncStorage from "@react-native-async-storage/async-storage";
import { import {
ActivationType, ActivationType,
LocationType,
LoginType, LoginType,
OnboardingType, OnboardingType,
PatchUserInfoType, PatchUserInfoType,
@ -87,7 +88,6 @@ export async function GetConfig() {
// User APIs // User APIs
export function UserRegister(register: RegistrationType) { export function UserRegister(register: RegistrationType) {
console.log(JSON.stringify(register));
return instance return instance
.post("/api/v1/accounts/users/", register) .post("/api/v1/accounts/users/", register)
.then(async (response) => { .then(async (response) => {
@ -148,7 +148,6 @@ export async function PatchUserInfo(info: PatchUserInfoType) {
return instance return instance
.patch("/api/v1/accounts/users/me/", info, config) .patch("/api/v1/accounts/users/me/", info, config)
.then((response) => { .then((response) => {
console.log(JSON.stringify(response.data));
return [true, response.data]; return [true, response.data];
}) })
.catch((error) => { .catch((error) => {
@ -255,7 +254,6 @@ export async function PatchStudentStatus(info: StudentStatusPatchType) {
}) })
.catch((error) => { .catch((error) => {
let error_message = ParseError(error); let error_message = ParseError(error);
console.log("Error!", error.response.data);
return [false, error_message]; return [false, error_message];
}); });
} }
@ -273,12 +271,11 @@ export async function GetStudentStatusList() {
}); });
} }
export async function GetStudentStatusListFiltered() { export async function GetStudentStatusListNear() {
const config = await GetConfig(); const config = await GetConfig();
return instance return instance
.get("/api/v1/student_status/filter/near_student_status", config) .get("/api/v1/student_status/near/", config)
.then((response) => { .then((response) => {
console.log("test", response.data);
return [true, response.data]; return [true, response.data];
}) })
.catch((error) => { .catch((error) => {
@ -288,10 +285,18 @@ export async function GetStudentStatusListFiltered() {
} }
// To-do // To-do
export async function GetStudentStatusListFilteredCurrentLocation() { export async function GetStudentStatusListFilteredCurrentLocation(
location: LocationType
) {
const config = await GetConfig(); const config = await GetConfig();
return instance return instance
.get("/api/v1/student_status/list/", config) .post(
"/api/v1/student_status/near_current_location/",
{
location: location,
},
config
)
.then((response) => { .then((response) => {
return [true, response.data]; return [true, response.data];
}) })
@ -329,7 +334,7 @@ export async function GetStudyGroupList() {
export async function CreateStudyGroup(info: StudyGroupCreateType) { export async function CreateStudyGroup(info: StudyGroupCreateType) {
const config = await GetConfig(); const config = await GetConfig();
console.log("Payload:", info); // console.log("Creating study group:", info);
return instance return instance
.post("/api/v1/study_groups/create/", info, config) .post("/api/v1/study_groups/create/", info, config)
.then((response) => { .then((response) => {

View file

@ -18,11 +18,13 @@ import { logout } from "../../features/redux/slices/StatusSlice/StatusSlice";
import AsyncStorage from "@react-native-async-storage/async-storage"; import AsyncStorage from "@react-native-async-storage/async-storage";
import UserIcon from "../../icons/UserIcon/UserIcon"; import UserIcon from "../../icons/UserIcon/UserIcon";
import SubjectIcon from "../../icons/SubjectIcon/SubjectIcon"; import SubjectIcon from "../../icons/SubjectIcon/SubjectIcon";
import { useQueryClient } from "@tanstack/react-query";
export default function CustomDrawerContent(props: {}) { export default function CustomDrawerContent(props: {}) {
const navigation = useNavigation<RootDrawerParamList>(); const navigation = useNavigation<RootDrawerParamList>();
const status = useSelector((state: RootState) => state.status); const status = useSelector((state: RootState) => state.status);
const dispatch = useDispatch(); const dispatch = useDispatch();
const queryClient = useQueryClient();
if (status.logged_in && status.onboarding) { if (status.logged_in && status.onboarding) {
return ( return (
<DrawerContentScrollView {...props}> <DrawerContentScrollView {...props}>
@ -40,6 +42,7 @@ export default function CustomDrawerContent(props: {}) {
onPress={async () => { onPress={async () => {
dispatch(logout()); dispatch(logout());
await AsyncStorage.clear(); await AsyncStorage.clear();
queryClient.clear();
navigation.navigate("Login"); navigation.navigate("Login");
}} }}
> >

View file

@ -3,31 +3,20 @@ import styles, { Viewport } from "../../styles";
import { import {
View, View,
Text, Text,
ToastAndroid,
TextInput, TextInput,
NativeSyntheticEvent, NativeSyntheticEvent,
TextInputChangeEventData, TextInputChangeEventData,
} from "react-native"; } from "react-native";
import { useState } from "react"; import { useState } from "react";
import { import {
UserInfoReturnType,
OptionType,
RootDrawerParamList, RootDrawerParamList,
StudentStatusType,
StudentStatusReturnType,
StudentStatusPatchType, StudentStatusPatchType,
StudyGroupCreateType, StudyGroupCreateType,
} from "../../interfaces/Interfaces"; } from "../../interfaces/Interfaces";
import Button from "../../components/Button/Button"; import Button from "../../components/Button/Button";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { useMutation, useQueryClient } from "@tanstack/react-query";
import { import { PatchStudentStatus, CreateStudyGroup } from "../../components/Api/Api";
PatchStudentStatus,
GetUserInfo,
ParseError,
CreateStudyGroup,
} from "../../components/Api/Api";
import { colors } from "../../styles"; import { colors } from "../../styles";
import DropDownPicker from "react-native-dropdown-picker";
import AnimatedContainerNoScroll from "../../components/AnimatedContainer/AnimatedContainerNoScroll"; import AnimatedContainerNoScroll from "../../components/AnimatedContainer/AnimatedContainerNoScroll";
import { urlProvider } from "../../components/Api/Api"; import { urlProvider } from "../../components/Api/Api";
import MapView, { UrlTile, Marker } from "react-native-maps"; import MapView, { UrlTile, Marker } from "react-native-maps";
@ -170,13 +159,6 @@ export default function CreateGroup({ route }: any) {
<View style={styles.padding} /> <View style={styles.padding} />
<Button <Button
onPress={() => { onPress={() => {
console.log({
group_name: name,
location: {
latitude: location.latitude,
longitude: location.longitude,
},
});
study_group_create.mutate({ study_group_create.mutate({
name: name, name: name,
location: location, location: location,

View file

@ -31,14 +31,11 @@ import {
} from "../../interfaces/Interfaces"; } from "../../interfaces/Interfaces";
import { useNavigation } from "@react-navigation/native"; import { useNavigation } from "@react-navigation/native";
import { import {
CreateStudyGroup,
GetStudentStatus, GetStudentStatus,
GetStudentStatusList, GetStudentStatusListNear,
GetStudentStatusListFiltered,
GetStudyGroupList, GetStudyGroupList,
GetStudyGroupListFiltered, GetStudyGroupListFiltered,
PatchStudentStatus, PatchStudentStatus,
urlProvider,
} from "../../components/Api/Api"; } from "../../components/Api/Api";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { useToast } from "react-native-toast-notifications"; import { useToast } from "react-native-toast-notifications";
@ -118,7 +115,7 @@ export default function Home() {
setDist(dist); setDist(dist);
// Deactivate student status if too far away // Deactivate student status if too far away
if (dist >= 2 && !map_debug) if (dist >= 2 && !map_debug)
mutation.mutate({ stop_studying.mutate({
active: false, active: false,
}); });
} }
@ -150,7 +147,6 @@ export default function Home() {
setButtonLabel("Start Studying"); setButtonLabel("Start Studying");
} }
setStudentStatus(data[1]); setStudentStatus(data[1]);
console.log(student_status);
}, },
onError: (error: Error) => { onError: (error: Error) => {
toast.show(String(error), { toast.show(String(error), {
@ -162,7 +158,7 @@ export default function Home() {
}, },
}); });
const mutation = useMutation({ const stop_studying = useMutation({
mutationFn: async (info: StudentStatusPatchType) => { mutationFn: async (info: StudentStatusPatchType) => {
const data = await PatchStudentStatus(info); const data = await PatchStudentStatus(info);
if (data[0] != true) { if (data[0] != true) {
@ -171,20 +167,70 @@ export default function Home() {
return data; return data;
}, },
onSuccess: () => { onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["user"] }); if (student_status?.study_group) {
queryClient.invalidateQueries({ queryKey: ["study_group_list_global"] }); // Display separate toast if you stop studying while in a study group
setTimeout(() => { toast.show("You left study group \n" + student_status?.study_group, {
queryClient.invalidateQueries({ queryKey: ["user_status"] }); type: "success",
queryClient.invalidateQueries({ queryKey: ["study_group_list"] }); placement: "top",
}, 500); duration: 2000,
setStudyGroups([]); animationType: "slide-in",
setStudying(false); });
}
toast.show("You are no longer studying \n" + subject, { toast.show("You are no longer studying \n" + subject, {
type: "success", type: "success",
placement: "top", placement: "top",
duration: 2000, duration: 2000,
animationType: "slide-in", animationType: "slide-in",
}); });
queryClient.invalidateQueries({ queryKey: ["user_status"] });
// Delay refetching for study groups since backend still needs to delete groups without students after leaving a study group
setTimeout(() => {
queryClient.invalidateQueries({ queryKey: ["study_group_list"] });
queryClient.invalidateQueries({
queryKey: ["study_group_list_global"],
});
}, 500);
setStudyGroups([]);
setStudying(false);
},
onError: (error: Error) => {
toast.show(String(error), {
type: "warning",
placement: "top",
duration: 2000,
animationType: "slide-in",
});
},
});
const change_study_group = useMutation({
mutationFn: async (info: StudentStatusPatchType) => {
const data = await PatchStudentStatus(info);
if (data[0] != true) {
return Promise.reject(new Error());
}
return data;
},
onSuccess: () => {
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",
placement: "top",
duration: 2000,
animationType: "slide-in",
});
}
queryClient.invalidateQueries({ queryKey: ["user_status"] });
// Delay refetching for study groups since backend still needs to delete groups without students after leaving a study group
setTimeout(() => {
queryClient.invalidateQueries({ queryKey: ["study_group_list"] });
queryClient.invalidateQueries({
queryKey: ["study_group_list_global"],
});
}, 500);
setStudyGroups([]);
}, },
onError: (error: Error) => { onError: (error: Error) => {
toast.show(String(error), { toast.show(String(error), {
@ -203,7 +249,7 @@ export default function Home() {
enabled: studying, enabled: studying,
queryKey: ["user_status_list"], queryKey: ["user_status_list"],
queryFn: async () => { queryFn: async () => {
const data = await GetStudentStatusListFiltered(); const data = await GetStudentStatusListNear();
if (data[0] == false) { if (data[0] == false) {
return Promise.reject(new Error(JSON.stringify(data[1]))); return Promise.reject(new Error(JSON.stringify(data[1])));
} }
@ -259,7 +305,7 @@ export default function Home() {
>([]); >([]);
// Student Status List // Student Status List
const StudyGroupGlobalQuery = useQuery({ const StudyGroupGlobalQuery = useQuery({
enabled: !studying && !StudentStatusQuery.isFetching, enabled: !studying,
queryKey: ["study_group_list_global"], queryKey: ["study_group_list_global"],
queryFn: async () => { queryFn: async () => {
const data = await GetStudyGroupList(); const data = await GetStudyGroupList();
@ -367,72 +413,10 @@ export default function Home() {
); );
} }
)} )}
{study_groups.map((studygroup: StudyGroupType, index: number) => { {!StudyGroupQuery.isPaused &&
const randomColorWithOpacity = `rgba(${Math.floor( !StudyGroupQuery.isRefetching &&
Math.random() * 256 !StudyGroupQuery.error ? (
)}, ${Math.floor(Math.random() * 256)}, ${Math.floor( study_groups.map(
Math.random() * 256
)}, 0.7)`;
return (
<React.Fragment key={index}>
<Marker
coordinate={studygroup.location}
pinColor={randomColorWithOpacity}
zIndex={1000}
onPress={() => {
toast.hideAll();
toast.show(
<View
style={{
alignContent: "center",
alignSelf: "center",
justifyContent: "center",
}}
>
<Text style={styles.text_white_tiny_bold}>
Subject: {studygroup.subject}
</Text>
<Text style={styles.text_white_tiny_bold}>
Students Studying: {studygroup.students.length}
</Text>
<Button
onPress={() => {
mutation.mutate({
study_group: studygroup.name,
});
}}
>
<Text style={styles.text_white_tiny_bold}>
Join Group
</Text>
</Button>
</View>,
{
type: "normal",
placement: "top",
duration: 2000,
animationType: "slide-in",
style: {
backgroundColor: colors.secondary_2,
borderWidth: 1,
borderColor: colors.primary_1,
},
}
);
}}
/>
<Circle
center={studygroup.location}
radius={studygroup.radius}
fillColor={randomColorWithOpacity}
strokeColor="white"
zIndex={1000}
/>
</React.Fragment>
);
})}
{study_groups_global.map(
(studygroup: StudyGroupType, index: number) => { (studygroup: StudyGroupType, index: number) => {
const randomColorWithOpacity = `rgba(${Math.floor( const randomColorWithOpacity = `rgba(${Math.floor(
Math.random() * 256 Math.random() * 256
@ -460,15 +444,18 @@ export default function Home() {
Subject: {studygroup.subject} Subject: {studygroup.subject}
</Text> </Text>
<Text style={styles.text_white_tiny_bold}> <Text style={styles.text_white_tiny_bold}>
Students Studying: {studygroup.students.length} Name: {studygroup.name}
</Text> </Text>
<Text style={styles.text_white_tiny_bold}>
Students Studying:{" "}
{studygroup.students.length}
</Text>
{student_status?.study_group !=
studygroup.name ? (
<Button <Button
onPress={() => { onPress={() => {
toast.show("Joined successfully", { change_study_group.mutate({
type: "success", study_group: studygroup.name,
placement: "top",
duration: 2000,
animationType: "slide-in",
}); });
}} }}
> >
@ -476,6 +463,25 @@ export default function Home() {
Join Group Join Group
</Text> </Text>
</Button> </Button>
) : (
<></>
)}
{student_status?.study_group ==
studygroup.name ? (
<Button
onPress={() => {
change_study_group.mutate({
study_group: "",
});
}}
>
<Text style={styles.text_white_tiny_bold}>
Leave Group
</Text>
</Button>
) : (
<></>
)}
</View>, </View>,
{ {
type: "normal", type: "normal",
@ -501,7 +507,83 @@ export default function Home() {
</React.Fragment> </React.Fragment>
); );
} }
)
) : (
<></>
)} )}
{!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 (
<React.Fragment key={index}>
<Marker
coordinate={studygroup.location}
pinColor={randomColorWithOpacity}
zIndex={1000}
onPress={() => {
toast.hideAll();
toast.show(
<View
style={{
alignContent: "center",
alignSelf: "center",
justifyContent: "center",
}}
>
<Text style={styles.text_white_tiny_bold}>
Subject: {studygroup.subject}
</Text>
<Text style={styles.text_white_tiny_bold}>
Name: {studygroup.name}
</Text>
<Text style={styles.text_white_tiny_bold}>
Students Studying:{" "}
{studygroup.students.length}
</Text>
{student_status?.study_group !=
studygroup.name ? (
<Text style={styles.text_white_tiny_bold}>
Get closer to join
</Text>
) : (
<></>
)}
</View>,
{
type: "normal",
placement: "top",
duration: 2000,
animationType: "slide-in",
style: {
backgroundColor: colors.secondary_2,
borderWidth: 1,
borderColor: colors.primary_1,
},
}
);
}}
/>
<Circle
center={studygroup.location}
radius={studygroup.radius}
fillColor={randomColorWithOpacity}
strokeColor="white"
zIndex={1000}
/>
</React.Fragment>
);
}
)
) : (
<></>
)}
{!studying || !student_status?.study_group ? (
<Marker <Marker
zIndex={1001} zIndex={1001}
coordinate={{ coordinate={{
@ -552,19 +634,6 @@ export default function Home() {
<Text style={styles.text_white_tiny_bold}> <Text style={styles.text_white_tiny_bold}>
You are here You are here
</Text> </Text>
<Text style={styles.text_white_tiny_bold}>
{"x: " +
(student_status?.location?.longitude != undefined
? student_status?.location?.longitude.toFixed(4)
: location.coords.longitude.toFixed(4))}
</Text>
<Text style={styles.text_white_tiny_bold}>
{"y: " +
(student_status?.location?.latitude != undefined
? student_status?.location?.latitude.toFixed(4)
: location.coords.latitude.toFixed(4))}
</Text>
{student_status?.active && {student_status?.active &&
!student_status?.study_group ? ( !student_status?.study_group ? (
<> <>
@ -576,17 +645,10 @@ export default function Home() {
<Button <Button
onPress={() => { onPress={() => {
if (student_status?.subject) { if (student_status?.subject) {
console.log({
location: {
latitude: student_status?.location.latitude,
longitude:
student_status?.location.longitude,
},
subject: student_status?.subject,
});
navigation.navigate("Create Group", { navigation.navigate("Create Group", {
location: { location: {
latitude: student_status?.location.latitude, latitude:
student_status?.location.latitude,
longitude: longitude:
student_status?.location.longitude, student_status?.location.longitude,
}, },
@ -606,10 +668,10 @@ export default function Home() {
{student_status?.study_group ? ( {student_status?.study_group ? (
<> <>
<Text style={styles.text_white_tiny_bold}> <Text style={styles.text_white_tiny_bold}>
{`Studying ${student_status?.subject}`} {`Studying: ${student_status?.subject}`}
</Text> </Text>
<Text style={styles.text_white_tiny_bold}> <Text style={styles.text_white_tiny_bold}>
{`In group ${student_status?.study_group}`} {`In group: ${student_status?.study_group}`}
</Text> </Text>
</> </>
) : ( ) : (
@ -630,13 +692,16 @@ export default function Home() {
); );
}} }}
></Marker> ></Marker>
) : (
<></>
)}
</MapView> </MapView>
<Button <Button
onPress={async () => { onPress={async () => {
if (!student_status?.active) { if (!student_status?.active) {
navigation.navigate("Start Studying", { location: location }); navigation.navigate("Start Studying", { location: location });
} else { } else {
mutation.mutate({ stop_studying.mutate({
active: false, active: false,
}); });
} }