From b8efd638ae37b2f62e3d435aa401a78df0341a77 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Thu, 6 Jul 2023 15:23:01 +0800 Subject: [PATCH 01/12] Fixed revalidation page not redirecting properly if server is unreachable --- src/components/Api/Api.tsx | 6 +++--- src/routes/Revalidation/Revalidation.tsx | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/Api/Api.tsx b/src/components/Api/Api.tsx index 47d5bf7..8820598 100644 --- a/src/components/Api/Api.tsx +++ b/src/components/Api/Api.tsx @@ -88,11 +88,11 @@ export async function TokenRefresh() { "Token refresh success! New Access Token", response.data.access );*/ - return [true]; + return true; }) .catch((error) => { - console.log("Refresh Failed: " + JSON.stringify(error.response.data)); - return [false, error.response.data]; + console.log("Refresh Failed: " + JSON.stringify(error.response)); + return false; }); } export async function UserInfo() { diff --git a/src/routes/Revalidation/Revalidation.tsx b/src/routes/Revalidation/Revalidation.tsx index bee1ca4..df677e5 100644 --- a/src/routes/Revalidation/Revalidation.tsx +++ b/src/routes/Revalidation/Revalidation.tsx @@ -17,7 +17,7 @@ export default function Revalidation() { useEffect(() => { setState("Previous session found"); TokenRefresh().then(async (response) => { - if (response[0]) { + if (response) { let user_info = await UserInfo(); await dispatch(setUser(user_info)); if (!(user_info.year_level || user_info.course || user_info.semester)) { From 99d42f5125d23cb9e6251fa81881e4536d175e1c Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Thu, 6 Jul 2023 15:37:22 +0800 Subject: [PATCH 02/12] Improved APIs to respond to unreachable error --- src/components/Api/Api.tsx | 22 ++++++++++++++++------ src/routes/Register/Register.tsx | 2 +- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/components/Api/Api.tsx b/src/components/Api/Api.tsx index 8820598..75300cf 100644 --- a/src/components/Api/Api.tsx +++ b/src/components/Api/Api.tsx @@ -51,7 +51,10 @@ export function UserRegister(register: RegistrationParams) { return [true, response.status]; }) .catch((error) => { - return [false, error.response.status, error.response.data]; + let error_message = ""; + if (error.response) error_message = error.response.data; + else error_message = "Unable to reach servers"; + return [false, error_message]; }); } @@ -70,8 +73,10 @@ export function UserLogin(user: LoginParams) { return [true]; }) .catch((error) => { - console.log("Login Failed:" + JSON.stringify(error.response.data)); - return [false, error.response.data]; + let error_message = ""; + if (error.response) error_message = error.response.data; + else error_message = "Unable to reach servers"; + return [false, error_message]; }); } @@ -91,7 +96,10 @@ export async function TokenRefresh() { return true; }) .catch((error) => { - console.log("Refresh Failed: " + JSON.stringify(error.response)); + let error_message = ""; + if (error.response) error_message = error.response.data; + else error_message = "Unable to reach servers"; + console.log("Token Refresh error:", error_message); return false; }); } @@ -108,8 +116,10 @@ export async function UserInfo() { return response.data; }) .catch((error) => { - console.log("User Info Error", error.response.data); - return [false, error.response.data]; + let error_message = ""; + if (error.response) error_message = error.response.data; + else error_message = "Unable to reach servers"; + return [false, error_message]; }); } diff --git a/src/routes/Register/Register.tsx b/src/routes/Register/Register.tsx index f484f11..ea2b90f 100644 --- a/src/routes/Register/Register.tsx +++ b/src/routes/Register/Register.tsx @@ -159,7 +159,7 @@ export default function Register() { } else { setUser({ ...user, - feedback: ParseError(JSON.stringify(result[2])), + feedback: ParseError(JSON.stringify(result[1])), }); } }); From cf08dab685a17a5276f4f91a5e1f1d219ae615e0 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Thu, 6 Jul 2023 16:04:57 +0800 Subject: [PATCH 03/12] Added content to onboarding and improved button to be responsive if disabled --- package-lock.json | 10 ++++++++++ package.json | 5 +++-- src/components/Button/Button.tsx | 15 +++++++++++++-- src/routes/Onboarding/Onboarding.tsx | 26 ++++++++++++++++++++++++++ src/styles.tsx | 1 + 5 files changed, 53 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index bc946b2..85b5680 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "moti": "^0.25.3", "react": "18.2.0", "react-native": "0.71.8", + "react-native-dropdown-picker": "^5.4.6", "react-native-gesture-handler": "~2.9.0", "react-native-reanimated": "~2.14.4", "react-native-safe-area-context": "4.5.0", @@ -12160,6 +12161,15 @@ "nullthrows": "^1.1.1" } }, + "node_modules/react-native-dropdown-picker": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/react-native-dropdown-picker/-/react-native-dropdown-picker-5.4.6.tgz", + "integrity": "sha512-T1XBHbE++M6aRU3wFYw3MvcOuabhWZ29RK/Ivdls2r1ZkZ62iEBZknLUPeVLMX3x6iUxj4Zgr3X2DGlEGXeHsA==", + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, "node_modules/react-native-gesture-handler": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.9.0.tgz", diff --git a/package.json b/package.json index 5c2ccd0..d6d1135 100644 --- a/package.json +++ b/package.json @@ -16,18 +16,19 @@ "@reduxjs/toolkit": "^1.9.5", "axios": "^1.4.0", "expo": "~48.0.18", + "expo-linking": "~4.0.1", "expo-status-bar": "~1.4.4", "moti": "^0.25.3", "react": "18.2.0", "react-native": "0.71.8", + "react-native-dropdown-picker": "^5.4.6", "react-native-gesture-handler": "~2.9.0", "react-native-reanimated": "~2.14.4", "react-native-safe-area-context": "4.5.0", "react-native-screens": "~3.20.0", "react-native-svg": "13.4.0", "react-redux": "^8.1.1", - "redux": "^4.2.1", - "expo-linking": "~4.0.1" + "redux": "^4.2.1" }, "devDependencies": { "@babel/core": "^7.20.0", diff --git a/src/components/Button/Button.tsx b/src/components/Button/Button.tsx index 6a843c7..3375a7e 100644 --- a/src/components/Button/Button.tsx +++ b/src/components/Button/Button.tsx @@ -1,20 +1,31 @@ import * as React from "react"; import { Pressable, GestureResponderEvent } from "react-native"; import styles from "../../styles"; +import { colors } from "../../styles"; export interface props { children: React.ReactNode; onPress: (event: GestureResponderEvent) => void; color: string; + disabled?: boolean; } -export default function Button(props: props) { +export default function Button({ disabled = false, ...props }: props) { + const rgb = props.color.match(/\d+/g); return ( {props.children} diff --git a/src/routes/Onboarding/Onboarding.tsx b/src/routes/Onboarding/Onboarding.tsx index 9a150b3..22a225d 100644 --- a/src/routes/Onboarding/Onboarding.tsx +++ b/src/routes/Onboarding/Onboarding.tsx @@ -6,6 +6,7 @@ import { RootDrawerParamList } from "../../interfaces/Interfaces"; import { colors } from "../../styles"; import { AnimatePresence, MotiView } from "moti"; import { useEffect, useState } from "react"; +import Button from "../../components/Button/Button"; export default function Onboarding() { const navigation = useNavigation(); // const dispatch = useDispatch(); @@ -15,6 +16,17 @@ export default function Onboarding() { course: "", semester: "", }); + function isStringEmpty(str: string) { + return str === "" || str === null || str === undefined; + } + const [complete, setComplete] = useState(false); + useEffect(() => { + setComplete( + !isStringEmpty(student_info.year_level) && + !isStringEmpty(student_info.course) && + !isStringEmpty(student_info.semester) + ); + }, [student_info]); function Introduction() { const [shown, setShown] = useState(true); useEffect(() => { @@ -72,6 +84,20 @@ export default function Onboarding() { > Academic Info + + + ); diff --git a/src/styles.tsx b/src/styles.tsx index 7d80160..d3dfd15 100644 --- a/src/styles.tsx +++ b/src/styles.tsx @@ -11,6 +11,7 @@ export const colors = { text_error: "#e32d1e", text_success: "green", icon_color: "white", + blue_disabled: "#C07624", }; export const font_sizes = { From f4ca96e35d18f9692a0c1a1d443542273a44dd75 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Thu, 6 Jul 2023 16:43:50 +0800 Subject: [PATCH 04/12] Improved onboarding page --- src/components/Button/Button.tsx | 1 - .../IsStringEmpty/IsStringEmpty.tsx | 3 + src/routes/Onboarding/Onboarding.tsx | 136 ++++++++++++------ src/styles.tsx | 5 + 4 files changed, 104 insertions(+), 41 deletions(-) create mode 100644 src/components/IsStringEmpty/IsStringEmpty.tsx diff --git a/src/components/Button/Button.tsx b/src/components/Button/Button.tsx index 3375a7e..83b9d7b 100644 --- a/src/components/Button/Button.tsx +++ b/src/components/Button/Button.tsx @@ -1,7 +1,6 @@ import * as React from "react"; import { Pressable, GestureResponderEvent } from "react-native"; import styles from "../../styles"; -import { colors } from "../../styles"; export interface props { children: React.ReactNode; diff --git a/src/components/IsStringEmpty/IsStringEmpty.tsx b/src/components/IsStringEmpty/IsStringEmpty.tsx new file mode 100644 index 0000000..b1cd9d1 --- /dev/null +++ b/src/components/IsStringEmpty/IsStringEmpty.tsx @@ -0,0 +1,3 @@ +export default function isStringEmpty(str: string) { + return str === "" || str === null || str === undefined; +} diff --git a/src/routes/Onboarding/Onboarding.tsx b/src/routes/Onboarding/Onboarding.tsx index 22a225d..2a68a37 100644 --- a/src/routes/Onboarding/Onboarding.tsx +++ b/src/routes/Onboarding/Onboarding.tsx @@ -7,52 +7,44 @@ import { colors } from "../../styles"; import { AnimatePresence, MotiView } from "moti"; import { useEffect, useState } from "react"; import Button from "../../components/Button/Button"; +import DropDownPicker from "react-native-dropdown-picker"; +import isStringEmpty from "../../components/IsStringEmpty/IsStringEmpty"; + export default function Onboarding() { const navigation = useNavigation(); // const dispatch = useDispatch(); // const creds = useSelector((state: RootState) => state.auth.creds); - const [student_info, setStudentInfo] = useState({ - year_level: "", - course: "", - semester: "", - }); - function isStringEmpty(str: string) { - return str === "" || str === null || str === undefined; - } + + // Semesters + const [semester, setSemester] = useState(""); + const [semesterOpen, setSemesterOpen] = useState(false); + const [semesters, setSemesters] = useState([ + { label: "1st Semester", value: "1st Sem" }, + { label: "2nd Semester", value: "2nd Sem" }, + ]); + // Year Level + const [year_level, setYearLevel] = useState(""); + const [yearLevelOpen, setYearLevelOpen] = useState(false); + const [year_levels, setYearLevels] = useState([ + { label: "1st Year", value: "1st Year" }, + { label: "2nd Year", value: "2nd Year" }, + ]); + // Course + const [course, setCourse] = useState(""); + const [courseOpen, setCourseOpen] = useState(false); + const [courses, setCourses] = useState([ + { label: "Bachelor of Science in Information Technology", value: "BSIT" }, + { label: "Bachelor of Science in Computer Science", value: "BSCS" }, + ]); const [complete, setComplete] = useState(false); + useEffect(() => { setComplete( - !isStringEmpty(student_info.year_level) && - !isStringEmpty(student_info.course) && - !isStringEmpty(student_info.semester) + !isStringEmpty(year_level) && + !isStringEmpty(course) && + !isStringEmpty(semester) ); - }, [student_info]); - function Introduction() { - const [shown, setShown] = useState(true); - useEffect(() => { - setTimeout(() => { - setShown(false); - }, 5000); - }, []); - return ( - - {shown && ( - - - We're glad to have you on board {"\n"} - Just a few more things before we get started - - - )} - - ); - } + }, [year_level, course, semester, complete]); return ( @@ -75,18 +67,82 @@ export default function Onboarding() { }} /> - + + + We're glad to have you on board {"\n"} + Just a few more things before we get started + + + Academic Info + { + setCourseOpen(open); + setSemesterOpen(false); + setYearLevelOpen(false); + }} + setValue={setCourse} + placeholder="Choose your course" + containerStyle={{ + ...styles.dropdown_template, + ...{ zIndex: 3000 }, + }} + dropDownContainerStyle={{ backgroundColor: "white" }} + /> + { + setSemesterOpen(open); + setCourseOpen(false); + setYearLevelOpen(false); + }} + setValue={setSemester} + placeholder="Current semester" + containerStyle={{ + ...styles.dropdown_template, + ...{ zIndex: 2000 }, + }} + dropDownContainerStyle={{ backgroundColor: "white" }} + /> + { + setYearLevelOpen(open); + setSemesterOpen(false); + setCourseOpen(false); + }} + setValue={setYearLevel} + placeholder="Your Year Level" + containerStyle={{ + ...styles.dropdown_template, + ...{ zIndex: 1000 }, + }} + dropDownContainerStyle={{ backgroundColor: "white" }} + /> diff --git a/src/styles.tsx b/src/styles.tsx index d3dfd15..6700f9a 100644 --- a/src/styles.tsx +++ b/src/styles.tsx @@ -99,6 +99,11 @@ const styles = StyleSheet.create({ padding: 10, borderRadius: 8, }, + dropdown_template: { + borderRadius: 16, + width: "70%", + marginVertical: 6, + }, }); export default styles; From bccc8081505c3cba5858ae08cdc4159dc04c2430 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Thu, 6 Jul 2023 17:19:19 +0800 Subject: [PATCH 05/12] Improved revalidation and added drop down menus to onboarding --- App.tsx | 33 +++++---- package-lock.json | 36 ++++++++++ package.json | 1 + src/components/Api/Api.tsx | 63 +++++++++++++++++ src/interfaces/Interfaces.tsx | 18 +++++ src/routes/Onboarding/Onboarding.tsx | 88 +++++++++++++++++++++--- src/routes/Revalidation/Revalidation.tsx | 5 +- 7 files changed, 218 insertions(+), 26 deletions(-) diff --git a/App.tsx b/App.tsx index 8ab50a5..d1d9e46 100644 --- a/App.tsx +++ b/App.tsx @@ -17,6 +17,7 @@ import Onboarding from "./src/routes/Onboarding/Onboarding"; import Revalidation from "./src/routes/Revalidation/Revalidation"; import Activation from "./src/routes/Activation/Activation"; import { useState, useEffect } from "react"; +import { QueryClientProvider, QueryClient } from "@tanstack/react-query"; const Drawer = createDrawerNavigator(); @@ -35,6 +36,8 @@ const linking = { }, }; +const queryClient = new QueryClient(); + export default function App() { const [initialRoute, setInitialRoute] = useState(null); useEffect(() => { @@ -50,20 +53,22 @@ export default function App() { }, [initialRoute]); return ( - - - - - - - - - - + + + + + + + + + + + + ); } diff --git a/package-lock.json b/package-lock.json index 85b5680..02e3d1a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@react-navigation/native": "^6.1.7", "@react-navigation/native-stack": "^6.9.13", "@reduxjs/toolkit": "^1.9.5", + "@tanstack/react-query": "^4.29.19", "axios": "^1.4.0", "expo": "~48.0.18", "expo-linking": "~4.0.1", @@ -5202,6 +5203,41 @@ "@sinonjs/commons": "^3.0.0" } }, + "node_modules/@tanstack/query-core": { + "version": "4.29.19", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.29.19.tgz", + "integrity": "sha512-uPe1DukeIpIHpQi6UzIgBcXsjjsDaLnc7hF+zLBKnaUlh7jFE/A+P8t4cU4VzKPMFB/C970n/9SxtpO5hmIRgw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "4.29.19", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.29.19.tgz", + "integrity": "sha512-XiTIOHHQ5Cw1WUlHaD4fmVUMhoWjuNJlAeJGq7eM4BraI5z7y8WkZO+NR8PSuRnQGblpuVdjClQbDFtwxTtTUw==", + "dependencies": { + "@tanstack/query-core": "4.29.19", + "use-sync-external-store": "^1.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-native": "*" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, "node_modules/@types/hammerjs": { "version": "2.0.41", "resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.41.tgz", diff --git a/package.json b/package.json index d6d1135..3caa37d 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "@react-navigation/native": "^6.1.7", "@react-navigation/native-stack": "^6.9.13", "@reduxjs/toolkit": "^1.9.5", + "@tanstack/react-query": "^4.29.19", "axios": "^1.4.0", "expo": "~48.0.18", "expo-linking": "~4.0.1", diff --git a/src/components/Api/Api.tsx b/src/components/Api/Api.tsx index 75300cf..cae13ae 100644 --- a/src/components/Api/Api.tsx +++ b/src/components/Api/Api.tsx @@ -135,3 +135,66 @@ export function UserActivate(activation: ActivationParams) { } // App APIs + +export async function GetCourses() { + const accessToken = await getAccessToken(); + return instance + .get("/api/v1/courses/", { + headers: { + Authorization: `Bearer ${accessToken}`, + }, + }) + .then((response) => { + // console.log(JSON.stringify(response.data)); + return 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 getting courses", error_message); + return false; + }); +} + +export async function GetSemesters() { + const accessToken = await getAccessToken(); + return instance + .get("/api/v1/semesters/", { + headers: { + Authorization: `Bearer ${accessToken}`, + }, + }) + .then((response) => { + // console.log(JSON.stringify(response.data)); + return 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 getting semesters", error_message); + return false; + }); +} + +export async function GetYearLevels() { + const accessToken = await getAccessToken(); + return instance + .get("/api/v1/year_levels/", { + headers: { + Authorization: `Bearer ${accessToken}`, + }, + }) + .then((response) => { + // console.log(JSON.stringify(response.data)); + return 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 getting year levels", error_message); + return false; + }); +} diff --git a/src/interfaces/Interfaces.tsx b/src/interfaces/Interfaces.tsx index 6c6be0e..eae85db 100644 --- a/src/interfaces/Interfaces.tsx +++ b/src/interfaces/Interfaces.tsx @@ -46,3 +46,21 @@ export interface ActivationParams { uid: string; token: string; } + +export interface SemesterParams { + id: string; + name: string; + shortname: string; +} + +export interface YearLevelParams { + id: string; + name: string; + shortname: string; +} + +export interface CourseParams { + id: string; + name: string; + shortname: string; +} diff --git a/src/routes/Onboarding/Onboarding.tsx b/src/routes/Onboarding/Onboarding.tsx index 2a68a37..a763653 100644 --- a/src/routes/Onboarding/Onboarding.tsx +++ b/src/routes/Onboarding/Onboarding.tsx @@ -2,42 +2,100 @@ import * as React from "react"; import styles from "../../styles"; import { View, Text } from "react-native"; import { useNavigation } from "@react-navigation/native"; -import { RootDrawerParamList } from "../../interfaces/Interfaces"; +import { + CourseParams, + RootDrawerParamList, + SemesterParams, + YearLevelParams, +} from "../../interfaces/Interfaces"; import { colors } from "../../styles"; import { AnimatePresence, MotiView } from "moti"; import { useEffect, useState } from "react"; import Button from "../../components/Button/Button"; import DropDownPicker from "react-native-dropdown-picker"; import isStringEmpty from "../../components/IsStringEmpty/IsStringEmpty"; - +import { useQuery } from "@tanstack/react-query"; +import { + GetCourses, + GetSemesters, + GetYearLevels, +} from "../../components/Api/Api"; export default function Onboarding() { const navigation = useNavigation(); // const dispatch = useDispatch(); // const creds = useSelector((state: RootState) => state.auth.creds); - + const [error, setError] = useState(false); // Semesters const [semester, setSemester] = useState(""); const [semesterOpen, setSemesterOpen] = useState(false); const [semesters, setSemesters] = useState([ - { label: "1st Semester", value: "1st Sem" }, - { label: "2nd Semester", value: "2nd Sem" }, + { label: "1st Semester", value: "1st Sem", id: "" }, + { label: "2nd Semester", value: "2nd Sem", id: "" }, ]); + const semester_query = useQuery({ + queryKey: ["semesters"], + queryFn: GetSemesters, + onSuccess: (data) => { + let semesters = data.map((item: SemesterParams) => ({ + label: item.name, + value: item.shortname, + id: item.id, + })); + setSemesters(semesters); + }, + onError: () => { + setError(true); + }, + }); // Year Level const [year_level, setYearLevel] = useState(""); const [yearLevelOpen, setYearLevelOpen] = useState(false); const [year_levels, setYearLevels] = useState([ - { label: "1st Year", value: "1st Year" }, - { label: "2nd Year", value: "2nd Year" }, + { label: "1st Year", value: "1st Year", id: "" }, + { label: "2nd Year", value: "2nd Year", id: "" }, ]); + const yearlevel_query = useQuery({ + queryKey: ["year_levels"], + queryFn: GetYearLevels, + onSuccess: (data) => { + let year_levels = data.map((item: YearLevelParams) => ({ + label: item.name, + value: item.shortname, + id: item.id, + })); + setYearLevels(year_levels); + }, + onError: () => { + setError(true); + }, + }); // Course const [course, setCourse] = useState(""); const [courseOpen, setCourseOpen] = useState(false); const [courses, setCourses] = useState([ - { label: "Bachelor of Science in Information Technology", value: "BSIT" }, - { label: "Bachelor of Science in Computer Science", value: "BSCS" }, + { + label: "Bachelor of Science in Information Technology", + value: "BSIT", + id: "", + }, + { label: "Bachelor of Science in Computer Science", value: "BSCS", id: "" }, ]); const [complete, setComplete] = useState(false); - + const course_query = useQuery({ + queryKey: ["courses"], + queryFn: GetCourses, + onSuccess: (data) => { + let courses = data.map((item: CourseParams) => ({ + label: item.name, + value: item.shortname, + id: item.id, + })); + setCourses(courses); + }, + onError: () => { + setError(true); + }, + }); useEffect(() => { setComplete( !isStringEmpty(year_level) && @@ -45,7 +103,15 @@ export default function Onboarding() { !isStringEmpty(semester) ); }, [year_level, course, semester, complete]); - + if (error) { + return ( + + + Error loading details + + + ); + } return ( diff --git a/src/routes/Revalidation/Revalidation.tsx b/src/routes/Revalidation/Revalidation.tsx index df677e5..ad8ff05 100644 --- a/src/routes/Revalidation/Revalidation.tsx +++ b/src/routes/Revalidation/Revalidation.tsx @@ -20,7 +20,10 @@ export default function Revalidation() { if (response) { let user_info = await UserInfo(); await dispatch(setUser(user_info)); - if (!(user_info.year_level || user_info.course || user_info.semester)) { + if ( + !(user_info.year_level || user_info.course || user_info.semester) && + (await UserInfo()) + ) { await setTimeout(() => { navigation.navigate("Onboarding"); }, 700); From 3931f584722cfaa09f2a60e6ef8d0cbdf75510e4 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Thu, 6 Jul 2023 20:29:04 +0800 Subject: [PATCH 06/12] Finished onboarding page --- src/components/Api/Api.tsx | 23 ++++++++++- src/interfaces/Interfaces.tsx | 6 +++ src/routes/Onboarding/Onboarding.tsx | 52 +++++++++--------------- src/routes/Revalidation/Revalidation.tsx | 11 +++-- 4 files changed, 54 insertions(+), 38 deletions(-) diff --git a/src/components/Api/Api.tsx b/src/components/Api/Api.tsx index cae13ae..38d2a54 100644 --- a/src/components/Api/Api.tsx +++ b/src/components/Api/Api.tsx @@ -3,6 +3,7 @@ import AsyncStorage from "@react-native-async-storage/async-storage"; import { ActivationParams, LoginParams, + OnboardingParams, RegistrationParams, } from "../../interfaces/Interfaces"; @@ -113,7 +114,7 @@ export async function UserInfo() { }) .then((response) => { // console.log(JSON.stringify(response.data)); - return response.data; + return [true, response.data]; }) .catch((error) => { let error_message = ""; @@ -198,3 +199,23 @@ export async function GetYearLevels() { return false; }); } + +export async function OnboardingUpdateStudentInfo(info: OnboardingParams) { + const accessToken = await getAccessToken(); + const headers = { + Authorization: `Bearer ${accessToken}`, + }; + return instance + .patch("/api/v1/accounts/users/me/", info, { headers }) + .then((response) => { + console.log(JSON.stringify(response.data)); + return 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 updating onboarding info", error_message); + return false; + }); +} diff --git a/src/interfaces/Interfaces.tsx b/src/interfaces/Interfaces.tsx index eae85db..d9671ec 100644 --- a/src/interfaces/Interfaces.tsx +++ b/src/interfaces/Interfaces.tsx @@ -64,3 +64,9 @@ export interface CourseParams { name: string; shortname: string; } + +export interface OnboardingParams { + year_level: string; + course: string; + semester: string; +} diff --git a/src/routes/Onboarding/Onboarding.tsx b/src/routes/Onboarding/Onboarding.tsx index a763653..16eb9f5 100644 --- a/src/routes/Onboarding/Onboarding.tsx +++ b/src/routes/Onboarding/Onboarding.tsx @@ -19,18 +19,18 @@ import { GetCourses, GetSemesters, GetYearLevels, + OnboardingUpdateStudentInfo, } from "../../components/Api/Api"; export default function Onboarding() { const navigation = useNavigation(); // const dispatch = useDispatch(); // const creds = useSelector((state: RootState) => state.auth.creds); - const [error, setError] = useState(false); // Semesters const [semester, setSemester] = useState(""); const [semesterOpen, setSemesterOpen] = useState(false); const [semesters, setSemesters] = useState([ - { label: "1st Semester", value: "1st Sem", id: "" }, - { label: "2nd Semester", value: "2nd Sem", id: "" }, + { label: "1st Semester", value: "1st Sem" }, + { label: "2nd Semester", value: "2nd Sem" }, ]); const semester_query = useQuery({ queryKey: ["semesters"], @@ -38,21 +38,17 @@ export default function Onboarding() { onSuccess: (data) => { let semesters = data.map((item: SemesterParams) => ({ label: item.name, - value: item.shortname, - id: item.id, + value: item.name, })); setSemesters(semesters); }, - onError: () => { - setError(true); - }, }); // Year Level const [year_level, setYearLevel] = useState(""); const [yearLevelOpen, setYearLevelOpen] = useState(false); const [year_levels, setYearLevels] = useState([ - { label: "1st Year", value: "1st Year", id: "" }, - { label: "2nd Year", value: "2nd Year", id: "" }, + { label: "1st Year", value: "1st Year" }, + { label: "2nd Year", value: "2nd Year" }, ]); const yearlevel_query = useQuery({ queryKey: ["year_levels"], @@ -60,14 +56,10 @@ export default function Onboarding() { onSuccess: (data) => { let year_levels = data.map((item: YearLevelParams) => ({ label: item.name, - value: item.shortname, - id: item.id, + value: item.name, })); setYearLevels(year_levels); }, - onError: () => { - setError(true); - }, }); // Course const [course, setCourse] = useState(""); @@ -76,34 +68,21 @@ export default function Onboarding() { { label: "Bachelor of Science in Information Technology", value: "BSIT", - id: "", }, - { label: "Bachelor of Science in Computer Science", value: "BSCS", id: "" }, + { label: "Bachelor of Science in Computer Science", value: "BSCS" }, ]); - const [complete, setComplete] = useState(false); const course_query = useQuery({ queryKey: ["courses"], queryFn: GetCourses, onSuccess: (data) => { let courses = data.map((item: CourseParams) => ({ label: item.name, - value: item.shortname, - id: item.id, + value: item.name, })); setCourses(courses); }, - onError: () => { - setError(true); - }, }); - useEffect(() => { - setComplete( - !isStringEmpty(year_level) && - !isStringEmpty(course) && - !isStringEmpty(semester) - ); - }, [year_level, course, semester, complete]); - if (error) { + if (yearlevel_query.error || semester_query.error || course_query.error) { return ( @@ -213,8 +192,15 @@ export default function Onboarding() { style={styles.button_template} >