diff --git a/.github/workflows/Node-js-CI.yml b/.github/workflows/Node-js-CI.yml
index 80ddfa2..9223800 100644
--- a/.github/workflows/Node-js-CI.yml
+++ b/.github/workflows/Node-js-CI.yml
@@ -35,4 +35,12 @@ jobs:
node-version: ${{ env.NODE_VERSION }}
- name: Running Test
- run: npm run test
\ No newline at end of file
+ run: npm run test
+ env:
+ FIREBASE_API_KEY: ${{ secrets.FIREBASE_API_KEY }}
+ FIREBASE_AUTH_DOMAIN: ${{ secrets.FIREBASE_AUTH_DOMAIN }}
+ FIREBASE_PROJECT_ID: ${{ secrets.FIREBASE_PROJECT_ID }}
+ FIREBASE_STORAGE_BUCKET: ${{ secrets.FIREBASE_STORAGE_BUCKET }}
+ FIREBASE_MESSAGING_SENDER_ID: ${{ secrets.FIREBASE_MESSAGING_SENDER_ID }}
+ FIREBASE_APP_ID: ${{ secrets.FIREBASE_APP_ID }}
+ FIREBASE_MEASUREMENT_ID: ${{ secrets.FIREBASE_MEASUREMENT_ID }}
\ No newline at end of file
diff --git a/app/(Auth)/LogInModal.tsx b/app/(Auth)/LogInModal.tsx
index 9fb908a..296bb1f 100644
--- a/app/(Auth)/LogInModal.tsx
+++ b/app/(Auth)/LogInModal.tsx
@@ -1,174 +1,219 @@
-import { Text, View, StyleSheet, Pressable, Modal } from "react-native"
+import { Text, View, StyleSheet, Pressable, Modal } from "react-native";
import React, { useState } from "react";
-import { TextInput as PaperTextInput, IconButton } from 'react-native-paper';
+import {
+ TextInput as PaperTextInput,
+ IconButton,
+ Props,
+} from "react-native-paper";
-type LogInProps = {
- isVisible: boolean,
- onClose: () => void
- toggleSignUp: () => void
-}
+import { AuthError, User } from "firebase/auth";
-const LogInModal = (props: LogInProps) => {
- const [emailText, setEmailText] = useState('');
- const [passwordText, setPasswordText] = useState('');
+import { emailVerification, logIn, logOut } from "./firebaseAuth";
- const [passwordVisible, setPasswordVisible] = useState(true);
+type LogInProps = {
+ isVisible: boolean;
+ onClose: () => void;
+ toggleSignUp: () => void;
+};
- const [emailBorderColor, setEmailBorderColor] = useState('gray');
- const [PasswordBorderColor, setPasswordBorderColor] = useState('gray');
+const LogInModal = (props: LogInProps) => {
+ const [emailText, setEmailText] = useState("");
+ const [passwordText, setPasswordText] = useState("");
- return (
-
-
- e.stopPropagation()} >
-
-
-
- Email
- setEmailBorderColor('black')} // border color on focus
- onBlur={() => setEmailBorderColor('gray')} // border color on focus
+ const [passwordVisible, setPasswordVisible] = useState(true);
- placeholder='Value'
- placeholderTextColor="#a9a9a9"
- value={emailText}
- onChangeText={setEmailText}
+ const [emailBorderColor, setEmailBorderColor] = useState("gray");
+ const [PasswordBorderColor, setPasswordBorderColor] = useState("gray");
- theme={{ colors: { primary: "transparent" } }} // this removes the underline
- underlineColor="transparent" // this removes the any extra underline
- /* obtain data here */
- />
- Password
- setPasswordBorderColor('black')} // border color on focus
- onBlur={() => setPasswordBorderColor('gray')} // border color on focus
+ const handleLogIn = async () => {
+ try {
+ const user = await logIn(emailText, passwordText);
+ await checkIfEmailVerified(user, props.onClose);
+ } catch (error: unknown) {
+ if (
+ (error as AuthError).code === "auth/user-not-found" ||
+ (error as AuthError).code === "auth/wrong-password"
+ ) {
+ alert("Email already in use");
+ } else if ((error as AuthError).code === "auth/invalid-email") {
+ alert("No Email Found, please Sign Up!");
+ } else if ((error as AuthError).code === "auth/too-many-request") {
+ alert("Too many unsuccessful login attempts. Please try again later.");
+ //invalid-credentials (just say wrong email or password)
+ } else {
+ console.log((error as AuthError).code);
+ alert("Sign In error: " + (error as Error).message);
+ }
+ }
+ };
- placeholder='Value'
- placeholderTextColor="#a9a9a9"
- secureTextEntry={passwordVisible}
- value={passwordText}
- onChangeText={setPasswordText}
- right={
- setPasswordVisible(!passwordVisible)}
- style={styles.icon} // this adjusts eye icon position
- />
- }
- theme={{ colors: { primary: "transparent" } }} // this removes the underline
- underlineColor="transparent" // this removes any extra underline
- /* obtain data here */
- />
- {
- /* handle action here */
- }}
- >
- Sign In
-
-
- {
- /* handle action here */
- }}
- >
- Forgot password?
-
-
- {
- props.toggleSignUp()
- console.log("Signup Pressed")
- props.onClose()
- }}
- >
- Need an account? Sign-up here.
-
-
-
-
- );
+ return (
+
+
+ e.stopPropagation()}>
+
+
+
+ Email
+ setEmailBorderColor("black")} // border color on focus
+ onBlur={() => setEmailBorderColor("gray")} // border color on focus
+ placeholder="Value"
+ placeholderTextColor="#a9a9a9"
+ value={emailText}
+ onChangeText={setEmailText}
+ theme={{ colors: { primary: "transparent" } }} // this removes the underline
+ underlineColor="transparent" // this removes the any extra underline
+ /* obtain data here */
+ />
+ Password
+ setPasswordBorderColor("black")} // border color on focus
+ onBlur={() => setPasswordBorderColor("gray")} // border color on focus
+ placeholder="Value"
+ placeholderTextColor="#a9a9a9"
+ secureTextEntry={passwordVisible}
+ value={passwordText}
+ onChangeText={setPasswordText}
+ right={
+ setPasswordVisible(!passwordVisible)}
+ style={styles.icon} // this adjusts eye icon position
+ />
+ }
+ theme={{ colors: { primary: "transparent" } }} // this removes the underline
+ underlineColor="transparent" // this removes any extra underline
+ /* obtain data here */
+ />
+ {
+ handleLogIn();
+ }}
+ >
+ Sign In
+
+
+ {
+ /* handle action here */
+ }}
+ >
+ Forgot password?
+
+
+ {
+ props.toggleSignUp();
+ console.log("Signup Pressed");
+ props.onClose();
+ }}
+ >
+ Need an account? Sign-up here.
+
+
+
+
+ );
};
const styles = StyleSheet.create({
- container: {
- flex: 1,
- backgroundColor: 'rgba(0,0,0,0.5)', // making the background page transparent
- justifyContent: 'center',
- alignItems: 'center',
- },
- box: {
- backgroundColor: 'white',
- borderRadius: 10,
- padding: 15,
- width: 400,
- alignItems: "center",
- },
- underline: {
- textDecorationLine: 'underline',
- color: 'black', // set this color of the underline 'black'
- },
- button: {
- backgroundColor: '#71E0BC',
- borderRadius: 5,
- padding: 10,
- alignItems: 'center',
- justifyContent: 'center',
- marginVertical: 10,
- width: 350,
- },
- buttonText: {
- color: 'black', // Set the text color to black
- },
- textSpace: {
- marginTop: 4, // Space before text
- marginBottom: 8, // Space after text
- },
- label: {
- alignSelf: 'flex-start', // align labels to the start
- marginLeft: 10, // Add some margin to the left to match the input margin
- marginBottom: 1, // Space between label and input
- },
- icon: {
- marginTop: 20,
- },
- paperInput: {
- borderWidth: 2,
- borderColor: '#777',
- backgroundColor: 'white',
- paddingHorizontal: 9,
- paddingVertical: 8,
- margin: 10,
- borderRadius: 6,
- width: 350,
- height: 23,
- // this adjust font size and line height to the standard
- fontSize: 14,
- },
- header: {
- width: '100%',
- height: 15,
- alignItems: "flex-end",
- justifyContent: 'center',
- marginLeft: 30,
- },
+ container: {
+ flex: 1,
+ backgroundColor: "rgba(0,0,0,0.5)", // making the background page transparent
+ justifyContent: "center",
+ alignItems: "center",
+ },
+ box: {
+ backgroundColor: "white",
+ borderRadius: 10,
+ padding: 15,
+ width: 400,
+ alignItems: "center",
+ },
+ underline: {
+ textDecorationLine: "underline",
+ color: "black", // set this color of the underline 'black'
+ },
+ button: {
+ backgroundColor: "#71E0BC",
+ borderRadius: 5,
+ padding: 10,
+ alignItems: "center",
+ justifyContent: "center",
+ marginVertical: 10,
+ width: 350,
+ },
+ buttonText: {
+ color: "black", // Set the text color to black
+ },
+ textSpace: {
+ marginTop: 4, // Space before text
+ marginBottom: 8, // Space after text
+ },
+ label: {
+ alignSelf: "flex-start", // align labels to the start
+ marginLeft: 10, // Add some margin to the left to match the input margin
+ marginBottom: 1, // Space between label and input
+ },
+ icon: {
+ marginTop: 20,
+ },
+ paperInput: {
+ borderWidth: 2,
+ borderColor: "#777",
+ backgroundColor: "white",
+ paddingHorizontal: 9,
+ paddingVertical: 8,
+ margin: 10,
+ borderRadius: 6,
+ width: 350,
+ height: 23,
+ // this adjust font size and line height to the standard
+ fontSize: 14,
+ },
+ header: {
+ width: "100%",
+ height: 15,
+ alignItems: "flex-end",
+ justifyContent: "center",
+ marginLeft: 30,
+ },
});
export default LogInModal;
+const checkIfEmailVerified = async (user: User, onClose: () => void) => {
+ if (user) {
+ if (!user.emailVerified) {
+ // means that user is still not verified yet, need them to be verified
+ await emailVerification();
+ await logOut();
+
+ //give a warning like an alert to ask to verify
+ alert("Please verify your email.");
+ }
+ //If verified, navigate to other place
+ console.log("Woo Verified, I'll navigate you later");
+
+ onClose();
+ } else {
+ throw new Error("Failed to check User");
+ }
+};
+
/* self-note:
when clocking the navigation 'link',
it erases the most components from the main background. figure out how to prevent that.
setvisible prolly would work for the 'link' (?)
-*/
\ No newline at end of file
+*/
diff --git a/app/(Auth)/SignUpModal.tsx b/app/(Auth)/SignUpModal.tsx
index 2a0b852..2144690 100644
--- a/app/(Auth)/SignUpModal.tsx
+++ b/app/(Auth)/SignUpModal.tsx
@@ -2,6 +2,9 @@ import { Text, View, TextInput, StyleSheet, Pressable, Modal } from "react-nativ
import React, { useState } from "react";
import { TextInput as PaperTextInput, IconButton } from 'react-native-paper';
+import { AuthError } from 'firebase/auth';
+import { signUp } from "./firebaseAuth";
+
type SignUpProps = {
isVisible: boolean,
onClose: () => void
@@ -20,6 +23,26 @@ const SignUpModal = (props: SignUpProps) => {
const [passwordbBorderColor, setPasswordBorderColor] = useState('gray');
const [ReEnterPasswordbBorderColor, setReEnterPasswordBorderColor] = useState('gray');
+ const handleSignUp = async () => {
+ try {
+ const user = await signUp(emailText, password, reEnterPassword)
+ if(user) {
+ //use saveUserData from firebase if needed
+ const id = user.uid;
+ }
+ //should navigate to a loading screen, or ask to verify first before doing anything
+ } catch (error: unknown) {
+ if ((error as AuthError).code === 'auth/email-already-in-use') {
+ alert('Email already in use');
+ } else if ((error as AuthError).code === 'auth/weak-password') {
+ alert('Weak Password. Please choose a stronger password')
+ //invalid email also
+ } else {
+ alert("Signup error: " + (error as Error).message)
+ }
+ };
+ }
+
return (
{
{
- /* handle action here */
+ handleSignUp()
}}
>
Sign In
diff --git a/app/(Auth)/firebaseAuth.tsx b/app/(Auth)/firebaseAuth.tsx
index 13c0738..ac87ea1 100644
--- a/app/(Auth)/firebaseAuth.tsx
+++ b/app/(Auth)/firebaseAuth.tsx
@@ -2,12 +2,11 @@ import {
createUserWithEmailAndPassword,
signInWithEmailAndPassword,
sendEmailVerification,
- signOut,
+ signOut
} from "firebase/auth";
import auth from "../../scripts/firebaseConfig";
-
export const signUp = async (
email: string,
password: string,
diff --git a/jest.setup.js b/jest.setup.js
new file mode 100644
index 0000000..355c7df
--- /dev/null
+++ b/jest.setup.js
@@ -0,0 +1 @@
+require('dotenv').config({ path: './.env' });
diff --git a/package.json b/package.json
index 6d24fa4..996286f 100644
--- a/package.json
+++ b/package.json
@@ -27,7 +27,10 @@
"scripts"
],
"transformIgnorePatterns": [
- "node_modules/(?!((jest-)?react-native|@react-native(-community)?)|expo(nent)?|@expo(nent)?/.|@expo-google-fonts/.|react-navigation|@react-navigation/.*|@sentry/react-native|native-base|react-native-svg|react-redux)"
+ "node_modules/(?!((jest-)?react-native|@react-native(-community)?)|expo(nent)?|@expo(nent)?/.|@expo-google-fonts/.|react-navigation|@react-navigation/.*|@sentry/react-native|native-base|react-native-svg|react-redux|@firebase|firebase)"
+ ],
+ "setupFiles": [
+ "/jest.setup.js"
]
},
"dependencies": {
diff --git a/scripts/firebaseConfig.js b/scripts/firebaseConfig.js
index 98da890..bc11f90 100644
--- a/scripts/firebaseConfig.js
+++ b/scripts/firebaseConfig.js
@@ -3,13 +3,13 @@ import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";
const firebaseConfig = {
- apiKey: process.env.EXPO_PUBLIC_FIREBASE_API_KEY,
- authDomain: process.env.EXPO_PUBLIC_FIREBASE_AUTH_DOMAIN,
- projectId: process.env.EXPO_PUBLIC_FIREBASE_PROJECT_ID,
- storageBucket: process.env.EXPO_PUBLIC_FIREBASE_STORAGE_BUCKET,
- messagingSenderId: process.env.EXPO_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
- appId: process.env.EXPO_PUBLIC_FIREBASE_APP_ID,
- measurementId: process.env.EXPO_PUBLIC_FIREBASE_MEASUREMENT_ID,
+ apiKey: process.env.FIREBASE_API_KEY,
+ authDomain: process.env.FIREBASE_AUTH_DOMAIN,
+ projectId: process.env.FIREBASE_PROJECT_ID,
+ storageBucket: process.env.FIREBASE_STORAGE_BUCKET,
+ messagingSenderId: process.env.FIREBASE_MESSAGING_SENDER_ID,
+ appId: process.env.FIREBASE_APP_ID,
+ measurementId: process.env.FIREBASE_MEASUREMENT_ID,
};
console.log(firebaseConfig)
diff --git a/yarn.lock b/yarn.lock
index 1af0cb6..382cac8 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3010,6 +3010,11 @@
resolved "https://registry.npmjs.org/@react-native-community/masked-view/-/masked-view-0.1.11.tgz"
integrity sha512-rQfMIGSR/1r/SyN87+VD8xHHzDYeHaJq6elOSCAD+0iLagXkSI2pfA0LmSXP21uw5i3em7GkkRjfJ8wpqWXZNw==
+"@react-native-picker/picker@^2.8.1":
+ version "2.8.1"
+ resolved "https://registry.npmjs.org/@react-native-picker/picker/-/picker-2.8.1.tgz"
+ integrity sha512-iFhsKQzRh/z3GlmvJWSjJJ4333FdLE/PhXxlGlYllE7sFf+UTzziVY+ajatuJ+R5zDw2AxfJV4v/3tAzUJb0/A==
+
"@react-native/assets-registry@0.74.85":
version "0.74.85"
resolved "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.74.85.tgz"
@@ -11563,6 +11568,7 @@ natural-compare@^1.4.0:
dependencies:
"@expo/vector-icons" "^14.0.2"
"@react-native-community/masked-view" "^0.1.11"
+ "@react-native-picker/picker" "^2.8.1"
"@react-navigation/native" "^6.1.18"
"@react-navigation/stack" "^6.4.1"
"@reduxjs/toolkit" "^2.2.6"