Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Projects happy thoughts - Sherry, Brian & Heléne #93

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ PS. Don't forget to add it in your readme as well.

## Collaborators
Add your collaborators here. Write their GitHub usernames in square brackets. If there's more than one, separate them with a comma, like this:
[github-username-1, github-username-2]

[[github-username-1](https://github.com/smily342), [github-username-2\]](https://github.com/Sherrydev11)
29 changes: 28 additions & 1 deletion src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,30 @@
// eslint-disable-next-line no-unused-vars
import React, { useEffect, useState } from "react";
import Form from "./Form";
import Thoughts from "./Thoughts";

export const App = () => {
return <div>Find me in src/app.jsx!</div>;
const [thoughts, setThoughts] = useState([]);


useEffect(() => {
fetch("https://happy-thoughts-ux7hkzgmwa-uc.a.run.app/thoughts")
.then((response) => response.json())
.then((data) => {
console.log(data);
setThoughts(data);
})
.catch((error) => console.error("Error fetching thoughts:", error));
}, []);

return (
<div>

{/* Pass setThoughts to Form */}
<Form setThoughts={setThoughts} />
<Thoughts thoughts={thoughts} setThoughts={setThoughts} />
</div>
);
};

export default App;
43 changes: 43 additions & 0 deletions src/Form.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React, { useState } from "react";

const Form = ({ setThoughts }) => {
const [message, setMessage] = useState("");

const handleSubmit = (event) => {
event.preventDefault();


// Send the message to the server using a POST request
fetch("https://happy-thoughts-ux7hkzgmwa-uc.a.run.app/thoughts", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ message }),
})
.then((res) => res.json())
.then((newThought) => {
setThoughts((prevThoughts) => [newThought, ...prevThoughts]);
setMessage("");
});
};

// Render the form and input elements for user interaction
return (
<form onSubmit={handleSubmit}>
<h2>What's making you happy right now?</h2>
<input
type="text"
value={message}
onChange={(e) => setMessage(e.target.value)}
placeholder="Write a happy thought"
required
minLength="5"
maxLength="140"
/>

<button className="submit">❤️ Send Happy Thought ❤️</button>
</form>
);
};

// Exported the Form component
export default Form;
79 changes: 79 additions & 0 deletions src/Thoughts.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import React, { useState } from "react";

const timeAgo = (timestamp) => {
const now = new Date();
const secondsDifference = Math.floor((now - new Date(timestamp)) / 1000);

//convert a given time difference
const units = {
year: 60 * 60 * 24 * 365,
month: 60 * 60 * 24 * 30,
week: 60 * 60 * 24 * 7,
day: 60 * 60 * 24,
hour: 60 * 60,
minute: 60,
second: 1,
};

for (let [unit, secondsInUnit] of Object.entries(units)) {
const amount = Math.floor(secondsDifference / secondsInUnit);
if (amount >= 1) {
return `${amount} ${unit}${amount > 1 ? "s" : ""} ago`;
}
}

return "just now";
};

const Thoughts = ({ thoughts, setThoughts }) => {
const [clickedIds, setClickedIds] = useState([]);

// Function for liking a thought
const handleLike = (id) => {
fetch(`https://happy-thoughts-ux7hkzgmwa-uc.a.run.app/thoughts/${id}/like`, {
method: "POST",
})
.then((res) => res.json())
.then((updatedThought) => {

if (updatedThought.hearts !== undefined && updatedThought.hearts !== null) {

setThoughts((prevThoughts) =>
prevThoughts.map((thought) =>
thought._id === updatedThought._id
? { ...thought, hearts: updatedThought.hearts }
: thought
)
);


setClickedIds((prevIds) => [...prevIds, id]);
}
})
.catch((error) => {
console.error("Error updating likes:", error);
});
};

return (
<div>
{/* Loop over each thought and show it */}
{thoughts.map((thought) => (
<div key={thought._id} className="message">
<p>{thought.message}</p>
<p className="time">{timeAgo(thought.createdAt)}</p>
<div className="heart-container">
<button
className={`heart-button ${clickedIds.includes(thought._id) ? "clicked" : ""}`}
onClick={() => handleLike(thought._id)}>
<span className="heart-icon">❤️ </span>
</button>
<span className="hearts-count"> x {thought.hearts ?? 0} </span>
</div>
</div>
))}
</div>
);
};

export default Thoughts;
156 changes: 148 additions & 8 deletions src/index.css
Original file line number Diff line number Diff line change
@@ -1,13 +1,153 @@
:root {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-family: 'Courier New', Courier, monospace;
}

code {
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
monospace;

/* Form styling */

form {
border: solid;
box-shadow: 10px 10px 1px 1px rgba(0, 0, 0, 0.801);
padding: 30px;
max-width: 70%;
margin: 20px;
background-color: rgba(238, 232, 232, 0.984);
margin-bottom: 40px;
box-sizing: border-box;
word-wrap: break-word;
overflow-wrap: break-word;
}


h2 {
font-size: 15px;
}

input {
padding: 25px;
width: 80%;
height: 20px;
}

.submit {
border-radius: 20px;
background-color: pink;
margin-top: 20px;
padding: 10px;
border: none;
}

/* Message styling */

.message {
border: solid;
padding: 30px;
max-width: 70%;
max-height: 30%;
margin: 20px;
margin-bottom: 40px;
box-shadow: 10px 10px 1px 1px rgba(0, 0, 0, 0.801);
box-sizing: border-box;
word-wrap: break-word;
overflow-wrap: break-word;
position: relative;
}

/* Heart button styling */
.heart-button {
background: rgb(232, 229, 229);
border-radius: 150%;
height: 50px;
width: 50px;
border: none;
font-size: 20px;
cursor: pointer;
}

.heart-button.clicked {
background-color: #ffcccb;
}

.hearts-count {
margin-right: 500px;
font-family: Arial, Helvetica, sans-serif;
color: rgb(182, 176, 176);

}

.heart-container {
display: flex;
align-items: center;
}

/* time styling */
.time {
font-size: 0.85rem;
font-family: Arial, Helvetica, sans-serif;
color: lightgrey;
position: absolute;
bottom: 10px;
right: 10px;
}




/* Responsive design for tablets */
@media (min-width:768px) and (max-width:1024px) {
body {
display: flex;
align-items: center;
overflow-x: hidden;
}

.message,
form {
max-width: 60%;
}

.hearts-count {
margin-right: 580px;
}

h1 {
text-align: center;
}
}

/* Responsive design for mobile*/

@media (min-width: 320px) and (max-width: 767px) {

body {
margin: 0;
padding: 0;
overflow-x: hidden;
}

form {
width: 80%;
max-width: 100%;
padding: 20px;
margin: 20px auto;
padding: 30px;
margin-right: 40px;
}

input {
width: 70%;
}

.heart-button {
padding: 15px;
}

.message {
margin-left: 30px;
width: 80%;
max-width: 100%;
}


}