Finalize changes to using modals for user feedback

This commit is contained in:
Keannu Bernasol 2023-08-14 21:57:52 +08:00
parent ff114b496c
commit 2ca1dd13ca
11 changed files with 119 additions and 90 deletions

View file

@ -1,5 +1,5 @@
import "react-native-gesture-handler"; import "react-native-gesture-handler";
import { Text } from "react-native"; import styles from "./src/styles";
import { NavigationContainer } from "@react-navigation/native"; import { NavigationContainer } from "@react-navigation/native";
import { createDrawerNavigator } from "@react-navigation/drawer"; import { createDrawerNavigator } from "@react-navigation/drawer";
import { Provider } from "react-redux"; import { Provider } from "react-redux";
@ -60,7 +60,10 @@ export default function App() {
} }
}, [initialRoute]); }, [initialRoute]);
return ( return (
<ToastProvider icon={<AppIcon size={64} />}> <ToastProvider
icon={<AppIcon size={64} />}
textStyle={{ ...styles.text_white_tiny_bold }}
>
<QueryClientProvider client={queryClient}> <QueryClientProvider client={queryClient}>
<Provider store={store}> <Provider store={store}>
<StatusBar style="light" /> <StatusBar style="light" />

View file

@ -28,7 +28,7 @@ const instance = axios.create({
timeout: 1000, timeout: 1000,
}); });
console.log(backendURL); console.log("Using backend API:", backendURL);
// 3rd Party APIs // 3rd Party APIs
export const urlProvider = export const urlProvider =

View file

@ -6,6 +6,7 @@ import { useNavigation, useRoute } from "@react-navigation/native";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { UserActivate } from "../../components/Api/Api"; import { UserActivate } from "../../components/Api/Api";
import { RootDrawerParamList } from "../../interfaces/Interfaces"; import { RootDrawerParamList } from "../../interfaces/Interfaces";
import { useToast } from "react-native-toast-notifications";
interface ActivationRouteParams { interface ActivationRouteParams {
uid?: string; uid?: string;
@ -16,9 +17,7 @@ export default function Activation() {
const route = useRoute(); const route = useRoute();
const { uid, token } = (route.params as ActivationRouteParams) || ""; const { uid, token } = (route.params as ActivationRouteParams) || "";
const navigation = useNavigation<RootDrawerParamList>(); const navigation = useNavigation<RootDrawerParamList>();
const [state, setState] = useState( const toast = useToast();
"Activating with UID " + uid + " and Token " + token
);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
useEffect(() => { useEffect(() => {
@ -28,16 +27,22 @@ export default function Activation() {
token: String(token), token: String(token),
}); });
if (result) { if (result) {
setTimeout(() => { toast.show("Activation successful", {
setState("Activation successful!"); type: "success",
}, 1000); placement: "top",
duration: 4000,
animationType: "slide-in",
});
setTimeout(() => { setTimeout(() => {
navigation.navigate("Login"); navigation.navigate("Login");
}, 2000); }, 2000);
} else { } else {
setTimeout(() => { toast.show("Activation unsuccessful. Please contact support", {
setState("Activation unsuccessful\nPlease contact support"); type: "warning",
}, 1000); placement: "top",
duration: 4000,
animationType: "slide-in",
});
} }
setLoading(false); setLoading(false);
} }
@ -63,8 +68,9 @@ export default function Activation() {
size={96} size={96}
color={colors.secondary_1} color={colors.secondary_1}
/> />
<Text style={styles.text_white_medium}>{state}</Text> <Text style={styles.text_white_medium}>
<Text style={styles.text_white_tiny}>{uid + "\n" + token}</Text> {"Activating with UID: " + uid + "\nToken: " + token}
</Text>
</AnimatedContainer> </AnimatedContainer>
</View> </View>
); );

View file

@ -1,5 +1,5 @@
import styles, { Viewport, colors } from "../../styles"; 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 AnimatedContainer from "../../components/AnimatedContainer/AnimatedContainer";
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import MapView, { Callout, Marker, UrlTile } from "react-native-maps"; 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", "Location permission was denied. Please allow in order to use StudE",
{ {
type: "warning", type: "warning",
placement: "bottom", placement: "top",
duration: 4000, duration: 2000,
animationType: "slide-in", animationType: "slide-in",
} }
); );
@ -129,18 +129,18 @@ export default function Home() {
onSuccess: () => { onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["user"] }); queryClient.invalidateQueries({ queryKey: ["user"] });
queryClient.invalidateQueries({ queryKey: ["user_status"] }); queryClient.invalidateQueries({ queryKey: ["user_status"] });
toast.show("You are no longer studying " + subject, { toast.show("You are no longer studying \n" + subject, {
type: "success", type: "success",
placement: "bottom", placement: "top",
duration: 4000, duration: 2000,
animationType: "slide-in", animationType: "slide-in",
}); });
}, },
onError: () => { onError: () => {
toast.show("Server error. Unable to update student status", { toast.show("Server error. Unable to update student status", {
type: "warning", type: "warning",
placement: "bottom", placement: "top",
duration: 4000, duration: 2000,
animationType: "slide-in", animationType: "slide-in",
}); });
}, },

View file

@ -8,7 +8,6 @@ import {
TextInputChangeEventData, TextInputChangeEventData,
} from "react-native"; } from "react-native";
import { useDispatch } from "react-redux"; import { useDispatch } from "react-redux";
import { colors } from "../../styles";
import { useState } from "react"; import { useState } from "react";
import LoginIcon from "../../icons/LoginIcon/LoginIcon"; import LoginIcon from "../../icons/LoginIcon/LoginIcon";
import Button from "../../components/Button/Button"; import Button from "../../components/Button/Button";
@ -89,16 +88,16 @@ export default function Login() {
navigation.navigate("Onboarding"); navigation.navigate("Onboarding");
toast.show("Successfully logged in", { toast.show("Successfully logged in", {
type: "success", type: "success",
placement: "bottom", placement: "top",
duration: 4000, duration: 2000,
animationType: "slide-in", animationType: "slide-in",
}); });
} else { } else {
dispatch(unsetOnboarding()); dispatch(unsetOnboarding());
toast.show("Successfully logged in", { toast.show("Successfully logged in", {
type: "success", type: "success",
placement: "bottom", placement: "top",
duration: 4000, duration: 2000,
animationType: "slide-in", animationType: "slide-in",
}); });
navigation.navigate("Home"); navigation.navigate("Home");
@ -108,8 +107,8 @@ export default function Login() {
console.log(ParseLoginError(JSON.stringify(result[1]))); console.log(ParseLoginError(JSON.stringify(result[1])));
toast.show(JSON.stringify(result[1]), { toast.show(JSON.stringify(result[1]), {
type: "warning", type: "warning",
placement: "bottom", placement: "top",
duration: 4000, duration: 2000,
animationType: "slide-in", animationType: "slide-in",
}); });
} }

View file

@ -48,6 +48,14 @@ export default function Onboarding() {
})); }));
setSemesters(semesters); setSemesters(semesters);
}, },
onError: () => {
toast.show("Server error: Unable to query available semesters", {
type: "warning",
placement: "top",
duration: 2000,
animationType: "slide-in",
});
},
}); });
// Year Level // Year Level
const [selected_yearlevel, setSelectedYearLevel] = useState(""); const [selected_yearlevel, setSelectedYearLevel] = useState("");
@ -66,6 +74,14 @@ export default function Onboarding() {
})); }));
setYearLevels(year_levels); setYearLevels(year_levels);
}, },
onError: () => {
toast.show("Server error: Unable to query available year levels", {
type: "warning",
placement: "top",
duration: 2000,
animationType: "slide-in",
});
},
}); });
// Course // Course
const [selected_course, setSelectedCourse] = useState(""); const [selected_course, setSelectedCourse] = useState("");
@ -87,6 +103,14 @@ export default function Onboarding() {
})); }));
setCourses(courses); 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) { if (yearlevel_query.error || semester_query.error || course_query.error) {
return ( return (
@ -230,8 +254,8 @@ export default function Onboarding() {
dispatch(setUser(result[1])); dispatch(setUser(result[1]));
toast.show("Changes applied successfully", { toast.show("Changes applied successfully", {
type: "success", type: "success",
placement: "bottom", placement: "top",
duration: 6000, duration: 2000,
animationType: "slide-in", animationType: "slide-in",
}); });
navigation.navigate("Home"); navigation.navigate("Home");
@ -241,8 +265,8 @@ export default function Onboarding() {
"An error has occured\nChanges have not been saved", "An error has occured\nChanges have not been saved",
{ {
type: "warning", type: "warning",
placement: "bottom", placement: "top",
duration: 6000, duration: 2000,
animationType: "slide-in", animationType: "slide-in",
} }
); );

View file

@ -146,7 +146,7 @@ export default function Register() {
"Success! An email has been sent to activate your account", "Success! An email has been sent to activate your account",
{ {
type: "success", type: "success",
placement: "bottom", placement: "top",
duration: 6000, duration: 6000,
animationType: "slide-in", animationType: "slide-in",
} }
@ -157,7 +157,7 @@ export default function Register() {
} else { } else {
toast.show(JSON.stringify(result[1]), { toast.show(JSON.stringify(result[1]), {
type: "warning", type: "warning",
placement: "bottom", placement: "top",
duration: 6000, duration: 6000,
animationType: "slide-in", animationType: "slide-in",
}); });

View file

@ -37,8 +37,8 @@ export default function Revalidation() {
dispatch(setOnboarding()); dispatch(setOnboarding());
toast.show("Previous session restored", { toast.show("Previous session restored", {
type: "success", type: "success",
placement: "bottom", placement: "top",
duration: 4000, duration: 2000,
animationType: "slide-in", animationType: "slide-in",
}); });
await setTimeout(() => { await setTimeout(() => {
@ -48,8 +48,8 @@ export default function Revalidation() {
dispatch(unsetOnboarding()); dispatch(unsetOnboarding());
toast.show("Previous session restored", { toast.show("Previous session restored", {
type: "success", type: "success",
placement: "bottom", placement: "top",
duration: 4000, duration: 2000,
animationType: "slide-in", animationType: "slide-in",
}); });
await setTimeout(() => { await setTimeout(() => {
@ -60,8 +60,8 @@ export default function Revalidation() {
await setState("Session expired"); await setState("Session expired");
toast.show("Session expired. Please login again", { toast.show("Session expired. Please login again", {
type: "warning", type: "warning",
placement: "bottom", placement: "top",
duration: 4000, duration: 2000,
animationType: "slide-in", animationType: "slide-in",
}); });
await setTimeout(() => { await setTimeout(() => {

View file

@ -40,9 +40,9 @@ export default function StartStudying({ route }: any) {
}, },
onError: () => { onError: () => {
toast.show("Server error: Unable to query available subjects", { toast.show("Server error: Unable to query available subjects", {
type: "error", type: "warning",
placement: "bottom", placement: "top",
duration: 4000, duration: 2000,
animationType: "slide-in", animationType: "slide-in",
}); });
}, },
@ -53,19 +53,19 @@ export default function StartStudying({ route }: any) {
onSuccess: () => { onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["user"] }); queryClient.invalidateQueries({ queryKey: ["user"] });
queryClient.invalidateQueries({ queryKey: ["user_status"] }); queryClient.invalidateQueries({ queryKey: ["user_status"] });
toast.show("You are now studying " + selected_subject, { toast.show("You are now studying \n" + selected_subject, {
type: "success", type: "success",
placement: "bottom", placement: "top",
duration: 4000, duration: 2000,
animationType: "slide-in", animationType: "slide-in",
}); });
navigation.navigate("Home"); navigation.navigate("Home");
}, },
onError: () => { onError: () => {
toast.show("A server error has occured. Please try again", { toast.show("A server error has occured. Please try again", {
type: "error", type: "warning",
placement: "bottom", placement: "top",
duration: 4000, duration: 2000,
animationType: "slide-in", animationType: "slide-in",
}); });
}, },

View file

@ -1,45 +1,28 @@
import * as React from "react"; import * as React from "react";
import styles from "../../styles"; import styles from "../../styles";
import { View, Text } from "react-native";
import { useState } from "react";
import { import {
View,
Text,
TextInput,
NativeSyntheticEvent,
TextInputChangeEventData,
} from "react-native";
import { useEffect, useState } from "react";
import {
SemesterParams,
UserInfoParams, UserInfoParams,
Semester,
SubjectParams, SubjectParams,
Subject, Subject,
YearLevel,
Course,
OptionType, OptionType,
Subjects,
} from "../../interfaces/Interfaces"; } from "../../interfaces/Interfaces";
import Button from "../../components/Button/Button"; import Button from "../../components/Button/Button";
import { Image } from "react-native"; import { Image } from "react-native";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { import { GetSubjects, PatchUserInfo, UserInfo } from "../../components/Api/Api";
GetCourses,
GetSemesters,
GetSubjects,
GetYearLevels,
PatchUserInfo,
UserInfo,
} from "../../components/Api/Api";
import { colors } from "../../styles"; import { colors } from "../../styles";
import DropDownPicker from "react-native-dropdown-picker"; import DropDownPicker from "react-native-dropdown-picker";
import AnimatedContainerNoScroll from "../../components/AnimatedContainer/AnimatedContainerNoScroll"; import AnimatedContainerNoScroll from "../../components/AnimatedContainer/AnimatedContainerNoScroll";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import { RootState } from "../../features/redux/Store/Store"; import { RootState } from "../../features/redux/Store/Store";
import { useToast } from "react-native-toast-notifications";
export default function SubjectsPage() { export default function SubjectsPage() {
const logged_in_user = useSelector((state: RootState) => state.user.user); const logged_in_user = useSelector((state: RootState) => state.user.user);
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const [feedback, setFeedback] = useState(""); const toast = useToast();
// User Info // User Info
const [user, setUser] = useState({ const [user, setUser] = useState({
first_name: "", first_name: "",
@ -72,7 +55,12 @@ export default function SubjectsPage() {
setSelectedSubjects(data[1].subjects); setSelectedSubjects(data[1].subjects);
}, },
onError: () => { 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({ const mutation = useMutation({
@ -81,7 +69,12 @@ export default function SubjectsPage() {
queryClient.invalidateQueries({ queryKey: ["user"] }); queryClient.invalidateQueries({ queryKey: ["user"] });
queryClient.invalidateQueries({ queryKey: ["subjects"] }); queryClient.invalidateQueries({ queryKey: ["subjects"] });
setSelectedSubjects([]); 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: () => { 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() {
<Text style={styles.text_white_small}>Save Changes</Text> <Text style={styles.text_white_small}>Save Changes</Text>
</Button> </Button>
<View style={styles.padding} /> <View style={styles.padding} />
<Text style={styles.text_white_small}>{feedback}</Text>
</View> </View>
</AnimatedContainerNoScroll> </AnimatedContainerNoScroll>
</View> </View>

View file

@ -58,16 +58,16 @@ export default function UserInfoPage() {
queryClient.invalidateQueries({ queryKey: ["user_status"] }); queryClient.invalidateQueries({ queryKey: ["user_status"] });
toast.show("Changes applied successfully", { toast.show("Changes applied successfully", {
type: "success", type: "success",
placement: "bottom", placement: "top",
duration: 4000, duration: 2000,
animationType: "slide-in", animationType: "slide-in",
}); });
}, },
onError: () => { onError: () => {
toast.show("An error has occured\nChanges have not been saved", { toast.show("An error has occured\nChanges have not been saved", {
type: "warning", type: "warning",
placement: "bottom", placement: "top",
duration: 4000, duration: 2000,
animationType: "slide-in", animationType: "slide-in",
}); });
}, },
@ -112,7 +112,7 @@ export default function UserInfoPage() {
toast.show("Server Error: Unable to query user info", { toast.show("Server Error: Unable to query user info", {
type: "warning", type: "warning",
placement: "bottom", placement: "bottom",
duration: 4000, duration: 2000,
animationType: "slide-in", animationType: "slide-in",
}); });
}, },
@ -130,7 +130,7 @@ export default function UserInfoPage() {
toast.show("Changes applied successfully", { toast.show("Changes applied successfully", {
type: "success", type: "success",
placement: "bottom", placement: "bottom",
duration: 4000, duration: 2000,
animationType: "slide-in", animationType: "slide-in",
}); });
dispatch(setUserinState(user)); dispatch(setUserinState(user));
@ -139,7 +139,7 @@ export default function UserInfoPage() {
toast.show("An error has occured\nChanges have not been saved", { toast.show("An error has occured\nChanges have not been saved", {
type: "warning", type: "warning",
placement: "bottom", placement: "bottom",
duration: 4000, duration: 2000,
animationType: "slide-in", animationType: "slide-in",
}); });
}, },
@ -164,8 +164,8 @@ export default function UserInfoPage() {
onError: () => { onError: () => {
toast.show("Server Error: Unable to query semester info", { toast.show("Server Error: Unable to query semester info", {
type: "warning", type: "warning",
placement: "bottom", placement: "top",
duration: 4000, duration: 2000,
animationType: "slide-in", animationType: "slide-in",
}); });
}, },
@ -188,8 +188,8 @@ export default function UserInfoPage() {
onError: () => { onError: () => {
toast.show("Server Error: Unable to query year level info", { toast.show("Server Error: Unable to query year level info", {
type: "warning", type: "warning",
placement: "bottom", placement: "top",
duration: 4000, duration: 2000,
animationType: "slide-in", animationType: "slide-in",
}); });
}, },
@ -212,8 +212,8 @@ export default function UserInfoPage() {
onError: () => { onError: () => {
toast.show("Server Error: Unable to query course info", { toast.show("Server Error: Unable to query course info", {
type: "warning", type: "warning",
placement: "bottom", placement: "top",
duration: 4000, duration: 2000,
animationType: "slide-in", animationType: "slide-in",
}); });
}, },
@ -426,7 +426,7 @@ export default function UserInfoPage() {
<Text style={styles.text_white_small}>Irregular </Text> <Text style={styles.text_white_small}>Irregular </Text>
</View> </View>
<Button <Button
onPress={async () => { onPress={() => {
setYearLevelOpen(false); setYearLevelOpen(false);
setSemesterOpen(false); setSemesterOpen(false);
setCourseOpen(false); setCourseOpen(false);