diff --git a/package-lock.json b/package-lock.json
index cefaccd..c3c5b8e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16,6 +16,7 @@
"firestore": "^1.1.6",
"react": "^18.2.0",
"react-dom": "^18.2.0",
+ "react-firebase-hooks": "^5.1.1",
"react-router-dom": "^6.22.3",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
@@ -15800,6 +15801,15 @@
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz",
"integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg=="
},
+ "node_modules/react-firebase-hooks": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/react-firebase-hooks/-/react-firebase-hooks-5.1.1.tgz",
+ "integrity": "sha512-y2UpWs82xs+39q5Rc/wq316ca52QsC0n8m801V+yM4IC4hbfOL4yQPVSh7w+ydstdvjN9F+lvs1WrO2VYxpmdA==",
+ "peerDependencies": {
+ "firebase": ">= 9.0.0",
+ "react": ">= 16.8.0"
+ }
+ },
"node_modules/react-is": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
diff --git a/package.json b/package.json
index e309a20..962a519 100644
--- a/package.json
+++ b/package.json
@@ -11,6 +11,7 @@
"firestore": "^1.1.6",
"react": "^18.2.0",
"react-dom": "^18.2.0",
+ "react-firebase-hooks": "^5.1.1",
"react-router-dom": "^6.22.3",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
diff --git a/src/App.js b/src/App.js
index 5135dab..4d843cd 100644
--- a/src/App.js
+++ b/src/App.js
@@ -7,8 +7,10 @@ import Login from 'components/Login';
import Signup from 'components/Signup';
import Profile from 'components/Profile';
import HomePage from 'components/HomePage';
-import Header from 'components/Header';
+import Header from 'components/Header/Header';
import UpdateProfile from 'components/UpdateProfile/UpdateProfile';
+import Write from 'components/Write/Write';
+import EditArticle from 'components/EditArticle/EditArticle';
function App() {
return (
@@ -21,6 +23,8 @@ function App() {
} />
} />
} />
+ } />
+ } />
diff --git a/src/components/EditArticle/EditArticle.js b/src/components/EditArticle/EditArticle.js
new file mode 100644
index 0000000..2d83235
--- /dev/null
+++ b/src/components/EditArticle/EditArticle.js
@@ -0,0 +1,70 @@
+// src/components/EditArticle.js
+import React, { useState, useEffect } from 'react';
+import { useParams, useNavigate } from 'react-router-dom';
+import { db } from 'firebase-config';
+import { doc, getDoc, updateDoc, serverTimestamp } from 'firebase/firestore';
+
+function EditArticle() {
+ const [title, setTitle] = useState('');
+ const [body, setBody] = useState('');
+ const { articleId } = useParams(); // Capture the articleId from the URL
+ const navigate = useNavigate();
+
+ useEffect(() => {
+ const fetchArticle = async () => {
+ const articleRef = doc(db, 'articles', articleId);
+ const docSnap = await getDoc(articleRef);
+ if (docSnap.exists()) {
+ setTitle(docSnap.data().title);
+ setBody(docSnap.data().body);
+ } else {
+ console.log("No such document!");
+ navigate('/profile'); // Redirect if the article doesn't exist
+ }
+ };
+ fetchArticle();
+ }, [articleId, navigate]);
+
+ const handleSubmit = async (e) => {
+ e.preventDefault();
+ const articleRef = doc(db, 'articles', articleId);
+ await updateDoc(articleRef, {
+ title,
+ body,
+ updatedAt: serverTimestamp(),
+ });
+ navigate('/profile'); // Navigate to the profile page after successful update
+ };
+
+ return (
+
+ );
+}
+
+export default EditArticle;
diff --git a/src/components/Header.js b/src/components/Header.js
deleted file mode 100644
index 67cc4f5..0000000
--- a/src/components/Header.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import React from 'react';
-import { Link } from 'react-router-dom';
-import { useAuth } from 'hooks/useAuth';
-
-function Header() {
- const { currentUser } = useAuth(); // This hook is to check if a user is logged in
-
- return (
-
-
-
- );
-}
-
-export default Header;
diff --git a/src/components/Header/Header.css b/src/components/Header/Header.css
new file mode 100644
index 0000000..7d8ce29
--- /dev/null
+++ b/src/components/Header/Header.css
@@ -0,0 +1,25 @@
+.header {
+ background-color: #007bff; /* A nice shade of blue */
+ padding: 10px 20px; /* Add some padding around the header */
+}
+
+.nav-links {
+ list-style: none; /* Remove default list styling */
+ padding: 0;
+ margin: 0;
+ display: flex; /* Display links in a row */
+ gap: 10px; /* Add some space between links */
+}
+
+.nav-link {
+ text-decoration: none; /* Remove underline from links */
+ color: white; /* Make text color white for contrast */
+ background-color: #0056b3; /* A slightly darker blue for buttons */
+ padding: 10px 15px; /* Add padding around the text */
+ border-radius: 5px; /* Round the corners */
+ transition: background-color 0.3s; /* Smooth background color transition on hover */
+}
+
+.nav-link:hover {
+ background-color: #003785; /* Darken button on hover */
+}
diff --git a/src/components/Header/Header.js b/src/components/Header/Header.js
new file mode 100644
index 0000000..cd96436
--- /dev/null
+++ b/src/components/Header/Header.js
@@ -0,0 +1,25 @@
+import React from 'react';
+import { Link } from 'react-router-dom';
+import { useAuth } from 'hooks/useAuth';
+import './Header.css'; // Import the CSS file
+
+function Header() {
+ const { currentUser } = useAuth(); // This hook checks if a user is logged in
+
+ return (
+
+
+
+ );
+}
+
+export default Header;
diff --git a/src/components/Profile.js b/src/components/Profile.js
index c7cd74c..2cb63b6 100644
--- a/src/components/Profile.js
+++ b/src/components/Profile.js
@@ -1,58 +1,76 @@
-// src/components/Profile.js
import React, { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
-import { auth, db } from 'firebase-config';
-import { signOut } from 'firebase/auth';
-import { doc, getDoc } from 'firebase/firestore';
+import { auth, db } from 'firebase-config'; // Adjust the import path as necessary
+import { signOut, onAuthStateChanged } from 'firebase/auth';
+import { doc, getDoc, collection, query, where, getDocs, deleteDoc } from 'firebase/firestore';
+import UserArticlesList from 'components/UserArticlesList/UserArticlesList'; // Import the new component
+
+
function Profile() {
const navigate = useNavigate();
- const user = auth.currentUser;
const [profileData, setProfileData] = useState(null);
+ const [userArticles, setUserArticles] = useState([]);
useEffect(() => {
- const fetchUserProfile = async () => {
+ const unsubscribe = onAuthStateChanged(auth, (user) => {
if (user) {
- const userRef = doc(db, "users", user.uid);
- const userProfile = await getDoc(userRef);
- if (userProfile.exists()) {
- setProfileData(userProfile.data());
- } else {
- // User does not have a profile yet, could navigate to create profile
- navigate('/update-profile');
- }
+ fetchUserProfile(user.uid);
+ } else {
+ // If no user is logged in, navigate to login or another appropriate page
+ navigate('/login');
}
- };
+ });
- fetchUserProfile();
- }, [navigate, user]);
+ // Clean up the subscription
+ return () => unsubscribe();
+ }, [navigate]);
+
+ const fetchUserProfile = async (userId) => {
+ // Fetch user profile
+ const userRef = doc(db, "users", userId);
+ const userProfile = await getDoc(userRef);
+ if (userProfile.exists()) {
+ setProfileData(userProfile.data());
+ } else {
+ navigate('/update-profile');
+ }
+
+ // Fetch user's articles
+ const articlesRef = collection(db, "articles");
+ const q = query(articlesRef, where("userId", "==", userId));
+ const querySnapshot = await getDocs(q);
+ const articles = querySnapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }));
+ setUserArticles(articles);
+ };
const handleLogout = async () => {
- try {
- await signOut(auth);
- navigate('/'); // Navigate to the root or login page after logout
- } catch (error) {
+ await signOut(auth).catch((error) => {
console.error('Logout failed', error);
- }
+ });
+ navigate('/');
};
- const handleEditProfile = () => {
- // Navigate to the update profile page
- navigate('/update-profile');
+ const handleDelete = async (articleId) => {
+ const articleRef = doc(db, "articles", articleId);
+ await deleteDoc(articleRef);
+ // Update the UI by removing the deleted article
+ setUserArticles(userArticles.filter(article => article.id !== articleId));
};
return (
Welcome to your profile
- {user &&
Email: {user.email}
}
{profileData && (
<>
+
Email: {auth.currentUser?.email}
Name: {profileData.name}
Date of Birth: {profileData.dateOfBirth}
Location: {profileData.location}
+
+
>
)}
-
-
+
);
}
diff --git a/src/components/UserArticlesList/UserArticlesList.css b/src/components/UserArticlesList/UserArticlesList.css
new file mode 100644
index 0000000..263b5c3
--- /dev/null
+++ b/src/components/UserArticlesList/UserArticlesList.css
@@ -0,0 +1,69 @@
+.articles-container {
+ margin: 20px auto;
+ padding: 20px;
+ background-color: #f0f0f0; /* Light gray background */
+ border-radius: 8px; /* Rounded corners for the container */
+ max-width: 800px; /* Set a max-width for better reading experience on large screens */
+}
+
+/* Style the list to remove bullets and padding */
+ul {
+ list-style-type: none; /* Remove bullets */
+ padding: 0; /* Remove default padding */
+ margin: 0; /* Remove default margin */
+}
+
+.article-item {
+ display: flex;
+ flex-direction: column; /* Stack content vertically */
+ margin-bottom: 20px;
+ padding: 20px;
+ background-color: white;
+ border-radius: 5px;
+ border: 1px solid #ddd; /* Add a border for distinction */
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.15); /* Stronger shadow for more depth */
+ transition: box-shadow 0.3s ease; /* Smooth transition for shadow on hover */
+}
+
+.article-item:hover {
+ box-shadow: 0 6px 8px rgba(0, 0, 0, 0.25); /* Enhanced shadow when hovered */
+}
+
+.article-title {
+ font-weight: bold;
+ color: #333; /* Darker text for the title */
+ margin-bottom: 10px;
+}
+
+.article-body {
+ color: #666; /* Lighter text for the body */
+ margin-bottom: 15px; /* Add space before buttons */
+}
+
+.button {
+ padding: 10px 15px;
+ margin-right: 10px;
+ border: none;
+ border-radius: 5px;
+ cursor: pointer; /* Cursor pointer to indicate it's clickable */
+ transition: all 0.2s; /* Smooth transition for all properties */
+ align-self: flex-start; /* Align buttons to the start of the flex container */
+}
+
+.edit-button {
+ background-color: #4CAF50; /* Green background for edit */
+ color: white;
+}
+
+.edit-button:hover {
+ background-color: #45a049; /* Slightly darker green on hover */
+}
+
+.delete-button {
+ background-color: #f44336; /* Red background for delete */
+ color: white;
+}
+
+.delete-button:hover {
+ background-color: #da190b; /* Slightly darker red on hover */
+}
diff --git a/src/components/UserArticlesList/UserArticlesList.js b/src/components/UserArticlesList/UserArticlesList.js
new file mode 100644
index 0000000..8829aa4
--- /dev/null
+++ b/src/components/UserArticlesList/UserArticlesList.js
@@ -0,0 +1,26 @@
+// UserArticlesList.js
+import React from 'react';
+import { useNavigate } from 'react-router-dom';
+import 'components/UserArticlesList/UserArticlesList.css'; // Import the CSS file here
+
+function UserArticlesList({ articles, onDelete }) {
+ const navigate = useNavigate();
+
+ return (
+
+
Your Articles
+
+ {articles.map(article => (
+ -
+
{article.title}
+ {article.body}
+
+
+
+ ))}
+
+
+ );
+}
+
+export default UserArticlesList;
diff --git a/src/components/Write/Write.js b/src/components/Write/Write.js
new file mode 100644
index 0000000..a058c10
--- /dev/null
+++ b/src/components/Write/Write.js
@@ -0,0 +1,69 @@
+import React, { useState } from 'react';
+import { useNavigate } from 'react-router-dom';
+import { auth, db } from 'firebase-config';
+import { collection, addDoc, serverTimestamp } from 'firebase/firestore';
+import { useAuthState } from 'react-firebase-hooks/auth';
+
+function Write() {
+ const [title, setTitle] = useState('');
+ const [body, setBody] = useState('');
+ const navigate = useNavigate();
+ const [user] = useAuthState(auth);
+
+ const handleSubmit = async (e) => {
+ e.preventDefault();
+
+ // Ensure user is logged in
+ if (!user) {
+ alert('You must be logged in to submit a story.');
+ return;
+ }
+
+ // Save the submission to Firestore
+ try {
+ await addDoc(collection(db, "articles"), {
+ userId: user.uid,
+ title: title,
+ body: body,
+ createdAt: serverTimestamp(),
+ });
+
+ // Navigate to the profile page after successful submission
+ navigate('/profile');
+ } catch (error) {
+ console.error('Error saving the article: ', error);
+ alert('An error occurred while saving the article.');
+ }
+ };
+
+ return (
+
+
What's on your mind?
+
+
+ );
+}
+
+export default Write;