Integrate api for login

This commit is contained in:
toledo 2023-04-08 14:18:58 +08:00
parent 0318f4eb53
commit c597e9eaab
11 changed files with 4923 additions and 466 deletions

View file

@ -10,11 +10,15 @@ import UserInfo from "./src/Routes/UserInfo/UserInfo";
import AddNote from "./src/Routes/AddNote/AddNote";
import Login from "./src/Routes/Login/Login";
import Register from "./src/Routes/Register/Register";
import { Provider } from "react-redux";
import Store from "./src/Features/Redux/Store/Store";
import { QueryClient, QueryClientProvider } from "react-query";
const Drawer = createDrawerNavigator();
export default function App() {
return (
<Provider store={Store}>
<NavigationContainer>
<Drawer.Navigator
initialRouteName="Home"
@ -28,5 +32,6 @@ export default function App() {
<Drawer.Screen name="Register" component={Register} />
</Drawer.Navigator>
</NavigationContainer>
</Provider>
);
}

4969
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -9,21 +9,30 @@
"web": "expo start --web"
},
"dependencies": {
"@expo/webpack-config": "^18.0.1",
"@react-navigation/drawer": "^6.6.2",
"@react-navigation/native": "^6.1.6",
"@reduxjs/toolkit": "^1.9.3",
"axios": "^1.3.4",
"expo": "~48.0.5",
"expo-status-bar": "~1.4.4",
"react": "18.2.0",
"react-native": "0.71.3",
"react-dom": "18.2.0",
"react-native": "0.71.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-native-svg": "13.4.0",
"react-native-web": "~0.18.10",
"react-query": "^3.39.3",
"react-redux": "^8.0.5",
"redux": "^4.2.1"
},
"devDependencies": {
"@babel/core": "^7.20.0",
"@types/react": "~18.0.14",
"@types/react-native": "^0.71.5",
"typescript": "^4.9.4"
},
"private": true

143
src/Components/Api/Api.tsx Normal file
View file

@ -0,0 +1,143 @@
import axios from "axios";
import {
ActivationParams,
UpdateNoteParams,
AddNoteParams,
LoginParams,
RegistrationParams,
} from "../../Interfaces/Interfaces";
// Note APIs
export function GetNotes() {
const token = JSON.parse(localStorage.getItem("token") || "{}");
return axios
.get("http://localhost:8000/api/v1/notes/", {
headers: {
Authorization: "Token " + token,
},
})
.then((response) => {
return response.data;
});
}
export function GetNote(id: number) {
const token = JSON.parse(localStorage.getItem("token") || "{}");
return axios
.get("http://localhost:8000/api/v1/notes/" + id + "/", {
headers: {
Authorization: "Token " + token,
},
})
.then((response) => {
return response.data;
});
}
export function UpdateNote(note: UpdateNoteParams) {
const token = JSON.parse(localStorage.getItem("token") || "{}");
return axios
.patch("http://localhost:8000/api/v1/notes/" + note.id + "/", note, {
headers: {
Authorization: "Token " + token,
},
})
.then((response) => {
return response.data;
})
.catch((error) => {
console.log("Error updating note", error);
return error;
});
}
export function AddNote(note: AddNoteParams) {
const token = JSON.parse(localStorage.getItem("token") || "{}");
return axios
.post("http://localhost:8000/api/v1/notes/", note, {
headers: {
Authorization: "Token " + token,
},
})
.then((response) => {
return response.data;
})
.catch((error) => {
console.log("Error adding note", error);
return error;
});
}
export function DeleteNote(id: number) {
const token = JSON.parse(localStorage.getItem("token") || "{}");
return axios
.delete("http://localhost:8000/api/v1/notes/" + id + "/", {
headers: {
Authorization: "Token " + token,
},
})
.catch((error) => {
console.log("Error deleting note", error);
return error;
});
}
// User APIs
export function UserRegister(register: RegistrationParams) {
return axios
.post("http://localhost:8000/api/v1/accounts/users/", register)
.then(async (response) => {
console.log(response.data);
return true;
})
.catch((error) => {
console.log("Registration failed: " + error);
return false;
});
}
export function UserLogin(user: LoginParams) {
return axios
.post("http://localhost:8000/api/v1/accounts/token/login/", user)
.then(async (response) => {
localStorage.setItem("token", JSON.stringify(response.data.auth_token));
console.log(
"Login Success! Stored Token: ",
JSON.parse(localStorage.getItem("token") || "{}")
);
return true;
})
.catch((error) => {
console.log("Login Failed: " + error);
return false;
});
}
export function UserInfo() {
const token = JSON.parse(localStorage.getItem("token") || "{}");
return axios
.get("http://localhost:8000/api/v1/accounts/users/me/", {
headers: {
Authorization: "Token " + token,
},
})
.then((response) => {
console.log(response.data);
return response.data;
});
}
export function UserActivate(activation: ActivationParams) {
return axios
.post("http://localhost:8000/api/v1/accounts/users/activation/", activation)
.then(async (response) => {
console.log("Activation Success");
return true;
})
.catch((error) => {
console.log("Activation failed: " + error);
return false;
});
}

View file

@ -0,0 +1,33 @@
import { createSlice } from "@reduxjs/toolkit";
export const LoggedInUserSlice = createSlice({
name: "Login",
initialState: {
value: {
email: "",
id: 0,
username: "",
},
},
reducers: {
SetUser: (state, action) => {
state.value = {
email: action.payload.email,
id: action.payload.id,
username: action.payload.username,
};
},
UnsetUser: (state) => {
state.value = {
email: "",
id: 0,
username: "",
};
},
},
});
// Action creators are generated for each case reducer function
export const { SetUser, UnsetUser } = LoggedInUserSlice.actions;
export default LoggedInUserSlice.reducer;

View file

@ -0,0 +1,21 @@
import { createSlice } from "@reduxjs/toolkit";
export const LoginSlice = createSlice({
name: "Login",
initialState: {
logged_in: false,
},
reducers: {
SetLoggedIn: (state) => {
state.logged_in = !state.logged_in;
},
SetLoggedOut: (state) => {
state.logged_in = !state.logged_in;
},
},
});
// Action creators are generated for each case reducer function
export const { SetLoggedIn, SetLoggedOut } = LoginSlice.actions;
export default LoginSlice.reducer;

View file

@ -0,0 +1,16 @@
import { configureStore } from "@reduxjs/toolkit";
import LoginReducer from "../Slices/LoginSlice/LoginSlice";
import LoggedInUserReucer from "../Slices/LoggedInUserSlice/LoggedInUserSlice";
const store = configureStore({
reducer: {
logged_in: LoginReducer,
logged_in_user: LoggedInUserReucer,
},
});
export default store;
// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;

View file

@ -6,3 +6,62 @@ export interface IconProps {
export interface RootDrawerParamList {
navigate: any;
}
// Redux Interfaces
export interface LoginState {
Login: { logged_in: boolean };
}
export interface LoggedInUserState {
LoggedInUser: {
value: {
email: string;
id: number;
username: string;
};
};
}
// Component Props Interfaces
export interface NoteProps {
title: string;
content: string;
id: number;
date_created: Date;
owner: string;
}
export interface IconProps {
size: number;
color: string;
}
// API Interfaces
export interface RegistrationParams {
email: string;
username: string;
password: string;
}
export interface LoginParams {
username: string;
password: string;
}
export interface ActivationParams {
uid: string;
token: string;
}
export interface AddNoteParams {
title: string;
content: string;
}
export interface UpdateNoteParams {
id: number;
title: string;
content: string;
}

View file

@ -3,8 +3,9 @@ import {View, Text} from 'react-native';
import styles from '../../styles';
import Background from '../../Components/Background/Background';
import AppIcon from '../../Components/Icons/AppIcon/AppIcon';
import { useDispatch } from "react-redux";
export default function Home() {
const dispatch = useDispatch();
return (
<Background>
<View

View file

@ -2,17 +2,25 @@ import * as React from 'react';
import { View, Text, TextInput } from 'react-native';
import styles from '../../styles';
import Background from '../../Components/Background/Background';
import { SafeAreaView} from "react-native";
import { SafeAreaView, NativeSyntheticEvent, TextInputChangeEventData } from "react-native";
import { StatusBar } from "expo-status-bar";
import { useState } from "react";
import { TouchableOpacity, } from "react-native";
import { NavigationHelpersContext, useNavigation } from "@react-navigation/native";
import { useDispatch } from "react-redux";
import { SetUser } from "../../Features/Redux/Slices/LoggedInUserSlice/LoggedInUserSlice";
import { SetLoggedIn } from "../../Features/Redux/Slices/LoginSlice/LoginSlice";
import { UserInfo, UserLogin } from "../../Components/Api/Api";
import { RootDrawerParamList } from "../../Interfaces/Interfaces";
export default function Login() {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const navigation = useNavigation<RootDrawerParamList>();
const dispatch = useDispatch();
const [user, setUser] = useState({
username: "",
password: "",
});
const [error, setError] = useState("");
return (
<Background>
<Text style={{ ...styles.text_white, ...{ fontSize: 32 } }}></Text>
@ -25,8 +33,12 @@ export default function Login() {
style={styles.TextInput}
placeholder="Username"
placeholderTextColor="white"
onChangeText={setUsername}
value={username}
value={user.username}
maxLength={20}
onChange={(e: NativeSyntheticEvent<TextInputChangeEventData>): void => {
setUser({ ...user, username: e.nativeEvent.text });
console.log(user.username)
}}
/>
</View>
@ -36,17 +48,34 @@ export default function Login() {
placeholder="Password"
placeholderTextColor="white"
secureTextEntry={true}
onChangeText={setPassword}
value={password}
value={user.password}
onChange={(e: NativeSyntheticEvent<TextInputChangeEventData>): void => {
setUser({ ...user, password: e.nativeEvent.text });
console.log(user.password)
}}
/>
</View>
<TouchableOpacity>
<Text style={styles.forgot_button}>Forgot Password?</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.loginBtn}>
<TouchableOpacity onPress={async () => {
setUser({
username: "",
password: "",
});
if (await UserLogin(user)) {
await dispatch(SetLoggedIn());
await dispatch(SetUser(await UserInfo()));
navigation.navigate("Home");
} else {
setError("Invalid Login");
}
}}
style={styles.loginBtn}>
<Text style={styles.loginText}>LOGIN</Text>
</TouchableOpacity>
<Text style={styles.text_small_red}>{error}</Text>
<TouchableOpacity style={styles.registerbtn}>
<Text style={styles.registertext}>REGISTER</Text>
</TouchableOpacity>

View file

@ -103,6 +103,12 @@ const styles = StyleSheet.create({
marginBottom: 30,
color: 'white',
},
text_small_red: {
color: "#bc231e",
fontSize: 10,
fontWeight: "bold",
textAlign: "center",
},
});
export default styles;