-
Notifications
You must be signed in to change notification settings - Fork 434
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
Project Happy Thoughts by Emma Engvall #445
base: master
Are you sure you want to change the base?
Changes from 8 commits
39540c7
e2f5d73
c7400cf
09f57a5
f112a77
d235f98
5332245
a2fcd03
25c3555
a623bda
1bad20a
ca24009
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,18 @@ | ||
# Happy Thoughts | ||
|
||
Replace this readme with your own information about your project. | ||
This week our assignment was to practice React state skills by fetching and posting data to an API. | ||
|
||
Start by briefly describing the assignment in a sentence or two. Keep it short and to the point. | ||
The following criteria should be met: | ||
✓ Your page should follow the design as closely as possible | ||
✓ You should list the most recent thoughts at the top and older thoughts at the bottom (sorted) | ||
✓ Your thoughts should show the content of the message and how many likes they've received | ||
✓ You should have a form to post new thoughts | ||
✓ You should implement the heart button to send likes on a thought | ||
|
||
## The problem | ||
What I learned from this week's project is that you cannot plan enough. I overcomplicated things and had to spend quite some time just going back and forth and then cleaning up the code. | ||
|
||
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? | ||
|
||
## View it live | ||
https://happy-thoughts-project-emma-engvall.netlify.app/ | ||
|
||
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. |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,89 @@ | ||
import React from 'react'; | ||
/* eslint-disable */ | ||
import React, { useState, useEffect } from 'react'; | ||
import { ThoughtForm } from 'components/ThoughtForm'; | ||
import { ThoughtList } from 'components/ThoughtList'; | ||
|
||
export const App = () => { | ||
|
||
const [thoughtList, setThoughtList] = useState ([]); | ||
const [loading, setLoading] = useState(false); | ||
const [newThought, setNewThought] = useState(''); | ||
|
||
//Fetching the latest 20 thoughts from the API | ||
const fetchThoughts = () => { | ||
setLoading(true); | ||
fetch('https://happy-thoughts-ux7hkzgmwa-uc.a.run.app/thoughts') | ||
.then((res) => res.json()) | ||
.then((data) => setThoughtList(data)) | ||
.catch((error) => console.error(error)) | ||
.finally(() => setLoading(false)); | ||
} | ||
|
||
useEffect(() => { | ||
fetchThoughts(); | ||
}, []) | ||
|
||
const handleNewThoughtChange = (event) => { | ||
setNewThought(event.target.value) | ||
} | ||
|
||
//Posting a new thought to the API | ||
const postNewThought = () => { | ||
const options = | ||
{ | ||
method: 'POST', | ||
headers: { | ||
'Content-Type': 'application/json' | ||
}, | ||
body: JSON.stringify({ message: newThought }) | ||
}; | ||
|
||
fetch('https://happy-thoughts-ux7hkzgmwa-uc.a.run.app/thoughts', options) | ||
.then((res) => res.json()) | ||
.then((data) => { | ||
setThoughtList((prevList) => [data, ...prevList]); | ||
}); | ||
} | ||
|
||
const handleFormSubmit = (event) => { | ||
event.preventDefault(); | ||
postNewThought(); | ||
setNewThought('') | ||
}; | ||
|
||
//Handle likes from users when the heart icon has been clicked. The number of likes will be increased by one every time the heart is clicked. | ||
const handleLike = (_id) => { | ||
fetch(`https://happy-thoughts-ux7hkzgmwa-uc.a.run.app/thoughts/${_id}/like`, { method: 'POST' }) | ||
.then((res) => { | ||
return res.json() | ||
}) | ||
.then ((data) => { | ||
const updateLikes = thoughtList.map((like) => { | ||
if (like._id === data._id) { | ||
like.hearts += 1; | ||
return like; | ||
} else { | ||
return like; | ||
} | ||
}); | ||
setThoughtList(updateLikes) | ||
}) | ||
} | ||
|
||
return ( | ||
<div> | ||
Find me in src/app.js! | ||
<main> | ||
<ThoughtForm | ||
newThought={newThought} | ||
onNewThoughtChange={handleNewThoughtChange} | ||
onFormSubmit={handleFormSubmit} | ||
/> | ||
<ThoughtList | ||
loading={loading} | ||
thoughtList={thoughtList} | ||
handleLike={handleLike} | ||
/> | ||
</main> | ||
</div> | ||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
/* eslint-disable */ | ||
import React from 'react'; | ||
|
||
export const ThoughtForm = ({ newThought, onNewThoughtChange, onFormSubmit }) => { | ||
|
||
//The submit button is disabled if the message contains less than six characters or more than 140 characters. | ||
const isSubmitButtonDisabled = newThought.length < 6 || newThought.length > 140; | ||
const characterWarning = () => { | ||
if (newThought.length > 140 ) { | ||
return ( | ||
<p className="character-warning">You are trying to send too much love.</p>) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Haha too much love is apparently a thing-in this app, atleast |
||
} else { | ||
return (<p className="character-count">{newThought.length} / 140</p>) | ||
} | ||
} | ||
return ( | ||
<section className="form-section"> | ||
<form classname="form" onSubmit={onFormSubmit}> | ||
<label className="label" htmlFor="new-thought"> | ||
<h2>What is making you happy right now? ❤️</h2> | ||
<textarea | ||
className="new-thought" | ||
id="new-thought" | ||
placeholder="Share your happy thought here..." | ||
rows="4" //maximum of four rows per message | ||
cols="40" //maximum of 40 characters per row. | ||
value={newThought} | ||
onChange={onNewThoughtChange} /> | ||
</label> | ||
{characterWarning()} | ||
<button | ||
className="submit-button" | ||
type="submit" | ||
disabled={isSubmitButtonDisabled}> | ||
❤️ Send Happy Thought ❤️ | ||
</button> | ||
</form> | ||
</section> | ||
) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
/* eslint-disable */ | ||
import React from 'react'; | ||
import { formatDistanceToNow } from 'date-fns'; | ||
|
||
|
||
export const ThoughtList = ({ loading, thoughtList, handleLike }) => { | ||
if (loading) { | ||
return <h1>Loading Happy Thoughts 💗</h1> | ||
} | ||
|
||
return ( | ||
<section className="thought-section"> | ||
{thoughtList.map((thought) => { | ||
return ( | ||
<div key={thought._id} className="single-thought"> | ||
<h4>{thought.message}</h4> | ||
<div className="thought-details"> | ||
<div className="likes-wrapper"> | ||
<button | ||
className={thought.hearts === 0 ? 'heart-button-nolikes' : 'heart-button'} | ||
type="button" | ||
onClick={() => handleLike(thought._id)}> | ||
❤️ | ||
</button> | ||
<span>x {thought.hearts}</span> | ||
</div> | ||
<div className="time-wrapper"> | ||
<span className="time">{formatDistanceToNow( //shows how long it has been since a message was posted | ||
new Date (thought.createdAt), | ||
Date.now(), | ||
{ addSuffix: true } | ||
)} | ||
ago | ||
</span> | ||
</div> | ||
</div> | ||
</div> | ||
)})} | ||
</section> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,104 @@ | ||
body { | ||
margin: 0; | ||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", | ||
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", | ||
sans-serif; | ||
margin: 0; | ||
font-family: Roboto Mono; | ||
background-color: white; | ||
-webkit-font-smoothing: antialiased; | ||
-moz-osx-font-smoothing: grayscale; | ||
display: flex; | ||
flex-direction: column; | ||
} | ||
|
||
code { | ||
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", | ||
monospace; | ||
} | ||
|
||
main { | ||
min-width: 335px; | ||
max-width: 500px; | ||
margin: 1.5rem auto 1rem auto; | ||
} | ||
|
||
.form-section { | ||
background-color: #f2f2f2; | ||
max-width: 500px; | ||
min-width: 335px; | ||
border: 1.6px solid; | ||
border-radius: 2px; | ||
box-shadow: 8px 8px; | ||
padding: 1.2rem; | ||
margin: 1rem; | ||
margin-bottom: 2rem; | ||
} | ||
|
||
h2 { | ||
font-family: monospace; | ||
font-weight: 400; | ||
font-size: 18px; | ||
} | ||
|
||
h4 { | ||
font-weight: 400; | ||
} | ||
|
||
.single-thought { | ||
background-color: white; | ||
max-width: 500px; | ||
min-width: 335px; | ||
border: 1.6px solid; | ||
border-radius: 2px; | ||
box-shadow: 8px 8px; | ||
margin: 1.5rem 1rem 1rem 1rem; | ||
padding: 1.2rem; | ||
overflow-wrap: break-word | ||
} | ||
|
||
.submit-button { | ||
background-color: pink; | ||
border-radius: 20px; | ||
font-family: monospace; | ||
padding: 8px 10px; | ||
border: none; | ||
cursor: pointer; | ||
color: black; | ||
font-weight: 600; | ||
font-size: 16px; | ||
} | ||
|
||
.submit-button:hover { | ||
background-color: #d5c0ff; | ||
} | ||
|
||
.character-count { | ||
color: rgb(104, 103, 103); | ||
font-size: 14px; | ||
margin-top: 2px; | ||
} | ||
|
||
.thought-details { | ||
display: flex; | ||
justify-content: space-between; | ||
} | ||
|
||
.heart-button, | ||
.heart-button-nolikes { | ||
border-radius: 100%; | ||
border: none; | ||
padding: 0.8rem; | ||
margin-right: 0.6rem; | ||
cursor: pointer; | ||
} | ||
|
||
.heart-button, | ||
.heart-button-nolikes:hover { | ||
background-color: pink; | ||
} | ||
|
||
.time { | ||
color: rgb(168, 167, 167); | ||
} | ||
|
||
.thought-section { | ||
margin-top: 2rem; | ||
} | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
very good comment