Compare commits
2
Commits
500b003189
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b771a989f1 | ||
|
|
8d9ed344d6 |
No files matched your search
@@ -22,13 +22,6 @@ node_modules/
|
|||||||
dist/
|
dist/
|
||||||
coverage/
|
coverage/
|
||||||
|
|
||||||
# Python
|
|
||||||
__pycache__/
|
|
||||||
*.py[cod]
|
|
||||||
.venv/
|
|
||||||
venv/
|
|
||||||
.pytest_cache/
|
|
||||||
|
|
||||||
# Java and Android build output
|
# Java and Android build output
|
||||||
.gradle/
|
.gradle/
|
||||||
build/
|
build/
|
||||||
|
|||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,34 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Exercise 1</title>
|
||||||
|
<script src="https://d3js.org/d3.v7.min.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1>Exercise 1</h1>
|
||||||
|
<script>
|
||||||
|
d3.select("body")
|
||||||
|
.append("svg")
|
||||||
|
.attr("width", 110)
|
||||||
|
.attr("height", 200)
|
||||||
|
.append("rect")
|
||||||
|
.attr("x", 10)
|
||||||
|
.attr("width", 100)
|
||||||
|
.attr("height", 200)
|
||||||
|
.attr("fill", "blue");
|
||||||
|
d3.select("body")
|
||||||
|
.append("svg")
|
||||||
|
.attr("width", 220)
|
||||||
|
.attr("height", 200)
|
||||||
|
.style("margin-left", "50px")
|
||||||
|
.append("rect")
|
||||||
|
.attr("x", 120)
|
||||||
|
.attr("width", 100)
|
||||||
|
.attr("height", 200)
|
||||||
|
.attr("fill", "green");
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
> Why do I have a folder named ".expo" in my project?
|
||||||
|
|
||||||
|
The ".expo" folder is created when an Expo project is started using "expo start" command.
|
||||||
|
|
||||||
|
> What do the files contain?
|
||||||
|
|
||||||
|
- "devices.json": contains information about devices that have recently opened this project. This is used to populate the "Development sessions" list in your development builds.
|
||||||
|
- "settings.json": contains the server configuration that is used to serve the application manifest.
|
||||||
|
|
||||||
|
> Should I commit the ".expo" folder?
|
||||||
|
|
||||||
|
No, you should not share the ".expo" folder. It does not contain any information that is relevant for other developers working on the project, it is specific to your machine.
|
||||||
|
Upon project creation, the ".expo" folder is already added to your ".gitignore" file.
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"devices": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,309 @@
|
|||||||
|
import { StatusBar } from "expo-status-bar";
|
||||||
|
import React, { useState, useEffect } from "react";
|
||||||
|
import { View, TextInput, Text, Button, Alert, StyleSheet } from "react-native";
|
||||||
|
import { db, firestore, auth } from "./FirebaseConfig";
|
||||||
|
import {
|
||||||
|
createUserWithEmailAndPassword,
|
||||||
|
signOut,
|
||||||
|
signInWithEmailAndPassword,
|
||||||
|
onAuthStateChanged,
|
||||||
|
} from "firebase/auth";
|
||||||
|
import { ref, set, onValue } from "firebase/database";
|
||||||
|
import { doc, setDoc, onSnapshot } from "firebase/firestore";
|
||||||
|
|
||||||
|
export default function App() {
|
||||||
|
const [registrationEmail, setRegistrationEmail] = useState("");
|
||||||
|
const [registrationPassword, setRegistrationPassword] = useState("");
|
||||||
|
const [loginEmail, setLoginEmail] = useState("");
|
||||||
|
const [loginPassword, setLoginPassword] = useState("");
|
||||||
|
const [loggedIn, setLoggedIn] = useState(false);
|
||||||
|
const [databaseData, setDatabaseData] = useState("");
|
||||||
|
const [user, setUser] = useState(null);
|
||||||
|
|
||||||
|
// Monitor authentication state
|
||||||
|
useEffect(() => {
|
||||||
|
const unsubscribe = onAuthStateChanged(auth, (currentUser) => {
|
||||||
|
setUser(currentUser);
|
||||||
|
setLoggedIn(!!currentUser);
|
||||||
|
});
|
||||||
|
return () => unsubscribe();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const registerWithFirebase = () => {
|
||||||
|
if (registrationEmail.length < 4) {
|
||||||
|
Alert.alert("Please enter an email address.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (registrationPassword.length < 4) {
|
||||||
|
Alert.alert("Please enter a password.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
createUserWithEmailAndPassword(
|
||||||
|
auth,
|
||||||
|
registrationEmail,
|
||||||
|
registrationPassword
|
||||||
|
)
|
||||||
|
.then((userCredential) => {
|
||||||
|
Alert.alert("User registered successfully!");
|
||||||
|
setRegistrationEmail("");
|
||||||
|
setRegistrationPassword("");
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log("Registration error:", error);
|
||||||
|
if (error.code === "auth/weak-password") {
|
||||||
|
Alert.alert("The password is too weak.");
|
||||||
|
} else if (error.code === "auth/email-already-in-use") {
|
||||||
|
Alert.alert("This email is already registered.");
|
||||||
|
} else {
|
||||||
|
Alert.alert(error.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const loginWithFirebase = () => {
|
||||||
|
if (loginEmail.length < 4) {
|
||||||
|
Alert.alert("Please enter an email address.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loginPassword.length < 4) {
|
||||||
|
Alert.alert("Please enter a password.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
signInWithEmailAndPassword(auth, loginEmail, loginPassword)
|
||||||
|
.then((userCredential) => {
|
||||||
|
Alert.alert("User logged in successfully!");
|
||||||
|
setLoginEmail("");
|
||||||
|
setLoginPassword("");
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log("Login error:", error);
|
||||||
|
if (error.code === "auth/wrong-password") {
|
||||||
|
Alert.alert("Wrong password.");
|
||||||
|
} else if (error.code === "auth/user-not-found") {
|
||||||
|
Alert.alert("User not found.");
|
||||||
|
} else {
|
||||||
|
Alert.alert(error.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const signoutWithFirebase = () => {
|
||||||
|
signOut(auth)
|
||||||
|
.then(() => {
|
||||||
|
Alert.alert("User was logged out!");
|
||||||
|
setDatabaseData("");
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
Alert.alert("Error signing out:", error.message);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const saveDataWithFirebase = () => {
|
||||||
|
if (!user) {
|
||||||
|
Alert.alert("Please log in first.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const userID = user.uid;
|
||||||
|
|
||||||
|
// Save to Realtime DB
|
||||||
|
set(ref(db, "users/" + userID), {
|
||||||
|
text: databaseData,
|
||||||
|
timestamp: Date.now(),
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
console.log("Data saved to Realtime DB");
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log("Realtime DB error:", error);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Save to Firestore
|
||||||
|
setDoc(
|
||||||
|
doc(firestore, "users", userID),
|
||||||
|
{
|
||||||
|
text: databaseData,
|
||||||
|
timestamp: Date.now(),
|
||||||
|
},
|
||||||
|
{ merge: true }
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
Alert.alert("Data saved successfully!");
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
Alert.alert("Error saving data");
|
||||||
|
console.log("Firestore error:", error);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const retrieveDataWithFirebase = () => {
|
||||||
|
if (!user) {
|
||||||
|
Alert.alert("Please log in first.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const userID = user.uid;
|
||||||
|
const dbRef = ref(db, "users/" + userID);
|
||||||
|
|
||||||
|
// Using Realtime DB
|
||||||
|
onValue(dbRef, (snapshot) => {
|
||||||
|
if (snapshot.exists()) {
|
||||||
|
const data = snapshot.val();
|
||||||
|
setDatabaseData(data.text || "");
|
||||||
|
Alert.alert("Data retrieved from Realtime DB");
|
||||||
|
} else {
|
||||||
|
Alert.alert("No data found");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Uncomment for Firestore
|
||||||
|
/*
|
||||||
|
const unsubscribe = onSnapshot(doc(firestore, "users", userID), (doc) => {
|
||||||
|
if (doc.exists()) {
|
||||||
|
const data = doc.data();
|
||||||
|
setDatabaseData(data.text || "");
|
||||||
|
Alert.alert("Data retrieved from Firestore");
|
||||||
|
} else {
|
||||||
|
Alert.alert("No data found in Firestore");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.form}>
|
||||||
|
<StatusBar style="auto" />
|
||||||
|
|
||||||
|
{!loggedIn ? (
|
||||||
|
<View>
|
||||||
|
<View style={styles.section}>
|
||||||
|
<Text style={styles.label}>Lab 5 - l_mclean215318</Text>
|
||||||
|
<Text style={styles.label}>Register with Firebase</Text>
|
||||||
|
<TextInput
|
||||||
|
style={styles.textInput}
|
||||||
|
onChangeText={setRegistrationEmail}
|
||||||
|
value={registrationEmail}
|
||||||
|
autoCapitalize="none"
|
||||||
|
autoCorrect={false}
|
||||||
|
autoCompleteType="email"
|
||||||
|
keyboardType="email-address"
|
||||||
|
placeholder="Email"
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
style={styles.textInput}
|
||||||
|
onChangeText={setRegistrationPassword}
|
||||||
|
value={registrationPassword}
|
||||||
|
autoCapitalize="none"
|
||||||
|
autoCorrect={false}
|
||||||
|
autoCompleteType="password"
|
||||||
|
placeholder="Password"
|
||||||
|
secureTextEntry={true}
|
||||||
|
/>
|
||||||
|
<Button title="Register" onPress={registerWithFirebase} />
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.section}>
|
||||||
|
<Text style={styles.label}>Sign In with Firebase</Text>
|
||||||
|
<TextInput
|
||||||
|
style={styles.textInput}
|
||||||
|
onChangeText={setLoginEmail}
|
||||||
|
value={loginEmail}
|
||||||
|
autoCapitalize="none"
|
||||||
|
autoCorrect={false}
|
||||||
|
autoCompleteType="email"
|
||||||
|
keyboardType="email-address"
|
||||||
|
placeholder="Email"
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
style={styles.textInput}
|
||||||
|
onChangeText={setLoginPassword}
|
||||||
|
value={loginPassword}
|
||||||
|
autoCapitalize="none"
|
||||||
|
autoCorrect={false}
|
||||||
|
autoCompleteType="password"
|
||||||
|
placeholder="Password"
|
||||||
|
secureTextEntry={true}
|
||||||
|
/>
|
||||||
|
<Button title="Login" onPress={loginWithFirebase} />
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
) : (
|
||||||
|
<View>
|
||||||
|
<Text style={styles.welcome}>Welcome, {user?.email}</Text>
|
||||||
|
<TextInput
|
||||||
|
style={styles.textArea}
|
||||||
|
multiline={true}
|
||||||
|
numberOfLines={4}
|
||||||
|
onChangeText={setDatabaseData}
|
||||||
|
value={databaseData}
|
||||||
|
placeholder="Enter your data here..."
|
||||||
|
/>
|
||||||
|
<View style={styles.buttonContainer}>
|
||||||
|
<Button title="Save Data" onPress={saveDataWithFirebase} />
|
||||||
|
<Button title="Load Data" onPress={retrieveDataWithFirebase} />
|
||||||
|
</View>
|
||||||
|
<View style={styles.signOutButton}>
|
||||||
|
<Button
|
||||||
|
title="Sign Out"
|
||||||
|
onPress={signoutWithFirebase}
|
||||||
|
color="#ff4444"
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
form: {
|
||||||
|
flex: 1,
|
||||||
|
margin: 30,
|
||||||
|
marginTop: 60,
|
||||||
|
},
|
||||||
|
section: {
|
||||||
|
marginBottom: 30,
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
fontSize: 18,
|
||||||
|
marginBottom: 15,
|
||||||
|
textAlign: "center",
|
||||||
|
fontWeight: "bold",
|
||||||
|
},
|
||||||
|
welcome: {
|
||||||
|
fontSize: 18,
|
||||||
|
marginBottom: 20,
|
||||||
|
textAlign: "center",
|
||||||
|
fontWeight: "bold",
|
||||||
|
},
|
||||||
|
textInput: {
|
||||||
|
borderColor: "#ccc",
|
||||||
|
borderWidth: 1,
|
||||||
|
marginBottom: 15,
|
||||||
|
paddingVertical: 8,
|
||||||
|
paddingHorizontal: 10,
|
||||||
|
borderRadius: 5,
|
||||||
|
},
|
||||||
|
textArea: {
|
||||||
|
borderColor: "#ccc",
|
||||||
|
borderWidth: 1,
|
||||||
|
marginBottom: 15,
|
||||||
|
paddingVertical: 8,
|
||||||
|
paddingHorizontal: 10,
|
||||||
|
borderRadius: 5,
|
||||||
|
height: 100,
|
||||||
|
textAlignVertical: "top",
|
||||||
|
},
|
||||||
|
buttonContainer: {
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
marginBottom: 20,
|
||||||
|
},
|
||||||
|
signOutButton: {
|
||||||
|
marginTop: 20,
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { initializeApp } from "firebase/app";
|
||||||
|
import { getDatabase } from "firebase/database";
|
||||||
|
import { getAuth } from "firebase/auth";
|
||||||
|
import { getFirestore } from "firebase/firestore";
|
||||||
|
|
||||||
|
// Your Firebase config
|
||||||
|
const firebaseConfig = {
|
||||||
|
apiKey: "AIzaSyBfvjd5heEO3nS59rQSqY3Vsr36Pv2V3RU",
|
||||||
|
authDomain: "week6-fb-db.firebaseapp.com",
|
||||||
|
databaseURL: "https://week6-fb-db-default-rtdb.firebaseio.com",
|
||||||
|
projectId: "week6-fb-db",
|
||||||
|
storageBucket: "week6-fb-db.firebasestorage.app",
|
||||||
|
messagingSenderId: "854313991657",
|
||||||
|
appId: "1:854313991657:web:42859a9b1c0bd06f391f78",
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initialize Firebase
|
||||||
|
const app = initializeApp(firebaseConfig);
|
||||||
|
export const db = getDatabase(app);
|
||||||
|
export const auth = getAuth(app);
|
||||||
|
export const firestore = getFirestore(app);
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"expo": {
|
||||||
|
"name": "firebase-DB",
|
||||||
|
"slug": "firebase-DB",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"orientation": "portrait",
|
||||||
|
"icon": "./assets/icon.png",
|
||||||
|
"userInterfaceStyle": "light",
|
||||||
|
"newArchEnabled": true,
|
||||||
|
"splash": {
|
||||||
|
"image": "./assets/splash-icon.png",
|
||||||
|
"resizeMode": "contain",
|
||||||
|
"backgroundColor": "#ffffff"
|
||||||
|
},
|
||||||
|
"ios": {
|
||||||
|
"supportsTablet": true
|
||||||
|
},
|
||||||
|
"android": {
|
||||||
|
"adaptiveIcon": {
|
||||||
|
"foregroundImage": "./assets/adaptive-icon.png",
|
||||||
|
"backgroundColor": "#ffffff"
|
||||||
|
},
|
||||||
|
"edgeToEdgeEnabled": true
|
||||||
|
},
|
||||||
|
"web": {
|
||||||
|
"favicon": "./assets/favicon.png"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
@@ -0,0 +1,8 @@
|
|||||||
|
import { registerRootComponent } from 'expo';
|
||||||
|
|
||||||
|
import App from './App';
|
||||||
|
|
||||||
|
// registerRootComponent calls AppRegistry.registerComponent('main', () => App);
|
||||||
|
// It also ensures that whether you load the app in Expo Go or in a native build,
|
||||||
|
// the environment is set up appropriately
|
||||||
|
registerRootComponent(App);
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"name": "firebase-db",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "expo start",
|
||||||
|
"android": "expo start --android",
|
||||||
|
"ios": "expo start --ios",
|
||||||
|
"web": "expo start --web"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@react-native-async-storage/async-storage": "^1.24.0",
|
||||||
|
"expo": "~54.0.12",
|
||||||
|
"expo-status-bar": "~3.0.8",
|
||||||
|
"firebase": "^12.3.0",
|
||||||
|
"react": "19.1.0",
|
||||||
|
"react-native": "0.81.4"
|
||||||
|
},
|
||||||
|
"private": true,
|
||||||
|
"devDependencies": {
|
||||||
|
"@expo/cli": "^54.0.10"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user