Skip to content

Commit 83f974d

Browse files
Next: Event Management Project APIs + MongoDB
1 parent b423881 commit 83f974d

File tree

16 files changed

+938
-5
lines changed

16 files changed

+938
-5
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import classes from "./comment-list.module.css";
2+
3+
function CommentList(props) {
4+
const { items } = props;
5+
6+
return (
7+
<ul className={classes.comments}>
8+
{items.map((comment) => {
9+
return (
10+
<li key={comment._id}>
11+
<p>{comment.text}</p>
12+
<div>
13+
By <address>{comment.name}</address>
14+
</div>
15+
</li>
16+
);
17+
})}
18+
</ul>
19+
);
20+
}
21+
22+
export default CommentList;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
.comments {
2+
display: flex;
3+
flex-direction: column;
4+
gap: 1rem;
5+
}
6+
7+
.comments li {
8+
text-align: left;
9+
padding: 0.5rem 0;
10+
border-bottom: 2px solid #ccc;
11+
}
12+
13+
.comments p {
14+
margin: 0;
15+
}
16+
17+
.comments li div {
18+
text-align: right;
19+
font-style: italic;
20+
}
21+
22+
.comments address {
23+
display: inline;
24+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { useEffect, useState } from "react";
2+
3+
import CommentList from "./comment-list";
4+
import NewComment from "./new-comment";
5+
import classes from "./comments.module.css";
6+
7+
function Comments(props) {
8+
const { eventId } = props;
9+
10+
const [comments, setComments] = useState([]);
11+
const [showComments, setShowComments] = useState(false);
12+
13+
useEffect(() => {
14+
if (!showComments) return;
15+
16+
getComments();
17+
}, [showComments]);
18+
19+
function toggleCommentsHandler() {
20+
setShowComments((prevStatus) => !prevStatus);
21+
}
22+
23+
function addCommentHandler(commentData) {
24+
fetch(`/api/comments/${eventId}`, {
25+
method: "POST",
26+
headers: {
27+
"Content-Type": "application/json",
28+
},
29+
body: JSON.stringify(commentData),
30+
});
31+
}
32+
33+
const getComments = () => {
34+
fetch(`/api/comments/${eventId}`)
35+
.then((res) => res.json())
36+
.then((data) => {
37+
console.log(data);
38+
setComments(data.comments);
39+
})
40+
.catch(console.error);
41+
};
42+
43+
return (
44+
<section className={classes.comments}>
45+
<button onClick={toggleCommentsHandler}>
46+
{showComments ? "Hide" : "Show"} Comments
47+
</button>
48+
{showComments && <NewComment onAddComment={addCommentHandler} />}
49+
{showComments && <CommentList items={comments} />}
50+
</section>
51+
);
52+
}
53+
54+
export default Comments;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
.comments {
2+
margin: 3rem auto;
3+
width: 90%;
4+
max-width: 40rem;
5+
text-align: center;
6+
}
7+
8+
.comments button {
9+
font: inherit;
10+
border-radius: 6px;
11+
padding: 0.5rem 1rem;
12+
background-color: transparent;
13+
color: #03be9f;
14+
border: 1px solid #03be9f;
15+
cursor: pointer;
16+
}
17+
18+
.comments button:hover,
19+
.comments button:active {
20+
background-color: #dcfff9;
21+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { useRef, useState } from "react";
2+
import classes from "./new-comment.module.css";
3+
4+
function NewComment(props) {
5+
const [isInvalid, setIsInvalid] = useState(false);
6+
7+
const emailInputRef = useRef();
8+
const nameInputRef = useRef();
9+
const commentInputRef = useRef();
10+
11+
function sendCommentHandler(event) {
12+
event.preventDefault();
13+
14+
const enteredEmail = emailInputRef.current.value;
15+
const enteredName = nameInputRef.current.value;
16+
const enteredComment = commentInputRef.current.value;
17+
18+
if (
19+
!enteredEmail ||
20+
enteredEmail.trim() === "" ||
21+
!enteredEmail.includes("@") ||
22+
!enteredName ||
23+
enteredName.trim() === "" ||
24+
!enteredComment ||
25+
enteredComment.trim() === ""
26+
) {
27+
setIsInvalid(true);
28+
return;
29+
}
30+
31+
props.onAddComment({
32+
email: enteredEmail,
33+
name: enteredName,
34+
text: enteredComment,
35+
});
36+
}
37+
38+
return (
39+
<form className={classes.form} onSubmit={sendCommentHandler}>
40+
<div className={classes.row}>
41+
<div className={classes.control}>
42+
<label htmlFor="email">Your email</label>
43+
<input
44+
type="email"
45+
id="email"
46+
ref={emailInputRef}
47+
defaultValue="[email protected]"
48+
/>
49+
</div>
50+
<div className={classes.control}>
51+
<label htmlFor="name">Your name</label>
52+
<input
53+
type="text"
54+
id="name"
55+
ref={nameInputRef}
56+
defaultValue="John Doe"
57+
/>
58+
</div>
59+
</div>
60+
<div className={classes.control}>
61+
<label htmlFor="comment">Your comment</label>
62+
<textarea
63+
id="comment"
64+
rows="5"
65+
ref={commentInputRef}
66+
defaultValue="Hello World!"
67+
></textarea>
68+
</div>
69+
{isInvalid && <p>Please enter a valid email address and comment!</p>}
70+
<button>Submit</button>
71+
</form>
72+
);
73+
}
74+
75+
export default NewComment;
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
.form {
2+
margin: 2rem auto;
3+
width: 100%;
4+
border-radius: 6px;
5+
background-color: #03be9f;
6+
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
7+
padding: 1rem;
8+
}
9+
10+
.row {
11+
display: flex;
12+
gap: 1rem;
13+
flex-wrap: wrap;
14+
}
15+
16+
.control {
17+
margin-bottom: 0.5rem;
18+
flex: 1;
19+
min-width: 10rem;
20+
}
21+
22+
.control label {
23+
display: block;
24+
font-weight: bold;
25+
margin-bottom: 0.5rem;
26+
color: white;
27+
text-align: left;
28+
}
29+
30+
.control input,
31+
.control textarea {
32+
font: inherit;
33+
padding: 0.25rem;
34+
border-radius: 4px;
35+
border: 1px solid #ccc;
36+
width: 100%;
37+
background-color: #dcfff9;
38+
}
39+
40+
.form button {
41+
background-color: white !important;
42+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { useRef } from "react";
2+
import classes from "./newsletter-registration.module.css";
3+
4+
function NewsletterRegistration() {
5+
const emailRef = useRef();
6+
7+
function registrationHandler(event) {
8+
event.preventDefault();
9+
10+
const email = emailRef.current.value;
11+
12+
fetch("/api/newsletter", {
13+
method: "POST",
14+
headers: {
15+
"Content-Type": "application/json",
16+
},
17+
body: JSON.stringify({ email }),
18+
})
19+
.then((res) => res.json())
20+
.then(console.log)
21+
.catch(console.error);
22+
}
23+
24+
return (
25+
<section className={classes.newsletter}>
26+
<h2>Sign up to stay updated!</h2>
27+
<form onSubmit={registrationHandler}>
28+
<div className={classes.control}>
29+
<input
30+
type="email"
31+
id="email"
32+
placeholder="Your email"
33+
aria-label="Your email"
34+
ref={emailRef}
35+
/>
36+
<button>Register</button>
37+
</div>
38+
</form>
39+
</section>
40+
);
41+
}
42+
43+
export default NewsletterRegistration;
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
.newsletter {
2+
margin: 3rem auto;
3+
width: 90%;
4+
max-width: 20rem;
5+
}
6+
7+
.newsletter h2 {
8+
text-align: center;
9+
}
10+
11+
.control input {
12+
font: inherit;
13+
padding: 0.25rem;
14+
border-radius: 4px;
15+
border-top-right-radius: 0;
16+
border-bottom-right-radius: 0;
17+
border: 1px solid #ccc;
18+
}
19+
20+
.newsletter button {
21+
background-color: #03be9f;
22+
border: 1px solid #03be9f;
23+
border-radius: 6px;
24+
color: #dafff7;
25+
border-top-left-radius: 0;
26+
border-bottom-left-radius: 0;
27+
font: inherit;
28+
cursor: pointer;
29+
}
30+
31+
.newsletter button:hover,
32+
.newsletter button:active {
33+
background-color: #02afa1;
34+
border-color: #02afa1;
35+
}
36+
37+
.control {
38+
display: flex;
39+
}
40+
41+
.control input {
42+
flex: 1;
43+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { MongoClient } from "mongodb";
2+
3+
export async function connectDatabase() {
4+
const DB_NAME = process.env.EB_NAME;
5+
const DB_USER = process.env.DB_USER;
6+
const DB_PASS = process.env.DB_PASS;
7+
const DB_URL = "cluster0.ntrwp.mongodb.net";
8+
9+
const client = await MongoClient.connect(
10+
`mongodb+srv://${DB_USER}:${DB_PASS}@${DB_URL}/${DB_NAME}?retryWrites=true&w=majority`
11+
);
12+
13+
return client;
14+
}
15+
16+
export async function insertDocument(client, collection, document) {
17+
const db = client.db();
18+
19+
const result = await db.collection(collection).insertOne(document);
20+
21+
return result;
22+
}
23+
24+
export async function getAllDocuments(client, collection, sort) {
25+
const db = client.db();
26+
27+
const documents = await db.collection(collection).find().sort(sort).toArray();
28+
29+
return documents;
30+
}

0 commit comments

Comments
 (0)