mirror of
https://github.com/lemeow125/StudE-Frontend.git
synced 2024-11-17 06:19:25 +08:00
Improved homepage
This commit is contained in:
parent
33ffcde6be
commit
529a7a75fd
6 changed files with 246 additions and 82 deletions
|
@ -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];
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
|
|
|
@ -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"],
|
||||
|
|
|
@ -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));
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue