Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
aungphone-mm committed Jul 26, 2024
1 parent b0ce236 commit 72ab85a
Show file tree
Hide file tree
Showing 10 changed files with 1,264 additions and 38 deletions.
902 changes: 902 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"firebase": "^10.12.4",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-scripts": "5.0.1",
Expand Down Expand Up @@ -34,5 +35,8 @@
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"gh-pages": "^6.1.1"
}
}
71 changes: 47 additions & 24 deletions src/App.css
Original file line number Diff line number Diff line change
@@ -1,38 +1,61 @@
.App {
text-align: center;
max-width: 800px;
margin: 0 auto;
padding: 20px;
font-family: Arial, sans-serif;
}

.App-logo {
height: 40vmin;
pointer-events: none;
.App-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}

@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
.user-info {
display: flex;
align-items: center;
}

.App-header {
background-color: #282c34;
min-height: 100vh;
.user-info span {
margin-right: 10px;
}

h1, h2 {
color: #333;
}

form {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
margin-bottom: 20px;
}

.App-link {
color: #61dafb;
input, textarea {
margin-bottom: 10px;
padding: 8px;
font-size: 16px;
}

@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
button {
padding: 10px;
background-color: #007bff;
color: white;
border: none;
cursor: pointer;
font-size: 16px;
}

button:hover {
background-color: #0056b3;
}
.auth-options {
display: flex;
justify-content: space-between;
margin-top: 20px;
}

.auth-options button {
flex: 1;
margin: 0 5px;
}
73 changes: 59 additions & 14 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,70 @@
import logo from './logo.svg';
// src/App.js

import React, { useState, useEffect } from 'react';
import './App.css';
import SignUp from './components/SignUp';
import Login from './components/Login';
import PasswordReset from './components/PasswordReset';
import NewEntry from './components/NewEntry';
import EntryList from './components/EntryList';
import { auth } from './firebase';

function App() {
const [user, setUser] = useState(null);
const [authMode, setAuthMode] = useState('login'); // 'login', 'signup', or 'reset'

useEffect(() => {
const unsubscribe = auth.onAuthStateChanged((user) => {
setUser(user);
});
return () => unsubscribe();
}, []);

const handleLogout = () => {
auth.signOut();
};

const renderAuthComponent = () => {
switch(authMode) {
case 'signup':
return <SignUp />;
case 'reset':
return <PasswordReset />;
default:
return <Login />;
}
};

return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
<h1>My Diary App</h1>
{user && (
<div className="user-info">
<span>Logged in as: {user.email}</span>
<button onClick={handleLogout}>Logout</button>
</div>
)}
</header>
<main>
{user ? (
<>
<NewEntry />
<EntryList />
</>
) : (
<>
{renderAuthComponent()}
<div className="auth-options">
<button onClick={() => setAuthMode('login')}>Login</button>
<button onClick={() => setAuthMode('signup')}>Sign Up</button>
<button onClick={() => setAuthMode('reset')}>Forgot Password</button>
</div>
</>
)}
</main>
</div>
);
}

export default App;
export default App;
37 changes: 37 additions & 0 deletions src/components/EntryList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React, { useState, useEffect } from 'react';
import { collection, query, orderBy, onSnapshot } from 'firebase/firestore';
import { auth, db } from '../firebase';

const EntryList = () => {
const [entries, setEntries] = useState([]);

useEffect(() => {
if (auth.currentUser) {
const q = query(collection(db, `users/${auth.currentUser.uid}/entries`), orderBy('createdAt', 'desc'));
const unsubscribe = onSnapshot(q, (querySnapshot) => {
const entriesData = querySnapshot.docs.map(doc => ({
id: doc.id,
...doc.data()
}));
setEntries(entriesData);
});

return () => unsubscribe();
}
}, []);

return (
<div>
<h2>Your Entries</h2>
{entries.map(entry => (
<div key={entry.id}>
<h3>{entry.title}</h3>
<p>{entry.content}</p>
<small>{entry.createdAt.toDate().toLocaleString()}</small>
</div>
))}
</div>
);
};

export default EntryList;
47 changes: 47 additions & 0 deletions src/components/Login.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// src/components/Login.js

import React, { useState } from 'react';
import { signInWithEmailAndPassword } from 'firebase/auth';
import { auth } from '../firebase';

const Login = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState(null);

const handleLogin = async (e) => {
e.preventDefault();
try {
await signInWithEmailAndPassword(auth, email, password);
setEmail('');
setPassword('');
setError(null);
} catch (error) {
setError(error.message);
}
};

return (
<form onSubmit={handleLogin}>
<h2>Login</h2>
{error && <p style={{color: 'red'}}>{error}</p>}
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
required
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Password"
required
/>
<button type="submit">Login</button>
</form>
);
};

export default Login;
54 changes: 54 additions & 0 deletions src/components/NewEntry.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React, { useState } from 'react';
import { addDoc, collection } from 'firebase/firestore';
import { auth, db } from '../firebase';

const NewEntry = () => {
const [title, setTitle] = useState('');
const [content, setContent] = useState('');

const handleSubmit = async (e) => {
e.preventDefault();

if (!auth.currentUser) {
alert('You must be logged in to create an entry.');
return;
}

try {
const docRef = await addDoc(collection(db, `users/${auth.currentUser.uid}/entries`), {
title: title,
content: content,
createdAt: new Date(),
});
console.log("Document written with ID: ", docRef.id);
setTitle('');
setContent('');
alert('Entry added successfully!');
} catch (e) {
console.error("Error adding document: ", e);
alert('Error adding entry. Please try again.');
}
};

return (
<form onSubmit={handleSubmit}>
<h2>New Diary Entry</h2>
<input
type="text"
value={title}
onChange={(e) => setTitle(e.target.value)}
placeholder="Entry Title"
required
/>
<textarea
value={content}
onChange={(e) => setContent(e.target.value)}
placeholder="Write your entry here..."
required
/>
<button type="submit">Add Entry</button>
</form>
);
};

export default NewEntry;
41 changes: 41 additions & 0 deletions src/components/PasswordReset.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// src/components/PasswordReset.js

import React, { useState } from 'react';
import { sendPasswordResetEmail } from 'firebase/auth';
import { auth } from '../firebase';

const PasswordReset = () => {
const [email, setEmail] = useState('');
const [message, setMessage] = useState('');
const [error, setError] = useState('');

const handleResetPassword = async (e) => {
e.preventDefault();
try {
await sendPasswordResetEmail(auth, email);
setMessage('Check your email for password reset instructions.');
setError('');
} catch (error) {
setError(error.message);
setMessage('');
}
};

return (
<form onSubmit={handleResetPassword}>
<h2>Reset Password</h2>
{message && <p style={{color: 'green'}}>{message}</p>}
{error && <p style={{color: 'red'}}>{error}</p>}
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Enter your email"
required
/>
<button type="submit">Reset Password</button>
</form>
);
};

export default PasswordReset;
Loading

0 comments on commit 72ab85a

Please sign in to comment.