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

Week 7 - Happy Thoughts by Daniel #442

Open
wants to merge 18 commits into
base: master
Choose a base branch
from
22 changes: 18 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,27 @@
# 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.
A happy twitter-like wall for all you thoughts. Share what you are thinking about right now!

## 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?
### The challenge


In this week's project, you'll be able to practice your React state skills by fetching and posting data to an API.

**What you need to do**

✓ 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

## 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://technigo-happy-thoughts-app.netlify.app/
14 changes: 4 additions & 10 deletions code/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
{
"extends": [
"airbnb"
],
"extends": ["airbnb"],
"globals": {
"document": true,
"window": true,
Expand All @@ -22,10 +20,9 @@
"modules": true
}
},
"plugins": [
"react-hooks"
],
"plugins": ["react-hooks"],
"rules": {
"linebreak-style": ["off", "unix"],
"react/function-component-definition": [
2,
{
Expand All @@ -42,10 +39,7 @@
"allowSingleLine": true
}
],
"comma-dangle": [
"error",
"never"
],
"comma-dangle": ["error", "never"],
"consistent-return": "off",
"curly": "error",
"eol-last": "off",
Expand Down
14 changes: 14 additions & 0 deletions code/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion code/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "technigo-react-starter",
"version": "1.0.0",
"private": true,
"private": false,
"dependencies": {
"babel-eslint": "^10.1.0",
"eslint": "^8.21.0",
Expand All @@ -10,6 +10,7 @@
"eslint-plugin-jsx-a11y": "^6.6.1",
"eslint-plugin-react": "^7.30.1",
"eslint-plugin-react-hooks": "^4.6.0",
"moment": "^2.29.4",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
Expand Down
57 changes: 53 additions & 4 deletions code/src/App.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,58 @@
import React from 'react';
/* eslint-disable react/jsx-closing-bracket-location */
/* eslint-disable no-unused-vars */
import React, { useEffect, useState } from 'react';
import { List } from 'components/List';
import { Input } from 'components/Input';

export const App = () => {
const [thoughts, setThoughts] = useState([]);
const [newPost, setNewPost] = useState('');
const [loading, setLoading] = useState(true);

const fetchThoughts = () => {
fetch('https://happy-thoughts-ux7hkzgmwa-uc.a.run.app/thoughts')
.then((res) => res.json())
.then((data) => {
setThoughts(data);
})
.finally(() => setLoading(false))
.catch((error) => console.log(error));
};

useEffect(() => {
fetchThoughts();
}, []);

const handleLikeChange = (id) => {
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
};
fetch(
`https://happy-thoughts-ux7hkzgmwa-uc.a.run.app/thoughts/${id}/like`,
options
)
.catch((error) => console.log(error))
.finally(() => fetchThoughts());
};
return (
<div>
Find me in src/app.js!
<div className="container">
<Input
thoughts={thoughts}
setThoughts={setThoughts}
newPost={newPost}
setNewPost={setNewPost}
/>
{loading && <p>Thoughts is loading...</p>}
{thoughts && (
<List
thoughts={thoughts}
setThoughts={setThoughts}
handleLikeChange={handleLikeChange}
/>
)}
</div>
);
}
};
55 changes: 55 additions & 0 deletions code/src/components/Input.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
.box {
background-color: rgb(250, 255, 253);
width: 80%;
display: flex;
flex-wrap: wrap;
border: 2px solid black;
box-shadow: 10px 10px 5px 0px rgba(0, 0, 0, 0.75);
-webkit-box-shadow: 10px 10px 5px 0px rgba(0, 0, 0, 0.75);
-moz-box-shadow: 10px 10px 5px 0px rgba(0, 0, 0, 0.75);
margin: 2rem;
}

.input-box {
background-color: rgb(234, 233, 233);
}

.input-box * {
padding: 0 1rem 0 1rem;
}

label {
width: 100%;
font-size: 1.2rem;
font-weight: 700;
margin: 1rem 0 0 0;
}

textarea {
width: 100%;
margin: 0.5rem 0 0 0;
border: 1px solid gray;
background-color: rgb(254, 254, 254);
}

.input-box button {
height: 3rem;
font-weight: 700;
background-color: rgba(229, 3, 3, 0.5);
border: none;
border-radius: 20px;
margin: 0.5rem 1rem 1rem;
}
button:hover {
cursor: pointer;
}

.input-box button:focus {
border: 2px solid black;
}
button:disabled,
button[disabled] {
border: 1px solid #999999;
background-color: #cccccc;
color: #666666;
}
50 changes: 50 additions & 0 deletions code/src/components/Input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/* eslint-disable react/jsx-closing-bracket-location */
/* eslint-disable no-unused-vars */
import React from 'react';
import './Input.css';

export const Input = ({ newPost, setNewPost, thoughts, setThoughts }) => {
const handleFormSubmit = (event) => {
event.preventDefault();
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ message: newPost })
};

fetch('https://happy-thoughts-ux7hkzgmwa-uc.a.run.app/thoughts', options)
.then((res) => res.json())
.then((newThought) => {
console.log(newThought);
setThoughts((prevThoughts) => [newThought, ...prevThoughts]);
})
.catch((error) => console.log(error));
};
return (
<div>
<form onSubmit={handleFormSubmit} className="box input-box">
<label htmlFor="thoughts" className="input-heading">
Whats making you happy right now?
<textarea
name="thoughts"
rows="4"
value={newPost}
placeholder="Write something nice"
onChange={(e) => {
setNewPost(e.target.value);
}}
/>
</label>
<button
type="submit"
disabled={newPost.length < 5 || newPost.length > 140}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Smart way of handling the allowed input length!

>
{' '}
❤️ Send happy thought ❤️
</button>
</form>
</div>
);
};
60 changes: 60 additions & 0 deletions code/src/components/List.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
@import url('https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@400;500;600&display=swap');
.box {
background-color: rgb(250, 255, 253);
width: 80%;
display: flex;
flex-wrap: wrap;
border: 2px solid black;
box-shadow: 10px 10px 5px 0px rgba(0, 0, 0, 0.75);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The softened box-shadow looks nice

-webkit-box-shadow: 10px 10px 5px 0px rgba(0, 0, 0, 0.75);
-moz-box-shadow: 10px 10px 5px 0px rgba(0, 0, 0, 0.75);
margin: 2rem;
}

.list {
width: 80%;
}
.message-text {
font-family: 'Roboto Mono', monospace;
width: 100%;
font-size: 1.2rem;
font-weight: 700;
padding: 0 0 0 1rem;
overflow-wrap: break-word;
}
.stats-container {
width: 100%;
display: flex;
justify-content: space-between;
margin: 1rem;
}

.like-container {
display: flex;
justify-content: space-between;
width: 5rem;
}
.like-container p {
margin: auto;
}
.heart {
border-radius: 50%;
width: 50px;
height: 50px;
display: flex;
justify-content: center;
align-items: center;
background-color: rgb(253, 254, 254);
}
.heart:hover {
cursor: pointer;
background-color: rgba(255, 0, 0, 0.2);
}

.time {
display: flex;
}

.time p {
margin: auto;
}
32 changes: 32 additions & 0 deletions code/src/components/List.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/* eslint-disable jsx-a11y/click-events-have-key-events */
/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */
/* eslint-disable no-unused-vars */
/* eslint-disable no-underscore-dangle */
import React from 'react';
import moment from 'moment';
import './List.css';

export const List = ({ thoughts, setThoughts, handleLikeChange }) => {
return (
<div className="list">
<ul>
{thoughts.map((thought) => (
<div key={thought._id} className="box messages">
<p className="message-text">{thought.message}</p>
<div className="stats-container">
<div className="like-container">
<div className="heart">
<p onClick={() => handleLikeChange(thought._id)}>❤️</p>
</div>
<p>x{thought.hearts}</p>
</div>
<div className="time">
<p>{moment(thought.createdAt).fromNow()}</p>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I got posted "in a few seconds" when I posted a thought, so this way of handling the post time seems to have some vulnerabilities. Unless you made some sort of time machine, which is awesome, and in that case: carry on

</div>
</div>
</div>
))}
</ul>
</div>
);
};
Loading