Improved homepage

This commit is contained in:
Keannu Bernasol 2023-08-10 17:23:12 +08:00
parent 33ffcde6be
commit 529a7a75fd
6 changed files with 246 additions and 82 deletions

View file

@ -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];
});
}

View file

@ -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;

View file

@ -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<RootDrawerParamList>();
const [location, setLocation] = useState<LocationType | null>(null);
const [dist, setDist] = useState<number | null>(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 (
<Callout>
<Text style={styles.text_black_medium}>
You are here {"\n"}
X: {Math.round(location.coords.longitude) + "\n"}
Z: {Math.round(location.coords.latitude) + "\n"}
Studying: {subject}
</Text>
</Callout>
);
} else {
return (
<Callout>
<Text style={styles.text_black_medium}>
You are here {"\n"}
X: {Math.round(location.coords.longitude) + "\n"}
Z: {Math.round(location.coords.latitude)}
</Text>
</Callout>
);
}
}
return <></>;
}
function CustomMap() {
if (dist && location) {
if (dist >= 2) {
// Just switch this condition for map debugging
if (dist <= 2 || map_debug) {
return (
<View>
<MapView
@ -149,21 +236,21 @@ export default function Home() {
}}
pinColor={colors.primary_1}
>
<Callout>
<Text style={styles.text_black_medium}>
You are here {"\n"}
X: {Math.round(location.coords.longitude) + "\n"}
Z: {Math.round(location.coords.latitude)}
</Text>
</Callout>
<CustomCallout />
</Marker>
</MapView>
<Button
onPress={async () => {
navigation.navigate("Start Studying", { location: location });
if (!studying) {
navigation.navigate("Start Studying", { location: location });
} else {
mutation.mutate({
active: false,
});
}
}}
>
<Text style={styles.text_white_medium}>Start Studying</Text>
<Text style={styles.text_white_medium}>{buttonLabel}</Text>
</Button>
</View>
);

View file

@ -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<RootDrawerParamList>();
// 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 (
<View style={styles.background}>
@ -87,50 +115,60 @@ export default function StartStudying({ route }: any) {
/>
</MapView>
<View style={styles.padding} />
<Text style={styles.text_white_small}>{feedback}</Text>
</View>
<View style={styles.flex_row}>
<View style={{ flex: 1 }}>
<Text style={styles.text_white_small_bold}>Start Studying</Text>
</View>
<View style={{ flex: 3 }}>
<DropDownPicker
zIndex={1000}
max={16}
open={subjectsOpen}
value={selected_subject}
items={subjects}
setOpen={(open) => {
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"
/>
</View>
</View>
<DropDownPicker
zIndex={1000}
max={16}
open={subjectsOpen}
value={selected_subject}
items={subjects}
setOpen={(open) => {
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"
/>
<View style={styles.padding} />
<Button onPress={() => {}}>
<Button
onPress={() => {
console.log({
subject: selected_subject,
location: {
latitude: location.coords.latitude,
longitude: location.coords.longitude,
},
});
mutation.mutate({
active: true,
subject: selected_subject,
location: {
latitude: location.coords.latitude,
longitude: location.coords.longitude,
},
});
}}
>
<Text style={styles.text_white_small}>Start Studying</Text>
</Button>
<View style={styles.padding} />
</AnimatedContainerNoScroll>
</View>
);

View file

@ -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"],

View file

@ -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));
},