diff --git a/pull_request_template.md b/pull_request_template.md index d92c89b5..e977ab0f 100644 --- a/pull_request_template.md +++ b/pull_request_template.md @@ -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) diff --git a/src/App.jsx b/src/App.jsx index 1091d431..99cc4144 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -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
Find me in src/app.jsx!
; + 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 ( +
+ + {/* Pass setThoughts to Form */} +
+ +
+ ); }; + +export default App; diff --git a/src/Form.jsx b/src/Form.jsx new file mode 100644 index 00000000..11d2fadd --- /dev/null +++ b/src/Form.jsx @@ -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 ( + +

What's making you happy right now?

+ setMessage(e.target.value)} + placeholder="Write a happy thought" + required + minLength="5" + maxLength="140" + /> + + + + ); +}; + +// Exported the Form component +export default Form; diff --git a/src/Thoughts.jsx b/src/Thoughts.jsx new file mode 100644 index 00000000..3f5c4a5c --- /dev/null +++ b/src/Thoughts.jsx @@ -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 ( +
+ {/* Loop over each thought and show it */} + {thoughts.map((thought) => ( +
+

{thought.message}

+

{timeAgo(thought.createdAt)}

+
+ + x {thought.hearts ?? 0} +
+
+ ))} +
+ ); +}; + +export default Thoughts; diff --git a/src/index.css b/src/index.css index 4558f538..272a90c9 100644 --- a/src/index.css +++ b/src/index.css @@ -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%; + } + + +} \ No newline at end of file