mirror of
https://github.com/lemeow125/StudE-Frontend.git
synced 2024-11-17 06:19:25 +08:00
Added avatar uploading
This commit is contained in:
parent
a3b3bd887f
commit
e4d64f3656
7 changed files with 84 additions and 12 deletions
8
app.json
8
app.json
|
@ -42,7 +42,13 @@
|
||||||
[
|
[
|
||||||
"expo-location",
|
"expo-location",
|
||||||
{
|
{
|
||||||
"locationAlwaysAndWhenInUsePermission": "Allow Stud-E to use your location."
|
"locationAlwaysAndWhenInUsePermission": "Allow StudE to use your location."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"expo-image-picker",
|
||||||
|
{
|
||||||
|
"photosPermission": "Allow StudE to take and send photos for sharing in-app"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
|
28
package-lock.json
generated
28
package-lock.json
generated
|
@ -16,6 +16,8 @@
|
||||||
"@tanstack/react-query": "^4.29.25",
|
"@tanstack/react-query": "^4.29.25",
|
||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
"expo": "~48.0.18",
|
"expo": "~48.0.18",
|
||||||
|
"expo-file-system": "~15.2.2",
|
||||||
|
"expo-image-picker": "~14.1.1",
|
||||||
"expo-intent-launcher": "~10.5.2",
|
"expo-intent-launcher": "~10.5.2",
|
||||||
"expo-linking": "~4.0.1",
|
"expo-linking": "~4.0.1",
|
||||||
"expo-location": "~15.1.1",
|
"expo-location": "~15.1.1",
|
||||||
|
@ -41,6 +43,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.20.0",
|
"@babel/core": "^7.20.0",
|
||||||
"@types/react": "~18.0.14",
|
"@types/react": "~18.0.14",
|
||||||
|
"@types/react-native-fetch-blob": "^0.10.7",
|
||||||
"typescript": "^4.9.4"
|
"typescript": "^4.9.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -5311,6 +5314,12 @@
|
||||||
"csstype": "^3.0.2"
|
"csstype": "^3.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/react-native-fetch-blob": {
|
||||||
|
"version": "0.10.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/react-native-fetch-blob/-/react-native-fetch-blob-0.10.7.tgz",
|
||||||
|
"integrity": "sha512-9UTvmUvArimShiENeR3xnRO71NcZjpTi7AcFAIbhdTIfqQOO2OK/I/DpUPXcZF/erffLxOoRkoXrZOxyBBWKRQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/scheduler": {
|
"node_modules/@types/scheduler": {
|
||||||
"version": "0.16.3",
|
"version": "0.16.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz",
|
||||||
|
@ -7458,6 +7467,25 @@
|
||||||
"expo": "*"
|
"expo": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/expo-image-loader": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/expo-image-loader/-/expo-image-loader-4.1.1.tgz",
|
||||||
|
"integrity": "sha512-ciEHVokU0f6w0eTxdRxLCio6tskMsjxWIoV92+/ZD37qePUJYMfEphPhu1sruyvMBNR8/j5iyOvPFVGTfO8oxA==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"expo": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/expo-image-picker": {
|
||||||
|
"version": "14.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/expo-image-picker/-/expo-image-picker-14.1.1.tgz",
|
||||||
|
"integrity": "sha512-SvWtnkLW7jp5Ntvk3lVcRQmhFYja8psmiR7O6P/+7S6f4llt3vaFwb4I3+pUXqJxxpi7BHc2+95qOLf0SFOIag==",
|
||||||
|
"dependencies": {
|
||||||
|
"expo-image-loader": "~4.1.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"expo": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/expo-intent-launcher": {
|
"node_modules/expo-intent-launcher": {
|
||||||
"version": "10.5.2",
|
"version": "10.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/expo-intent-launcher/-/expo-intent-launcher-10.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/expo-intent-launcher/-/expo-intent-launcher-10.5.2.tgz",
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
"@tanstack/react-query": "^4.29.25",
|
"@tanstack/react-query": "^4.29.25",
|
||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
"expo": "~48.0.18",
|
"expo": "~48.0.18",
|
||||||
|
"expo-file-system": "~15.2.2",
|
||||||
|
"expo-image-picker": "~14.1.1",
|
||||||
"expo-intent-launcher": "~10.5.2",
|
"expo-intent-launcher": "~10.5.2",
|
||||||
"expo-linking": "~4.0.1",
|
"expo-linking": "~4.0.1",
|
||||||
"expo-location": "~15.1.1",
|
"expo-location": "~15.1.1",
|
||||||
|
@ -42,6 +44,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.20.0",
|
"@babel/core": "^7.20.0",
|
||||||
"@types/react": "~18.0.14",
|
"@types/react": "~18.0.14",
|
||||||
|
"@types/react-native-fetch-blob": "^0.10.7",
|
||||||
"typescript": "^4.9.4"
|
"typescript": "^4.9.4"
|
||||||
},
|
},
|
||||||
"private": true
|
"private": true
|
||||||
|
|
|
@ -17,7 +17,7 @@ if (__DEV__) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Switch this on if you wanna run production URLs while in development
|
// Switch this on if you wanna run production URLs while in development
|
||||||
let use_production = true;
|
let use_production = false;
|
||||||
if (use_production) {
|
if (use_production) {
|
||||||
backendURL = "https://stude.keannu1.duckdns.org";
|
backendURL = "https://stude.keannu1.duckdns.org";
|
||||||
backendURLWebsocket = "ws://stude.keannu1.duckdns.org";
|
backendURLWebsocket = "ws://stude.keannu1.duckdns.org";
|
||||||
|
@ -142,6 +142,7 @@ export async function UserInfo() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function PatchUserInfo(info: PatchStudentData) {
|
export async function PatchUserInfo(info: PatchStudentData) {
|
||||||
|
console.log("API", JSON.stringify(info));
|
||||||
const config = await GetConfig();
|
const config = await GetConfig();
|
||||||
return instance
|
return instance
|
||||||
.patch("/api/v1/accounts/users/me/", info, config)
|
.patch("/api/v1/accounts/users/me/", info, config)
|
||||||
|
@ -153,7 +154,7 @@ export async function PatchUserInfo(info: PatchStudentData) {
|
||||||
let error_message = "";
|
let error_message = "";
|
||||||
if (error.response) error_message = error.response.data;
|
if (error.response) error_message = error.response.data;
|
||||||
else error_message = "Unable to reach servers";
|
else error_message = "Unable to reach servers";
|
||||||
// console.log(error_message);
|
console.log(error_message);
|
||||||
return [false, error_message];
|
return [false, error_message];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,6 +96,11 @@ export interface Subject {
|
||||||
export type Subjects = Array<Subject>;
|
export type Subjects = Array<Subject>;
|
||||||
export type SubjectParams = [boolean, Subjects];
|
export type SubjectParams = [boolean, Subjects];
|
||||||
|
|
||||||
|
export type avatar = {
|
||||||
|
uri: string;
|
||||||
|
type: string;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
// For dropdown menu
|
// For dropdown menu
|
||||||
|
|
||||||
export interface OnboardingParams {
|
export interface OnboardingParams {
|
||||||
|
@ -112,6 +117,7 @@ export interface PatchStudentData {
|
||||||
subjects?: any[] | null; // To-do, replace 'any' with your actual type
|
subjects?: any[] | null; // To-do, replace 'any' with your actual type
|
||||||
year_level?: string | null;
|
year_level?: string | null;
|
||||||
irregular?: boolean | null;
|
irregular?: boolean | null;
|
||||||
|
avatar?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StudentData {
|
export interface StudentData {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import {
|
||||||
TextInput,
|
TextInput,
|
||||||
NativeSyntheticEvent,
|
NativeSyntheticEvent,
|
||||||
TextInputChangeEventData,
|
TextInputChangeEventData,
|
||||||
|
Pressable,
|
||||||
} from "react-native";
|
} from "react-native";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import {
|
import {
|
||||||
|
@ -32,13 +33,14 @@ import {
|
||||||
} from "../../components/Api/Api";
|
} 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 { ValueType } from "react-native-dropdown-picker";
|
|
||||||
import AnimatedContainerNoScroll from "../../components/AnimatedContainer/AnimatedContainerNoScroll";
|
import AnimatedContainerNoScroll from "../../components/AnimatedContainer/AnimatedContainerNoScroll";
|
||||||
import BouncyCheckbox from "react-native-bouncy-checkbox";
|
import BouncyCheckbox from "react-native-bouncy-checkbox";
|
||||||
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 { useDispatch } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
import { setUser as setUserinState } from "../../features/redux/slices/UserSlice/UserSlice";
|
import { setUser as setUserinState } from "../../features/redux/slices/UserSlice/UserSlice";
|
||||||
|
import * as ImagePicker from "expo-image-picker";
|
||||||
|
import * as FileSystem from "expo-file-system";
|
||||||
|
|
||||||
export default function UserInfoPage() {
|
export default function UserInfoPage() {
|
||||||
const logged_in_user = useSelector((state: RootState) => state.user.user);
|
const logged_in_user = useSelector((state: RootState) => state.user.user);
|
||||||
|
@ -71,9 +73,9 @@ export default function UserInfoPage() {
|
||||||
year_level: data[1].year_level,
|
year_level: data[1].year_level,
|
||||||
semester: data[1].semester,
|
semester: data[1].semester,
|
||||||
course: data[1].course,
|
course: data[1].course,
|
||||||
avatar: data[1].avatar,
|
|
||||||
student_id_number: data[1].student_id_number,
|
student_id_number: data[1].student_id_number,
|
||||||
irregular: data[1].irregular,
|
irregular: data[1].irregular,
|
||||||
|
avatar: data[1].avatar,
|
||||||
});
|
});
|
||||||
setSelectedCourse(data[1].course);
|
setSelectedCourse(data[1].course);
|
||||||
setSelectedSemester(data[1].semester);
|
setSelectedSemester(data[1].semester);
|
||||||
|
@ -157,15 +159,39 @@ export default function UserInfoPage() {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Profile photo
|
// Profile photo
|
||||||
|
const pickImage = async () => {
|
||||||
|
// No permissions request is necessary for launching the image library
|
||||||
|
let result = await ImagePicker.launchImageLibraryAsync({
|
||||||
|
mediaTypes: ImagePicker.MediaTypeOptions.All,
|
||||||
|
allowsEditing: true,
|
||||||
|
aspect: [4, 3],
|
||||||
|
quality: 1,
|
||||||
|
});
|
||||||
|
if (!result.canceled) {
|
||||||
|
const encodedImage = await FileSystem.readAsStringAsync(
|
||||||
|
result.assets[0].uri,
|
||||||
|
{ encoding: "base64" }
|
||||||
|
);
|
||||||
|
mutation.mutate({
|
||||||
|
avatar: encodedImage,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
function Avatar() {
|
function Avatar() {
|
||||||
if (user.avatar) {
|
if (user.avatar) {
|
||||||
return <Image source={{ uri: user.avatar }} style={styles.profile} />;
|
return (
|
||||||
|
<Pressable onPress={pickImage}>
|
||||||
|
<Image source={{ uri: user.avatar }} style={styles.profile} />
|
||||||
|
</Pressable>
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
|
<Pressable onPress={pickImage}>
|
||||||
<Image
|
<Image
|
||||||
source={require("../../img/user_profile_placeholder.png")}
|
source={require("../../img/user_profile_placeholder.png")}
|
||||||
style={{ ...styles.profile, ...{ marginRight: 48 } }}
|
style={{ ...styles.profile, ...{ marginRight: 48 } }}
|
||||||
/>
|
/>
|
||||||
|
</Pressable>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -350,7 +376,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={() => {
|
onPress={async () => {
|
||||||
setYearLevelOpen(false);
|
setYearLevelOpen(false);
|
||||||
setSemesterOpen(false);
|
setSemesterOpen(false);
|
||||||
setCourseOpen(false);
|
setCourseOpen(false);
|
||||||
|
|
|
@ -182,6 +182,8 @@ const styles = StyleSheet.create({
|
||||||
borderRadius: 150 / 2,
|
borderRadius: 150 / 2,
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
padding: 0,
|
padding: 0,
|
||||||
|
borderColor: colors.primary_2,
|
||||||
|
borderWidth: 3,
|
||||||
},
|
},
|
||||||
input: {
|
input: {
|
||||||
paddingHorizontal: 8,
|
paddingHorizontal: 8,
|
||||||
|
|
Loading…
Reference in a new issue