-
# Happy thoughts Project
In this week's project, you'll be able to practice your React state skills by fetching and posting data to an API.
-## Getting Started with the Project
-
-### Dependency Installation & Startup Development Server
-
-Once cloned, navigate to the project's root directory and this project uses npm (Node Package Manager) to manage its dependencies.
-
-The command below is a combination of installing dependencies, opening up the project on VS Code and it will run a development server on your terminal.
-
-```bash
-npm i && code . && npm run dev
-```
-
### The Problem
-Describe how you approached to problem, and what tools and techniques you used to solve it. How did you plan? What technologies did you use? If you had more time, what would be next?
+I started by created the components I believed I needed. My goal was to have the App.jsx as clean as possible and let the components handle the tasks: GET, POST and the returns. I realised quite late that I couldnt insert the new post into the Thoughts list without merging most of the code into one component. Tried many different options but still haven't managed figuring it out. So with more time I would probably create more, but simpler components or just divide it differently. I would also have liked to reach more of the strechgoals.
-### View it live
+I managed quite far with the class material but halfway I got stuck and used ChatGPT, Google and previous students code as my help.
-Every project should be deployed somewhere. Be sure to include the link to the deployed project so that the viewer can click around and see what it's all about.
+Something I find very challenged is to plan correctly and I feel that I don't know what is right and wrong and doubt my solutions a lot.
-## Instructions
+### View it live
-
- See instructions of this project
-
+https://gabyshappythoughts.netlify.app/
diff --git a/package.json b/package.json
index 74245b0c..7bef2983 100644
--- a/package.json
+++ b/package.json
@@ -10,6 +10,7 @@
"preview": "vite preview"
},
"dependencies": {
+ "date-fns": "^4.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
diff --git a/src/App.jsx b/src/App.jsx
index 1091d431..22b1213b 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -1,3 +1,16 @@
+import React from "react"
+import { Header } from "./components/header/Header";
+import { PostThoughts } from "./components/postThoughts/PostThoughts";
+import { Thoughts } from "./components/thoughts/Thoughts"
+import { Footer } from "./components/footer/Footer";
+
export const App = () => {
- return
Find me in src/app.jsx!
;
+ return (
+
+
+
+
+
+
+ );
};
diff --git a/src/components/ApiUrl.jsx b/src/components/ApiUrl.jsx
new file mode 100644
index 00000000..75246af5
--- /dev/null
+++ b/src/components/ApiUrl.jsx
@@ -0,0 +1 @@
+ export const URL = "https://happy-thoughts-ux7hkzgmwa-uc.a.run.app/thoughts"
\ No newline at end of file
diff --git a/src/components/footer/Footer.jsx b/src/components/footer/Footer.jsx
new file mode 100644
index 00000000..a7ee3f45
--- /dev/null
+++ b/src/components/footer/Footer.jsx
@@ -0,0 +1,10 @@
+import "./footer.css";
+
+export const Footer = () => {
+ return (
+
+
Thank you for your sparkle
+
ยฉ 2024 Copyright - Developed by Gabriella Iofe
+
+ )
+}
\ No newline at end of file
diff --git a/src/components/footer/footer.css b/src/components/footer/footer.css
new file mode 100644
index 00000000..5c5798ed
--- /dev/null
+++ b/src/components/footer/footer.css
@@ -0,0 +1,19 @@
+.footer {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+h4 {
+ font-family: Courier New, monospace;
+ font-size: 16px;
+ margin-bottom: 5px;
+
+}
+
+h5 {
+ font-family: Courier New, monospace;
+ font-size: 11px;
+ margin-top: auto;
+ margin-bottom: 10px;
+}
\ No newline at end of file
diff --git a/src/components/header/Header.jsx b/src/components/header/Header.jsx
new file mode 100644
index 00000000..d58a61f1
--- /dev/null
+++ b/src/components/header/Header.jsx
@@ -0,0 +1,11 @@
+import "./header.css";
+
+export const Header = () => {
+ return (
+
+
Happy Thoughts Project
+
by Gabriella Iofe
+
+ )
+
+}
\ No newline at end of file
diff --git a/src/components/header/header.css b/src/components/header/header.css
new file mode 100644
index 00000000..e0267b31
--- /dev/null
+++ b/src/components/header/header.css
@@ -0,0 +1,20 @@
+.header {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+h1 {
+ font-family: Courier New, monospace;
+ font-size: 23px;
+ font-weight: bold;
+ margin-bottom: 5px;
+
+}
+
+h2 {
+ font-family: Courier New, monospace;
+ font-size: 15px;
+ margin-top: auto;
+ margin-bottom: 30px;
+}
\ No newline at end of file
diff --git a/src/components/postThoughts/PostThoughts.jsx b/src/components/postThoughts/PostThoughts.jsx
new file mode 100644
index 00000000..2e09b834
--- /dev/null
+++ b/src/components/postThoughts/PostThoughts.jsx
@@ -0,0 +1,77 @@
+import { useState } from "react";
+import { URL } from "../ApiUrl";
+import "./postThoughts.css";
+
+
+
+export const PostThoughts = () => {
+ const [body, setBody] = useState('')
+ const [loading, setLoading] = useState(false)
+ const [errorMessage, setErrorMessage] = useState('');
+
+
+ //This functions POSTs a happy thought to the API
+ const handleSubmit = async (event) => {
+ event.preventDefault()
+ setLoading(true) /* Start loading on submit */
+ setErrorMessage('');
+
+ // Validation: Check if message is between 5 and 140 characters
+ if (body.length < 5 || body.length > 140) {
+ setErrorMessage("Message must be between 5 and 140 characters.");
+ setLoading(false);
+ return;
+ }
+
+ try {
+ const response = await fetch(URL, {
+ method: "POST",
+ headers: {
+ //this is a way to send extra information to our API.
+ "content-type": "application/json; charset=utf-8"
+ },
+ body: JSON.stringify({message: body})//command to tell API the message (and what i call it in my code "body" should be fetched)
+ });
+
+ if (response.ok) {
+ const recentBody = await response.json(); //Get the new post
+ setBody((previousBody) => [recentBody, ...previousBody]); // Update the post state
+ setBody(''); //this clears the input field after its been posted
+
+ } else {
+ const errorData = await response.json();
+ setErrorMessage(errorData.message || "An error occurred. Please try again.");
+ }
+ } catch (error) {
+ setErrorMessage("Network error. Please try again later.");
+ console.log("error:", error);
+ } finally {
+ setLoading(false) /* Stops the loading */
+ }
+ }
+
+
+ return (
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/components/postThoughts/postThoughts.css b/src/components/postThoughts/postThoughts.css
new file mode 100644
index 00000000..719ea25b
--- /dev/null
+++ b/src/components/postThoughts/postThoughts.css
@@ -0,0 +1,45 @@
+.post-thoughts-container {
+ background-color: rgb(239, 236, 237);
+ border: solid rgb(209, 208, 209) 2px;
+ padding: 15px;
+ margin: 0px 15px 25px 15px;
+ box-shadow: 6px 6px 0px 0px rgb(0, 0, 0);
+}
+
+label {
+ color: black;
+}
+
+h3 {
+ font-family:"Segoe UI", Arial, sans-serif;
+ font-size: 16px;
+}
+
+.textarea {
+ background-color: white;
+ height: 50px;
+ width: 100%;
+ margin: 10px 0px 10px 0px;
+ padding: 5px;
+ font-family: Courier New, monospace;
+ font-size: 13px;
+}
+
+.error-message {}
+
+.send-button {
+ padding: 9px;
+ border-radius: 30px;
+ border: none;
+ background-color: rgb(250, 144, 160);
+ font-size: 13px;
+ font-family: "Segoe UI", Arial, sans-serif;
+}
+
+@media only screen and (min-width: 768px) {
+ .post-thoughts-container {
+ width: 417px;
+ margin-left: auto;
+ margin-right: auto;
+ }
+ }
\ No newline at end of file
diff --git a/src/components/thoughts/Thoughts.jsx b/src/components/thoughts/Thoughts.jsx
new file mode 100644
index 00000000..55f75200
--- /dev/null
+++ b/src/components/thoughts/Thoughts.jsx
@@ -0,0 +1,74 @@
+
+import { useState,useEffect } from "react"
+import { URL } from "../ApiUrl";
+import { formatDistance } from 'date-fns';
+import "./thoughts.css";
+
+//A function to fetch and display the message object in a list
+export const Thoughts = () => {
+ const [thoughts, setThoughts] = useState([])
+
+ useEffect(() => {
+ const fetchThoughts = async () => {
+ try {
+ const response = await fetch(URL)
+ const data = await response.json()
+ setThoughts(data)
+ console.log("Thought is", data)
+ } catch (error) {
+ console.log("Error fetching thoughts is:", error)
+ }
+ }
+ fetchThoughts()
+ }, []);
+
+
+ const addLike = async (postId) => {
+ try {
+ fetch(`${URL}/${postId}/like`, {method: "POST"})
+
+ //Update the state with a like
+ setThoughts((prevThoughts) =>
+ prevThoughts.map((thought) =>
+ thought._id === postId ? { ...thought, hearts: thought.hearts + 1 } : thought
+ ))
+ } catch (error) {
+ console.error("Error liking the post is:", error)
+ }
+ }
+
+
+
+ return (
+
+
+ {thoughts.map((thought) => (
+
+
{thought.message}
+
+
+
+ x {thought.hearts} {/* Display likes outside the button */}
+