Skip to content

Commit

Permalink
Feature/login (#18)
Browse files Browse the repository at this point in the history
* feat(Firebase.config): Created the authentication connection

Created the login, the signup, and authstate functions

* Added dependency for firebase/auth

* Added stub for login landing page. Updated mod and sum

* Updated firebase dependency

* Login tests

* feat(Client): Created a simple login page

Auth works + login page works + alerts

* fix(Auth): Makes react native remember login

* fix(Login): Ready for PR

* fix(PR-Changes): Added the fixes for PR

* fix: deleting package.json

* refactor: Fixed gitignore

* fix(login-navigation): added simple navigation to login page for added functionality

---------

Co-authored-by: bedrockdude10 <[email protected]>
Co-authored-by: andrewcaplan1 <[email protected]>
Co-authored-by: Andrew Caplan <[email protected]>
  • Loading branch information
4 people authored Jan 31, 2024
1 parent b2b377a commit 139fbd8
Show file tree
Hide file tree
Showing 9 changed files with 203 additions and 3 deletions.
8 changes: 7 additions & 1 deletion client/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ import { Text } from 'react-native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { NavigationContainer, NavigationProp } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import LoginPage from './screens/Login';
import MedList from './screens/Medication';
import Home from './assets/home.svg';
import DocPickerButton from './components/DocPickerButton';

export type ScreenNames = ['BottomNav', 'Landing', 'TEMP-FileUpload'];
export type ScreenNames = ['BottomNav', 'Landing', 'TEMP-FileUpload', 'Login'];
export type RootStackParamList = Record<ScreenNames[number], any>;
export type StackNavigation = NavigationProp<RootStackParamList>;

Expand All @@ -19,6 +20,11 @@ export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Login"
options={{ headerShown: true }}
component={LoginPage}
/>
<Stack.Screen
name="BottomNav"
options={{ headerShown: false }}
Expand Down
21 changes: 21 additions & 0 deletions client/firebase.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Import the functions you need from the SDKs you need
import { initializeApp } from 'firebase/app';
import { initializeAuth, getReactNativePersistence } from 'firebase/auth';
import ReactNativeAsyncStorage from '@react-native-async-storage/async-storage';

// Your web app's Firebase configuration
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
const firebaseConfig = {
apiKey: 'AIzaSyA8Ox_r-nkPjzvmrqI4uDrBVHuKDUsOKfU',
authDomain: 'care-wallet-generate.firebaseapp.com',
projectId: 'care-wallet-generate',
storageBucket: 'care-wallet-generate.appspot.com',
messagingSenderId: '567693879422',
appId: '1:567693879422:web:97b722f9c4eb38e484d02f',
measurementId: 'G-NW8HWJ14V4'
};

const app = initializeApp(firebaseConfig);
export const auth = initializeAuth(app, {
persistence: getReactNativePersistence(ReactNativeAsyncStorage)
});
7 changes: 5 additions & 2 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
"check": "prettier --check ."
},
"dependencies": {
"@firebase/auth": "^1.5.1",
"@react-native-async-storage/async-storage": "^1.21.0",
"@fortawesome/fontawesome-svg-core": "^6.5.1",
"@fortawesome/free-brands-svg-icons": "^6.5.1",
"@fortawesome/free-regular-svg-icons": "^6.5.1",
Expand All @@ -25,12 +27,13 @@
"expo-document-picker": "~11.5.4",
"expo-file-system": "~15.4.5",
"expo-status-bar": "~1.6.0",
"firebase": "^10.7.2",
"nativewind": "^2.0.11",
"react": "18.2.0",
"react-native": "0.72.6",
"react-native-safe-area-context": "4.6.3",
"react-native-screens": "~3.22.0",
"react-native-svg-transformer": "^1.3.0"
"react-native-svg-transformer": "^1.3.0",
"react-native-screens": "~3.22.0"
},
"devDependencies": {
"@babel/core": "^7.20.0",
Expand Down
Empty file added client/screens/Landing.tsx
Empty file.
70 changes: 70 additions & 0 deletions client/screens/Login.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import React, { useState } from 'react';
import { View, TextInput, Button, Alert, StyleSheet } from 'react-native';
import { logIn } from '../services/auth/login';
import { signUp } from '../services/auth/signup';
import {
useNavigation,
StackActions,
useRoute
} from '@react-navigation/native';

const LoginPage: React.FC = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');

const navigation = useNavigation();
const route = useRoute();

const handleLogin = async () => {
if (!email || !password) {
Alert.alert('Error', 'Email and password are required');
return;
}
const result = await logIn(email, password);
if (typeof result === 'string') {
Alert.alert('Login Failed', result.substring(5).replaceAll('-', ' '));
} else {
Alert.alert('Login Success', 'Welcome back!');
// console.log('result: ', result);
navigation.navigate('BottomNav');
}
};

const handleSignUp = async () => {
if (!email || !password) {
Alert.alert('Error', 'Email and password are required');
return;
}
const result = await signUp(email, password);
if (typeof result === 'string') {
Alert.alert('Signup Failed', result.substring(5).replaceAll('-', ' '));
} else {
Alert.alert('Signup Success', 'Welcome to the app!');
// console.log('result: ', result);
navigation.navigate('BottomNav');
}
};

return (
<View className="flex-1 justify-center items-center px-5">
<TextInput
className="w-full my-2.5 py-2 px-3 border border-gray-300 rounded"
value={email}
onChangeText={setEmail}
placeholder="Email"
keyboardType="email-address"
/>
<TextInput
className="w-full my-2.5 py-2 px-3 border border-gray-300 rounded"
value={password}
onChangeText={setPassword}
placeholder="Password"
secureTextEntry
/>
<Button title="Login" onPress={handleLogin} />
<Button title="Sign Up" onPress={handleSignUp} />
</View>
);
};

export default LoginPage;
13 changes: 13 additions & 0 deletions client/services/auth/authState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { auth } from '../../firebase.config';
import {
onAuthStateChanged as firebaseOnAuthStateChanged,
User
} from 'firebase/auth';

export const onAuthStateChanged = (
callback: (user: User | null) => void
): void => {
firebaseOnAuthStateChanged(auth, (user: User | null) => {
callback(user);
});
};
37 changes: 37 additions & 0 deletions client/services/auth/login.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { auth } from '../../firebase.config';
import {
createUserWithEmailAndPassword,
signInWithEmailAndPassword,
User
} from 'firebase/auth';

export const logIn = async (
email: string,
password: string
): Promise<User | string> => {
try {
const userCredential = await signInWithEmailAndPassword(
auth,
email,
password
);
return userCredential.user;
} catch (error: any) {
console.error('Error logging in: ', error.code);
if (error.code === 'auth/user-not-found') {
try {
const newUserCredential = await createUserWithEmailAndPassword(
auth,
email,
password
);
return newUserCredential.user;
} catch (creationError: any) {
console.error('Error creating user: ', creationError.code);
return creationError.code;
}
} else {
return error.code;
}
}
};
20 changes: 20 additions & 0 deletions client/services/auth/signup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { auth } from '../../firebase.config';
import { User } from 'firebase/auth';
import { createUserWithEmailAndPassword } from 'firebase/auth';

export const signUp = async (
email: string,
password: string
): Promise<User | String> => {
try {
const userCredential = await createUserWithEmailAndPassword(
auth,
email,
password
);
return userCredential.user;
} catch (error: any) {
console.error('Error signing up: ', error.code);
return error.code;
}
};
30 changes: 30 additions & 0 deletions client/services/auth/tests/login.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// import { mockAuth } from 'firebase-mock';
// import { logIn } from 'client/services/auth/login.ts'; // Adjust path to match your project structure

// describe('logIn function', () => {
// const auth = mockAuth();

// it('should log in with valid credentials', async () => {
// auth.signInWithEmailAndPassword.mockResolvedValueOnce({
// user: {
// uid: 'mock-user-id',
// email: '[email protected]',
// // ...other user properties
// },
// });

// const user = await logIn('[email protected]', 'password');

// expect(user).toBeDefined();
// expect(user.uid).toBe('mock-user-id');
// expect(user.email).toBe('[email protected]');
// });

// it('should handle invalid credentials', async () => {
// auth.signInWithEmailAndPassword.mockRejectedValueOnce(new Error('Invalid email or password'));

// const user = await logIn('[email protected]', 'wrongpassword');

// expect(user).toBeNull();
// });
// });

0 comments on commit 139fbd8

Please sign in to comment.