-
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
Sammy: project-happy-thoughts #436
base: master
Are you sure you want to change the base?
Changes from all commits
43e51a4
c0935c5
7803d3e
4bc6987
e0fdb7c
db11ff8
2ab7733
c668744
354b06b
b99f606
a9972df
42ac0c0
c79d1b6
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,13 @@ | ||
# Happy Thoughts | ||
|
||
Replace this readme with your own information about your project. | ||
|
||
Start by briefly describing the assignment in a sentence or two. Keep it short and to the point. | ||
Practice React state skills by fetching and posting data to an API. | ||
The task was to follow a design but I kinda failed on that part. | ||
|
||
## 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? | ||
Hard to know what to put in components, had to remove/add/rearrange my code multiple times. | ||
CSS, JS, React, API. | ||
|
||
## View it live | ||
|
||
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. | ||
https://phenomenal-bavarois-c771f2.netlify.app/ |
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,90 @@ | ||
import React from 'react'; | ||
/* eslint-disable linebreak-style */ | ||
/* eslint-disable no-underscore-dangle */ | ||
import Footer from 'components/Footer'; | ||
import React, { useState, useEffect } from 'react'; | ||
import Header from './components/Header' | ||
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('') | ||
|
||
/* FETCHES MOST RECENT THOUGHTS */ | ||
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(); | ||
}, []) | ||
|
||
/* WRTIES NEW TEXT-INPUT-VALUE TO SETNEWTHOUGHT */ | ||
const handleNewThoughtChange = (event) => { | ||
setNewThought(event.target.value) | ||
} | ||
|
||
/* POSTS NEW THOUGHT AND UPDATES STATE */ | ||
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('') | ||
}; | ||
|
||
/* POSTS NEW LIKES TO API */ | ||
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! | ||
<Header /> | ||
<main> | ||
<ThoughtForm | ||
onFormSubmit={handleFormSubmit} | ||
newThought={newThought} | ||
onNewThoughtChange={handleNewThoughtChange} /> | ||
<ThoughtList | ||
loading={loading} | ||
thoughtList={thoughtList} | ||
handleLike={handleLike} /> | ||
</main> | ||
<Footer /> | ||
</div> | ||
); | ||
} | ||
} | ||
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. Very nice structure in your App.js! Impressive! |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import React from 'react'; | ||
|
||
const Footer = () => { | ||
return ( | ||
<div aria-hidden="true" className="contact"> | ||
<p>Happy Thoughts made by <a href="https://www.linkedin.com/in/sammy-olsson/" target="_blank" rel="noreferrer">Sammy Olsson</a>, | ||
Team-🐢 | ||
Comment on lines
+6
to
+7
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. Nice add with the contact information! |
||
</p> | ||
</div> | ||
) | ||
}; | ||
|
||
export default Footer; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
/* eslint-disable linebreak-style */ | ||
import React from 'react'; | ||
import logo from './assets/happy-logo.png' | ||
|
||
const Header = () => { | ||
return ( | ||
<header> | ||
<div className="image-wrapper"> | ||
<img className="logo" src={logo} alt="logo happy thoughts" /> | ||
</div> | ||
</header>) | ||
} | ||
|
||
export default Header; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
/* eslint-disable linebreak-style */ | ||
import React from 'react'; | ||
|
||
const ThoughtForm = ({ newThought, onNewThoughtChange, onFormSubmit }) => { | ||
const isSubmitButtonDisabled = newThought.length < 6 || newThought.length > 140; | ||
Comment on lines
+4
to
+5
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. Short and consistent code on the length parameters. |
||
/* SHOWS CHARACTER-COUNT OR A WARNING MESSAGE DEPENDING ON NUMBER OF CHARACTERS */ | ||
const characterWarning = () => { | ||
if (newThought.length > 140) { | ||
return (<p className="character-warning">Your thought can only be 140 characters long</p>) | ||
} else { | ||
return (<p className="character-count">{newThought.length} / 140, need atleast 6 characters.</p>) | ||
} | ||
} | ||
return ( | ||
<section className="form-section"> | ||
<form className="form" onSubmit={onFormSubmit}> | ||
<label className="label" htmlFor="thought-input"> | ||
What's making you happy right now? | ||
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. Good job adding the: ' |
||
<textarea | ||
className="thought-input" | ||
id="thought-input" | ||
placeholder="Enter the happy thought here..." | ||
value={newThought} | ||
onChange={onNewThoughtChange} /> | ||
</label> | ||
{characterWarning()} | ||
<button | ||
className="submit-button" | ||
type="submit" | ||
disabled={isSubmitButtonDisabled}> | ||
🖤 Shoot a happy thought! | ||
</button> | ||
</form> | ||
</section>) | ||
} | ||
|
||
export default ThoughtForm |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
/* eslint-disable linebreak-style */ | ||
/* eslint-disable no-underscore-dangle */ | ||
import React from 'react'; | ||
import { formatDistanceToNow } from 'date-fns'; | ||
|
||
const ThoughtList = ({ loading, thoughtList, handleLike }) => { | ||
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. Very clear and structured code and props. Your code is easy to follow and understand. |
||
if (loading) { | ||
return <h2>Loading happy thought...</h2> | ||
} | ||
return ( | ||
<section className="thought-section"> | ||
{thoughtList.map((thought) => { | ||
return ( | ||
<div key={thought._id} className="single-thought"> | ||
<p>{thought.message}</p> | ||
<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( | ||
Comment on lines
+26
to
+27
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. Smart solution with the newDate. |
||
new Date(thought.createdAt), | ||
Date.now(), | ||
{ addSuffix: true } | ||
)} | ||
</span> | ||
</div> | ||
</div> | ||
</div> | ||
) | ||
})} | ||
|
||
</section> | ||
) | ||
} | ||
|
||
export default ThoughtList |
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.
Good job commenting!