Skip to content

Commit

Permalink
Account Page still not done yet.
Browse files Browse the repository at this point in the history
Tests Written.
Created User Tokens With Verification
Handle different users + account setting page #33
Co-authored-by: rhit-norflwe <rhit-norflwe@users.noreply.github.com>
  • Loading branch information
rhit-villencr committed Jan 11, 2025
1 parent f398c68 commit c2c8b98
Show file tree
Hide file tree
Showing 16 changed files with 311 additions and 35 deletions.
2 changes: 1 addition & 1 deletion app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export default function Layout() {
cardStyle: { backgroundColor: 'white' }
}}
>
<Stack.Screen name="index" component={App} />
<Stack.Screen name="index" component={App} options={{ headerShown: false }} />
<Stack.Screen name="home" component={TaskScreen} />
<Stack.Screen name="healthTracker" component={HealthTracker} />
<Stack.Screen name="mealTracker" component={MealTracking} />
Expand Down
14 changes: 12 additions & 2 deletions app/addEventPage.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import React, { useState } from 'react';
import React, { useCallback, useState } from 'react';
import { View, TextInput, Text, TouchableOpacity, ScrollView } from 'react-native';
import DateTimePicker from '@react-native-community/datetimepicker';
import { Dropdown } from 'react-native-element-dropdown';
import { styles } from './styles';
import { RootStackParamList } from '@/components/Types';
import { StackNavigationProp } from '@react-navigation/stack';
import { useNavigation } from '@react-navigation/native';
import { useFocusEffect, useNavigation } from '@react-navigation/native';
import MultiSelect from 'react-native-multiple-select';
import { cLog } from './log';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { verifyToken } from './constants';

interface FormProps {
title: string;
Expand Down Expand Up @@ -47,6 +48,8 @@ const GenericAddPageForm: React.FC<FormProps> = ({ title, initialData, fields, m
};

const handleSave = async () => {
const isTokenValid = await verifyToken(navigation);
if (!isTokenValid) return;
const formattedData = {
...formData,
event_date: formData.event_date?.toISOString().split('T')[0],
Expand All @@ -72,6 +75,13 @@ const GenericAddPageForm: React.FC<FormProps> = ({ title, initialData, fields, m
const handleIngredientChange = (selectedItems: string[]) => {
handleChange('ingredients', selectedItems);
};

useFocusEffect(
useCallback(() => {
verifyToken(navigation);
}, [])
);

return (
<ScrollView contentContainerStyle={styles.addContainer}>
<Text style={styles.sectionHeader}>{title}</Text>
Expand Down
20 changes: 20 additions & 0 deletions app/constants.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import AsyncStorage from "@react-native-async-storage/async-storage";
import axios from "axios";
import { cLog } from './log';

// export const IPAddr = "http://34.204.83.156:8080" // For AWS
export const IPAddr = "http://137.112.196.132:8080" // For local testing on laptop
export const logging = true;
Expand Down Expand Up @@ -50,4 +54,20 @@ export const getPageFromEventType = (eventType) => {
default:
return eventType;
}
}

export const verifyToken = async (navigation) => {
const hit = IPAddr + '/checkLogin';
const storedUserName = await AsyncStorage.getItem('userName');
const storedToken = await AsyncStorage.getItem('token');
const storedUserId = await AsyncStorage.getItem('userId');
const response = await axios.put(hit, { userName: storedUserName, token: storedToken, userId: storedUserId });
if (!response.data) {
cLog('Token verification failed');
await AsyncStorage.clear();
navigation.navigate('index');
return false;
}
cLog('Verify response:', response.data);
return true;
}
9 changes: 5 additions & 4 deletions app/home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,13 @@ export default function TaskScreen() {
}
};

const fetchHeader = async () => {
const name = await AsyncStorage.getItem('name');
setHeader(name);
};

useFocusEffect(
useCallback(() => {
const fetchHeader = async () => {
const name = await AsyncStorage.getItem('name');
setHeader(name);
};
fetchHeader();
fetchAllEvents();
}, [])
Expand Down
35 changes: 27 additions & 8 deletions app/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,34 @@ export default function TaskScreen() {

const checkLogin = async () => {
try {
const userId = await AsyncStorage.getItem('userId');
cLog('User id:', userId);
if (userId && !isNaN(Number(userId))) {
cLog("Navigating Home");
navigation.navigate('home');
} else {
cLog('User not logged in');
const storedToken = await AsyncStorage.getItem('token') || '';
const storedUserName = await AsyncStorage.getItem('userName') || '';

// Check if we have a valid token and username
if (!storedToken || !storedUserName) {
console.log('No valid token or username found');
return;
}

const hit = IPAddr + '/checkLogin';
const response = await axios.put(hit, { userName: storedUserName, token: storedToken });

cLog('Login response:', response.data);
if (!response.data) {
return;
}

const userInfo = response.data.split(",");
await AsyncStorage.setItem('userId', userInfo[0]);
await AsyncStorage.setItem('userName', userInfo[1]);
await AsyncStorage.setItem('email', userInfo[2]);
await AsyncStorage.setItem('name', userInfo[3]);
await AsyncStorage.setItem('token', userInfo[4]);

cLog('User id saved:', response.data.userId);
navigation.navigate('home');
} catch (error) {
console.error('Error checking login:', error);
console.error('Error logging in:', error);
}
}

Expand All @@ -46,6 +64,7 @@ export default function TaskScreen() {
await AsyncStorage.setItem('userName', userInfo[1]);
await AsyncStorage.setItem('email', userInfo[2]);
await AsyncStorage.setItem('name', userInfo[3]);
await AsyncStorage.setItem('token', userInfo[4]);
cLog('User id saved:', response.data.userId);
navigation.navigate('home');
} catch (error) {
Expand Down
24 changes: 15 additions & 9 deletions app/mainPageTemplate.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import React, { useState } from 'react';
import React, { useCallback, useState } from 'react';
import { View, Text, FlatList, TouchableOpacity } from 'react-native';
import BouncyCheckbox from "react-native-bouncy-checkbox";
import { Calendar } from 'react-native-calendars';
import { styles } from './styles';
import { Ionicons } from "@expo/vector-icons";
import { RootStackParamList, Task } from '../components/Types';
import { useNavigation } from '@react-navigation/native';
import { useFocusEffect, useNavigation } from '@react-navigation/native';
import { StackNavigationProp } from '@react-navigation/stack';
import { cLog } from './log';
import { getPageFromEventType, getPageName } from './constants';
import { getPageFromEventType, getPageName, verifyToken } from './constants';
// import { cLog } from './log';

interface FormProps {
Expand All @@ -21,7 +21,7 @@ interface FormProps {

const GenericMainPageForm: React.FC<FormProps> = ({ title, header, nextPage, thisPage, tasks }) => {
const [selectedDate, setSelectedDate] = useState('');
const [isCalendarVisible, setIsCalendarVisible] = useState(true);
const [isCalendarVisible, setIsCalendarVisible] = useState(true);

type Prop = StackNavigationProp<RootStackParamList, keyof RootStackParamList>;
const navigation = useNavigation<Prop>();
Expand All @@ -33,10 +33,10 @@ const GenericMainPageForm: React.FC<FormProps> = ({ title, header, nextPage, thi
const handleViewPress = (item: Task) => {
// cLog(item);
const route = { ...item, thisPage };
if(route.thisPage === 'index'){
if (route.thisPage === 'index') {
route.thisPage = getPageFromEventType(route.event.event_type) as keyof RootStackParamList;
}
cLog("Route:",route);
cLog("Route:", route);
navigation.navigate(getPageName(route.thisPage) as any, { event: route });
}

Expand All @@ -59,6 +59,12 @@ const GenericMainPageForm: React.FC<FormProps> = ({ title, header, nextPage, thi
</TouchableOpacity>
);

useFocusEffect(
useCallback(() => {
verifyToken(navigation);
}, [])
);

return (
<View style={styles.container}>
<View>
Expand All @@ -77,9 +83,9 @@ const GenericMainPageForm: React.FC<FormProps> = ({ title, header, nextPage, thi
<Text style={styles.calendarHeader}>Events</Text>
<TouchableOpacity onPress={() => setIsCalendarVisible(!isCalendarVisible)}>
<Ionicons
name={isCalendarVisible ? "chevron-down-outline" : "chevron-forward-outline"}
size={24}
color="#9b59b6"
name={isCalendarVisible ? "chevron-down-outline" : "chevron-forward-outline"}
size={24}
color="#9b59b6"
/>
</TouchableOpacity>
</View>
Expand Down
16 changes: 13 additions & 3 deletions app/viewEventPage.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import React, { useState } from 'react';
import React, { useCallback, useState } from 'react';
import { View, TextInput, Text, TouchableOpacity, ScrollView } from 'react-native';
import DateTimePicker from '@react-native-community/datetimepicker';
import { Dropdown } from 'react-native-element-dropdown';
import { styles } from './styles';
import { RootStackParamList } from '@/components/Types';
import { StackNavigationProp } from '@react-navigation/stack';
import { useNavigation } from '@react-navigation/native';
import { useFocusEffect, useNavigation } from '@react-navigation/native';
import MultiSelect from 'react-native-multiple-select';
import { verifyToken } from './constants';

interface FormProps {
title: string;
Expand Down Expand Up @@ -44,7 +45,9 @@ const GenericViewPageForm: React.FC<FormProps> = ({ title, initialData, fields,
}
};

const handleSave = () => {
const handleSave = async () => {
const isTokenValid = await verifyToken(navigation); // Await the token verification
if (!isTokenValid) return;
const formattedData = {
...formData,
event_date: formData.event_date?.toISOString().split('T')[0],
Expand All @@ -66,6 +69,13 @@ const GenericViewPageForm: React.FC<FormProps> = ({ title, initialData, fields,
const handleIngredientChange = (selectedItems: string[]) => {
handleChange('ingredients', selectedItems);
};

useFocusEffect(
useCallback(() => {
verifyToken(navigation);
}, [])
);

return (
<ScrollView contentContainerStyle={styles.addContainer}>
<Text style={styles.sectionHeader}>{title}</Text>
Expand Down
Binary file modified backend/omniplanner.db
Binary file not shown.
4 changes: 4 additions & 0 deletions backend/omniplanner/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ dependencies {
implementation 'com.google.oauth-client:google-oauth-client-jetty:1.34.1'
implementation 'com.google.apis:google-api-services-calendar:v3-rev20220715-2.0.0'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'

runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5'

testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.mockito:mockito-core:5.3.1'
Expand Down
Binary file modified backend/omniplanner/omniplanner.db
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public class User {
private String userName;
private String passwordHash;
private String salt;
private String tempToken;

public int getId() {
return id;
Expand Down Expand Up @@ -76,4 +77,16 @@ public String getSalt() {
public void setSalt(String salt) {
this.salt = salt;
}

public String getTempToken() {
return tempToken;
}

public void setTempToken(String tempToken) {
this.tempToken = tempToken;
}

public String toString() {
return this.id +"," + this.userName + "," + this.email + "," + this.name + "," + this.tempToken;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,26 @@ public List<User> getUsers() {
return userService.getAllUsers();
}

@PutMapping("/checkLogin")
public String checkLogin(@RequestBody String loginRequest) {
try {
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(loginRequest);
String username = jsonNode.get("userName").asText();
String token = jsonNode.get("token").asText();
String userId = jsonNode.has("userId") ? jsonNode.get("userId").asText() : null;

if(userId != null && !userId.isEmpty()) {
return userService.checkLogin(username, token, userId);
}

return userService.checkLogin(username, token);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}

@PutMapping("/login")
public String login(@RequestBody String loginRequest) {
try {
Expand Down
Loading

0 comments on commit c2c8b98

Please sign in to comment.