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 {
ActivationType,
LocationType,
LoginType,
OnboardingType,
PatchUserInfoType,
@ -87,7 +88,6 @@ export async function GetConfig() {
// User APIs
export function UserRegister(register: RegistrationType) {
console.log(JSON.stringify(register));
return instance
.post("/api/v1/accounts/users/", register)
.then(async (response) => {
@ -148,7 +148,6 @@ export async function PatchUserInfo(info: PatchUserInfoType) {
return instance
.patch("/api/v1/accounts/users/me/", info, config)
.then((response) => {
console.log(JSON.stringify(response.data));
return [true, response.data];
})
.catch((error) => {
@ -255,7 +254,6 @@ export async function PatchStudentStatus(info: StudentStatusPatchType) {
})
.catch((error) => {
let error_message = ParseError(error);
console.log("Error!", error.response.data);
return [false, error_message];
});
}
@ -273,12 +271,11 @@ export async function GetStudentStatusList() {
});
}
export async function GetStudentStatusListFiltered() {
export async function GetStudentStatusListNear() {
const config = await GetConfig();
return instance
.get("/api/v1/student_status/filter/near_student_status", config)
.get("/api/v1/student_status/near/", config)
.then((response) => {
console.log("test", response.data);
return [true, response.data];
})
.catch((error) => {
@ -288,10 +285,18 @@ export async function GetStudentStatusListFiltered() {
}
// To-do
export async function GetStudentStatusListFilteredCurrentLocation() {
export async function GetStudentStatusListFilteredCurrentLocation(
location: LocationType
) {
const config = await GetConfig();
return instance
.get("/api/v1/student_status/list/", config)
.post(
"/api/v1/student_status/near_current_location/",
{
location: location,
},
config
)
.then((response) => {
return [true, response.data];
})
@ -329,7 +334,7 @@ export async function GetStudyGroupList() {
export async function CreateStudyGroup(info: StudyGroupCreateType) {
const config = await GetConfig();
console.log("Payload:", info);
// console.log("Creating study group:", info);
return instance
.post("/api/v1/study_groups/create/", info, config)
.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 UserIcon from "../../icons/UserIcon/UserIcon";
import SubjectIcon from "../../icons/SubjectIcon/SubjectIcon";
import { useQueryClient } from "@tanstack/react-query";
export default function CustomDrawerContent(props: {}) {
const navigation = useNavigation<RootDrawerParamList>();
const status = useSelector((state: RootState) => state.status);
const dispatch = useDispatch();
const queryClient = useQueryClient();
if (status.logged_in && status.onboarding) {
return (
<DrawerContentScrollView {...props}>
@ -40,6 +42,7 @@ export default function CustomDrawerContent(props: {}) {
onPress={async () => {
dispatch(logout());
await AsyncStorage.clear();
queryClient.clear();
navigation.navigate("Login");
}}
>

View file

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

View file

@ -31,14 +31,11 @@ import {
} from "../../interfaces/Interfaces";
import { useNavigation } from "@react-navigation/native";
import {
CreateStudyGroup,
GetStudentStatus,
GetStudentStatusList,
GetStudentStatusListFiltered,
GetStudentStatusListNear,
GetStudyGroupList,
GetStudyGroupListFiltered,
PatchStudentStatus,
urlProvider,
} from "../../components/Api/Api";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { useToast } from "react-native-toast-notifications";
@ -118,7 +115,7 @@ export default function Home() {
setDist(dist);
// Deactivate student status if too far away
if (dist >= 2 && !map_debug)
mutation.mutate({
stop_studying.mutate({
active: false,
});
}
@ -150,7 +147,6 @@ export default function Home() {
setButtonLabel("Start Studying");
}
setStudentStatus(data[1]);
console.log(student_status);
},
onError: (error: Error) => {
toast.show(String(error), {
@ -162,7 +158,7 @@ export default function Home() {
},
});
const mutation = useMutation({
const stop_studying = useMutation({
mutationFn: async (info: StudentStatusPatchType) => {
const data = await PatchStudentStatus(info);
if (data[0] != true) {
@ -171,20 +167,70 @@ export default function Home() {
return data;
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["user"] });
queryClient.invalidateQueries({ queryKey: ["study_group_list_global"] });
setTimeout(() => {
queryClient.invalidateQueries({ queryKey: ["user_status"] });
queryClient.invalidateQueries({ queryKey: ["study_group_list"] });
}, 500);
setStudyGroups([]);
setStudying(false);
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",
});
}
toast.show("You are no longer studying \n" + subject, {
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([]);
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) => {
toast.show(String(error), {
@ -203,7 +249,7 @@ export default function Home() {
enabled: studying,
queryKey: ["user_status_list"],
queryFn: async () => {
const data = await GetStudentStatusListFiltered();
const data = await GetStudentStatusListNear();
if (data[0] == false) {
return Promise.reject(new Error(JSON.stringify(data[1])));
}
@ -259,7 +305,7 @@ export default function Home() {
>([]);
// Student Status List
const StudyGroupGlobalQuery = useQuery({
enabled: !studying && !StudentStatusQuery.isFetching,
enabled: !studying,
queryKey: ["study_group_list_global"],
queryFn: async () => {
const data = await GetStudyGroupList();
@ -367,276 +413,295 @@ export default function Home() {
);
}
)}
{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)`;
{!StudyGroupQuery.isPaused &&
!StudyGroupQuery.isRefetching &&
!StudyGroupQuery.error ? (
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 (
<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) => {
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}>
Students Studying: {studygroup.students.length}
</Text>
<Button
onPress={() => {
toast.show("Joined successfully", {
type: "success",
placement: "top",
duration: 2000,
animationType: "slide-in",
});
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}>
Join Group
Subject: {studygroup.subject}
</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>
);
}
)}
<Marker
zIndex={1001}
coordinate={{
latitude:
student_status?.location?.latitude ||
location.coords.latitude,
longitude:
student_status?.location?.longitude ||
location.coords.longitude,
}}
draggable={!student_status?.active}
onDragEnd={(e) => {
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(
<View
style={{
alignContent: "center",
alignSelf: "center",
justifyContent: "center",
}}
>
<Text style={styles.text_white_tiny_bold}>
You are here
</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?.study_group ? (
<>
<Text style={styles.text_white_tiny_bold}>
{student_status?.active
? "Studying " + student_status?.subject
: ""}
</Text>
<Button
onPress={() => {
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", {
location: {
latitude: student_status?.location.latitude,
longitude:
student_status?.location.longitude,
},
subject: student_status?.subject,
});
<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 ? (
<Button
onPress={() => {
change_study_group.mutate({
study_group: studygroup.name,
});
}}
>
<Text style={styles.text_white_tiny_bold}>
Join Group
</Text>
</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>,
{
type: "normal",
placement: "top",
duration: 2000,
animationType: "slide-in",
style: {
backgroundColor: colors.secondary_2,
borderWidth: 1,
borderColor: colors.primary_1,
},
}
}}
>
<Text style={styles.text_white_tiny_bold}>
Create Group
</Text>
</Button>
</>
) : (
<></>
)}
{student_status?.study_group ? (
<>
<Text style={styles.text_white_tiny_bold}>
{`Studying ${student_status?.subject}`}
</Text>
<Text style={styles.text_white_tiny_bold}>
{`In group ${student_status?.study_group}`}
</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 ? (
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
zIndex={1001}
coordinate={{
latitude:
student_status?.location?.latitude ||
location.coords.latitude,
longitude:
student_status?.location?.longitude ||
location.coords.longitude,
}}
draggable={!student_status?.active}
onDragEnd={(e) => {
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,
});
}
);
}}
></Marker>
}}
pinColor={colors.primary_1}
onPress={() => {
toast.hideAll();
toast.show(
<View
style={{
alignContent: "center",
alignSelf: "center",
justifyContent: "center",
}}
>
<Text style={styles.text_white_tiny_bold}>
You are here
</Text>
{student_status?.active &&
!student_status?.study_group ? (
<>
<Text style={styles.text_white_tiny_bold}>
{student_status?.active
? "Studying " + student_status?.subject
: ""}
</Text>
<Button
onPress={() => {
if (student_status?.subject) {
navigation.navigate("Create Group", {
location: {
latitude:
student_status?.location.latitude,
longitude:
student_status?.location.longitude,
},
subject: student_status?.subject,
});
}
}}
>
<Text style={styles.text_white_tiny_bold}>
Create Group
</Text>
</Button>
</>
) : (
<></>
)}
{student_status?.study_group ? (
<>
<Text style={styles.text_white_tiny_bold}>
{`Studying: ${student_status?.subject}`}
</Text>
<Text style={styles.text_white_tiny_bold}>
{`In group: ${student_status?.study_group}`}
</Text>
</>
) : (
<></>
)}
</View>,
{
type: "normal",
placement: "top",
duration: 2000,
animationType: "slide-in",
style: {
backgroundColor: colors.secondary_2,
borderWidth: 1,
borderColor: colors.primary_1,
},
}
);
}}
></Marker>
) : (
<></>
)}
</MapView>
<Button
onPress={async () => {
if (!student_status?.active) {
navigation.navigate("Start Studying", { location: location });
} else {
mutation.mutate({
stop_studying.mutate({
active: false,
});
}