From b1df3106462fd6fd7aa0ae6c6a49db9de64defa0 Mon Sep 17 00:00:00 2001 From: Matteo A Date: Mon, 12 Oct 2020 22:26:34 +0200 Subject: [PATCH 1/5] feat(post): add date on post --- client/src/Components/Screens/Home.js | 554 +++++++++++--------- client/src/Components/Screens/SinglePost.js | 356 +++++++------ client/src/Utils/date-util.js | 28 + 3 files changed, 514 insertions(+), 424 deletions(-) create mode 100644 client/src/Utils/date-util.js diff --git a/client/src/Components/Screens/Home.js b/client/src/Components/Screens/Home.js index 4e2afd2..28bb38d 100644 --- a/client/src/Components/Screens/Home.js +++ b/client/src/Components/Screens/Home.js @@ -1,275 +1,309 @@ -import React, { useState, useEffect, useContext } from 'react' -import '../../Styles/Home.css' -import { Link } from 'react-router-dom' -import Loading from './Loading' -import { UserContext } from '../../App' -import M from 'materialize-css' +import React, { useState, useEffect, useContext } from "react"; +import "../../Styles/Home.css"; +import { Link } from "react-router-dom"; +import Loading from "./Loading"; +import { UserContext } from "../../App"; +import M from "materialize-css"; +import { relativeDate } from "../../Utils/date-util.js"; function Home() { + const { state } = useContext(UserContext); + const [loading, setLoading] = useState(true); + const [miniLoading, setMiniLoading] = useState(false); + const [posts, setPosts] = useState([]); + useEffect(() => { + fetch("/allposts", { + headers: { + Authorization: "Bearer " + localStorage.getItem("jwt"), + }, + }) + .then((res) => res.json()) + .then((data) => { + setPosts(data.posts); + setLoading(false); + }) + .catch((err) => { + console.log(err); + setLoading(false); + }); + }, []); - const { state } = useContext(UserContext) - const [loading, setLoading] = useState(true) - const [miniLoading, setMiniLoading] = useState(false) - const [posts, setPosts] = useState([]) - useEffect(() => { - fetch('/allposts', { - headers: { - "Authorization": "Bearer " + localStorage.getItem("jwt") - } - }) - .then(res => res.json()) - .then(data => { - setPosts(data.posts) - setLoading(false) - }) - .catch(err => { - console.log(err) - setLoading(false) - }) - }, []) + const makeComment = (text, postId) => { + fetch("/comment", { + method: "put", + headers: { + "Content-Type": "application/json", + Authorization: "Bearer " + localStorage.getItem("jwt"), + }, + body: JSON.stringify({ + text, + postId, + }), + }) + .then((res) => res.json()) + .then((data) => { + const newData = posts.map((post) => { + if (post._id === data._id) { + return data; + } else { + return post; + } + }); + setPosts(newData); + }) + .catch((err) => { + console.log(err); + }); + }; - const makeComment = (text, postId) => { - fetch('/comment', { - method: "put", - headers: { - "Content-Type": "application/json", - "Authorization": "Bearer " + localStorage.getItem("jwt") - }, - body: JSON.stringify({ - text, - postId - }) - }).then(res => res.json()) - .then(data => { - const newData = posts.map(post => { - if (post._id === data._id) { - return data - } else { - return post - } - }) - setPosts(newData) - }) - .catch(err => { - console.log(err) - }) - } + const likePost = (id) => { + setMiniLoading(true); + fetch("/like", { + method: "put", + headers: { + "Content-Type": "application/json", + Authorization: "Bearer " + localStorage.getItem("jwt"), + }, + body: JSON.stringify({ + postId: id, + }), + }) + .then((res) => res.json()) + .then((data) => { + const newData = posts.map((post) => { + if (post._id === data._id) { + return data; + } else { + return post; + } + }); + setPosts(newData); + setMiniLoading(false); + }) + .catch((err) => { + setMiniLoading(false); + console.log(err); + }); + }; - const likePost = (id) => { - setMiniLoading(true) - fetch('/like', { - method: "put", - headers: { - "Content-Type": "application/json", - "Authorization": "Bearer " + localStorage.getItem("jwt") - }, - body: JSON.stringify({ - postId: id - }) - }).then(res => res.json()) - .then(data => { - const newData = posts.map(post => { - if (post._id === data._id) { - return data - } else { - return post - } - }) - setPosts(newData) - setMiniLoading(false) - }) - .catch(err => { - setMiniLoading(false) - console.log(err) - }) - } + const unlikePost = (id) => { + setMiniLoading(true); + fetch("/unlike", { + method: "put", + headers: { + "Content-Type": "application/json", + Authorization: "Bearer " + localStorage.getItem("jwt"), + }, + body: JSON.stringify({ + postId: id, + }), + }) + .then((res) => res.json()) + .then((data) => { + const newData = posts.map((post) => { + if (post._id === data._id) { + return data; + } else { + return post; + } + }); + setPosts(newData); + setMiniLoading(false); + }) + .catch((err) => { + setMiniLoading(false); + console.log(err); + }); + }; - const unlikePost = (id) => { - setMiniLoading(true) - fetch('/unlike', { - method: "put", - headers: { - "Content-Type": "application/json", - "Authorization": "Bearer " + localStorage.getItem("jwt") - }, - body: JSON.stringify({ - postId: id - }) - }).then(res => res.json()) - .then(data => { - const newData = posts.map(post => { - if (post._id === data._id) { - return data - } else { - return post - } - }) - setPosts(newData) - setMiniLoading(false) - }) - .catch(err => { - setMiniLoading(false) - console.log(err) - }) - } + const deletePost = (postId) => { + fetch(`/deletepost/${postId}`, { + method: "delete", + headers: { + Authorization: "Bearer " + localStorage.getItem("jwt"), + }, + }) + .then((res) => res.json()) + .then((result) => { + const newData = posts.filter((post) => { + return post._id !== result._id; + }); + setPosts(newData); + M.Toast.dismissAll(); + M.toast({ html: "Post deleted", classes: "#43a047 green darken-1" }); + }) + .catch((err) => console.log(err)); + }; - const deletePost = (postId) => { - fetch(`/deletepost/${postId}`, { - method: "delete", - headers: { - "Authorization": "Bearer " + localStorage.getItem("jwt") - } - }).then(res => res.json()) - .then(result => { - const newData = posts.filter(post => { - return post._id !== result._id - }) - setPosts(newData) - M.Toast.dismissAll() - M.toast({ html: "Post deleted", classes: "#43a047 green darken-1" }) - }) - .catch(err => console.log(err)) - } + const deleteComment = (postId, commentId) => { + fetch(`/deletecomment/${commentId}`, { + method: "put", + headers: { + "Content-Type": "application/json", + Authorization: "Bearer " + localStorage.getItem("jwt"), + }, + body: JSON.stringify({ + postId, + }), + }) + .then((res) => res.json()) + .then((data) => { + const newData = posts.map((post) => { + if (post._id === data._id) { + return data; + } else { + return post; + } + }); + setPosts(newData); + M.Toast.dismissAll(); + M.toast({ + html: "Comment deleted", + classes: "#43a047 green darken-1", + displayLength: 1800, + }); + }) + .catch((err) => { + console.log(err); + }); + }; - const deleteComment = (postId, commentId) => { - fetch(`/deletecomment/${commentId}`, { - method: "put", - headers: { - "Content-Type": "application/json", - "Authorization": "Bearer " + localStorage.getItem("jwt") - }, - body: JSON.stringify({ - postId - }) - }).then(res => res.json()) - .then(data => { - const newData = posts.map(post => { - if (post._id === data._id) { - return data - } else { - return post - } - }) - setPosts(newData) - M.Toast.dismissAll() - M.toast({ html: "Comment deleted", classes: "#43a047 green darken-1", displayLength: 1800 }) - }) - .catch(err => { - console.log(err) - }) - } + if (loading || !posts) { + return ; + } else { + return ( +
+
+ +
+ create + Create Post +
+ +
+ {posts.map((post, index) => { + let name = ""; + if (state._id === post.postedBy._id) { + name = "You"; + } else { + name = post.postedBy.name; + } + return ( +
+
+ none + + {" "} + {name} + + {post.postedBy._id === state._id && ( + + deletePost(post._id)} + > + delete_forever + + + )} +
+
+ post_img +
+
+
+ {miniLoading ? ( +
+ ) : ( +
+ {post.likes.includes(state._id) ? ( + unlikePost(post._id)} + className="unlike material-icons" + > + thumb_up + + ) : ( + likePost(post._id)} + className="like material-icons" + > + thumb_up + + )} +
+ )} - if (loading || !posts) { - return ( - - ) - } else { - return ( -
-
- -
- create - Create Post -
- + + {relativeDate(post.createdAt)} +
- { - posts.map((post, index) => { - let name = "" - if (state._id === post.postedBy._id) { - name = "You" - } else { - name = post.postedBy.name - } - return ( -
-
- none - {name} - { - post.postedBy._id === state._id - && - - deletePost(post._id)}>delete_forever - - } -
-
- post_img -
-
- { - miniLoading ? -
-
- : -
- { - post.likes.includes(state._id) ? - unlikePost(post._id)} className="unlike material-icons">thumb_up - : - likePost(post._id)} className="like material-icons">thumb_up - } -
- } -

{post.likes.length} likes

-

{post.body}

+

{post.likes.length} likes

+

{post.body}

-
-
Comments
-
- { - - post.comments.map((comment, index) => { - - return ( - <> -
{ - comment.postedBy._id === state._id ? - "You" - : - comment.postedBy.name - } : {comment.text} - { - comment.postedBy._id === state._id && - - deleteComment(post._id, comment._id)} className="unlike material-icons">delete - - } -
-
- - ) - }) - } -
-
- -
{ - e.preventDefault(); - makeComment(e.target[0].value, post._id) - e.target[0].value = "" - } - }> - -
-
-
- ) - }) - } +
+
Comments
+
+ {post.comments.map((comment, index) => { + return ( + <> +
+ + {comment.postedBy._id === state._id + ? "You" + : comment.postedBy.name} + {" "} + : {comment.text} + {comment.postedBy._id === state._id && ( + + + deleteComment(post._id, comment._id) + } + className="unlike material-icons" + > + delete + + + )} +
+
+ + ); + })} +
+
+
{ + e.preventDefault(); + makeComment(e.target[0].value, post._id); + e.target[0].value = ""; + }} + > + +
+
- ) - } + ); + })} +
+ ); + } } -export default Home +export default Home; diff --git a/client/src/Components/Screens/SinglePost.js b/client/src/Components/Screens/SinglePost.js index 9855784..32a5c6d 100644 --- a/client/src/Components/Screens/SinglePost.js +++ b/client/src/Components/Screens/SinglePost.js @@ -1,220 +1,248 @@ -import React, { useState, useEffect, useContext } from 'react' -import '../../Styles/SinglePost.css' -import Loading from './Loading' -import { useParams } from 'react-router-dom' -import '../../Styles/Home.css' -import { Link } from 'react-router-dom' -import { UserContext } from '../../App' -import M from 'materialize-css' - +import React, { useState, useEffect, useContext } from "react"; +import "../../Styles/SinglePost.css"; +import Loading from "./Loading"; +import { useParams } from "react-router-dom"; +import "../../Styles/Home.css"; +import { Link } from "react-router-dom"; +import { UserContext } from "../../App"; +import M from "materialize-css"; +import { relativeDate } from "../../Utils/date-util.js"; function SinglePost() { - - const { state } = useContext(UserContext) - const [miniLoading, setMiniLoading] = useState(false) - const [post, setPost] = useState(null) - const { id } = useParams() + const { state } = useContext(UserContext); + const [miniLoading, setMiniLoading] = useState(false); + const [post, setPost] = useState(null); + const { id } = useParams(); useEffect(() => { fetch(`/singlepost/${id}`, { headers: { - "Authorization": "Bearer " + localStorage.getItem("jwt") - } + Authorization: "Bearer " + localStorage.getItem("jwt"), + }, }) - .then(res => res.json()) - .then(result => { - setPost(result.post) - - }).catch(err => console.log(err)) - - }, []) - - + .then((res) => res.json()) + .then((result) => { + setPost(result.post); + }) + .catch((err) => console.log(err)); + }, []); const makeComment = (text, postId) => { - fetch('/comment', { + fetch("/comment", { method: "put", headers: { "Content-Type": "application/json", - "Authorization": "Bearer " + localStorage.getItem("jwt") + Authorization: "Bearer " + localStorage.getItem("jwt"), }, body: JSON.stringify({ text, - postId - }) - }).then(res => res.json()) - .then(data => { - setPost(data) - }) - .catch(err => { - console.log(err) + postId, + }), + }) + .then((res) => res.json()) + .then((data) => { + setPost(data); }) - } + .catch((err) => { + console.log(err); + }); + }; const likePost = (id) => { - setMiniLoading(true) - fetch('/like', { + setMiniLoading(true); + fetch("/like", { method: "put", headers: { "Content-Type": "application/json", - "Authorization": "Bearer " + localStorage.getItem("jwt") + Authorization: "Bearer " + localStorage.getItem("jwt"), }, body: JSON.stringify({ - postId: id - }) - }).then(res => res.json()) - .then(data => { - setPost(data) - setMiniLoading(false) - }) - .catch(err => { - setMiniLoading(false) - console.log(err) + postId: id, + }), + }) + .then((res) => res.json()) + .then((data) => { + setPost(data); + setMiniLoading(false); }) - } + .catch((err) => { + setMiniLoading(false); + console.log(err); + }); + }; const unlikePost = (id) => { - setMiniLoading(true) - fetch('/unlike', { + setMiniLoading(true); + fetch("/unlike", { method: "put", headers: { "Content-Type": "application/json", - "Authorization": "Bearer " + localStorage.getItem("jwt") + Authorization: "Bearer " + localStorage.getItem("jwt"), }, body: JSON.stringify({ - postId: id - }) - }).then(res => res.json()) - .then(data => { - setPost(data) - setMiniLoading(false) - }) - .catch(err => { - setMiniLoading(false) - console.log(err) + postId: id, + }), + }) + .then((res) => res.json()) + .then((data) => { + setPost(data); + setMiniLoading(false); }) - } + .catch((err) => { + setMiniLoading(false); + console.log(err); + }); + }; const deletePost = (postId) => { fetch(`/deletepost/${postId}`, { method: "delete", headers: { - "Authorization": "Bearer " + localStorage.getItem("jwt") - } - }).then(res => res.json()) - .then(result => { - setPost(result) - M.Toast.dismissAll() - M.toast({ html: "Post deleted", classes: "#43a047 green darken-1" }) + Authorization: "Bearer " + localStorage.getItem("jwt"), + }, + }) + .then((res) => res.json()) + .then((result) => { + setPost(result); + M.Toast.dismissAll(); + M.toast({ html: "Post deleted", classes: "#43a047 green darken-1" }); }) - .catch(err => console.log(err)) - } + .catch((err) => console.log(err)); + }; const deleteComment = (postId, commentId) => { fetch(`/deletecomment/${commentId}`, { method: "put", headers: { "Content-Type": "application/json", - "Authorization": "Bearer " + localStorage.getItem("jwt") + Authorization: "Bearer " + localStorage.getItem("jwt"), }, body: JSON.stringify({ - postId - }) - }).then(res => res.json()) - .then(data => { - setPost(data) - M.Toast.dismissAll() - M.toast({ html: "Comment deleted", classes: "#43a047 green darken-1", displayLength: 1800 }) - }) - .catch(err => { - console.log(err) + postId, + }), + }) + .then((res) => res.json()) + .then((data) => { + setPost(data); + M.Toast.dismissAll(); + M.toast({ + html: "Comment deleted", + classes: "#43a047 green darken-1", + displayLength: 1800, + }); }) - } - - return ( - post ? -
-
- none - {post.postedBy._id === state._id ? "You" : post.postedBy.name} - { - post.postedBy._id === state._id - && - - deletePost(post._id)}>delete_forever - - } -
-
- post_img -
-
- { - miniLoading ? -
-
- : -
- { - post.likes.includes(state._id) ? - unlikePost(post._id)} className="unlike material-icons">thumb_up - : - likePost(post._id)} className="like material-icons">thumb_up - } -
+ .catch((err) => { + console.log(err); + }); + }; + + return post ? ( +
+
+ none + {post.likes.length} likes

-

{post.body}

- -
-
Comments
-
- { + > + {" "} + + {post.postedBy._id === state._id ? "You" : post.postedBy.name} + + + {post.postedBy._id === state._id && ( + + deletePost(post._id)} + > + delete_forever + + + )} +
+
+ post_img +
+
+
+ {miniLoading ? ( +
+ ) : ( +
+ {post.likes.includes(state._id) ? ( + unlikePost(post._id)} + className="unlike material-icons" + > + thumb_up + + ) : ( + likePost(post._id)} + className="like material-icons" + > + thumb_up + + )} +
+ )} - post.comments.map((comment, index) => { + {relativeDate(post.createdAt)} +
- return ( - <> -
{ - comment.postedBy._id === state._id ? - "You" - : - comment.postedBy.name - } : {comment.text} - { - comment.postedBy._id === state._id && - - deleteComment(post._id, comment._id)} className="unlike material-icons">delete - - } -
-
- - ) - }) - } -
+

{post.likes.length} likes

+

{post.body}

+ +
+
Comments
+
+ {post.comments.map((comment, index) => { + return ( + <> +
+ + {comment.postedBy._id === state._id + ? "You" + : comment.postedBy.name} + {" "} + : {comment.text} + {comment.postedBy._id === state._id && ( + + deleteComment(post._id, comment._id)} + className="unlike material-icons" + > + delete + + + )} +
+
+ + ); + })}
+
-
{ + { e.preventDefault(); - makeComment(e.target[0].value, post._id) - e.target[0].value = "" - } - }> - -
-
+ makeComment(e.target[0].value, post._id); + e.target[0].value = ""; + }} + > + +
- : - ) +
+ ) : ( + + ); } -export default SinglePost +export default SinglePost; diff --git a/client/src/Utils/date-util.js b/client/src/Utils/date-util.js new file mode 100644 index 0000000..ebe3e1b --- /dev/null +++ b/client/src/Utils/date-util.js @@ -0,0 +1,28 @@ +export const relativeDate = (timestamp) => { + const NB_DAYS_YEAR = 365; // nb days on a year + const NB_HOURS_DAY = 24; // nb hours on a day + const NB_MINUTES_HOUR = 60; // nb minutes on a hour + const diffMs = Date.now() - new Date(timestamp).getTime(); + + const diffMinutes = Math.floor(diffMs / 60000); + const diffHours = Math.floor(diffMinutes / NB_MINUTES_HOUR); + const diffDays = Math.floor(diffHours / NB_HOURS_DAY); + const diffYears = Math.floor(diffDays / NB_DAYS_YEAR); + + if (diffMinutes <= 2) return "Posted a few minutes ago"; + + if (diffMinutes < NB_MINUTES_HOUR) return `Posted ${diffMinutes} minutes ago`; + + if (diffHours < NB_HOURS_DAY) { + const hourLabel = diffHours === 1 ? "hour" : "hours"; + return `Posted ${diffHours} ${hourLabel} ago`; + } + + if (diffDays < NB_DAYS_YEAR) { + const dayLabel = diffDays === 1 ? "day" : "days"; + return `Posted ${diffDays} ${dayLabel} ago`; + } + + const yearLabel = diffYears === 1 ? "year" : "years"; + return `Posted ${diffYears} ${yearLabel} ago`; +}; From 9d310e688f382a5f5e4941fec7021f1e081e8f6e Mon Sep 17 00:00:00 2001 From: Matteo A Date: Mon, 12 Oct 2020 22:26:49 +0200 Subject: [PATCH 2/5] style(post): add date style --- client/src/Styles/Home.css | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/client/src/Styles/Home.css b/client/src/Styles/Home.css index 3d467f6..a71d3b3 100644 --- a/client/src/Styles/Home.css +++ b/client/src/Styles/Home.css @@ -226,4 +226,19 @@ color: var(--sec-text) !important; font-size: 18px; color: var(--primary-text); font-weight: 600; -} \ No newline at end of file +} + +.card +> .card-content +> .post-info-stripe { + display: flex; + justify-content: space-between; +} + +.card +> .card-content +> .post-info-stripe +> .post-date { + color: var(--sec-text); + font-style: italic; +} From 0c69be7ae14c758c5ba24a5feb2dd3e060df9663 Mon Sep 17 00:00:00 2001 From: Matteo A Date: Mon, 12 Oct 2020 22:30:51 +0200 Subject: [PATCH 3/5] fix(post): fix recent post condition --- client/src/Utils/date-util.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/Utils/date-util.js b/client/src/Utils/date-util.js index ebe3e1b..ea43ee6 100644 --- a/client/src/Utils/date-util.js +++ b/client/src/Utils/date-util.js @@ -9,7 +9,7 @@ export const relativeDate = (timestamp) => { const diffDays = Math.floor(diffHours / NB_HOURS_DAY); const diffYears = Math.floor(diffDays / NB_DAYS_YEAR); - if (diffMinutes <= 2) return "Posted a few minutes ago"; + if (diffMinutes < 2) return "Posted a few minutes ago"; if (diffMinutes < NB_MINUTES_HOUR) return `Posted ${diffMinutes} minutes ago`; From 5f017bb5af862e327250349fa484b66b335085b3 Mon Sep 17 00:00:00 2001 From: Matteo A Date: Mon, 12 Oct 2020 22:48:24 +0200 Subject: [PATCH 4/5] fix: restore original code format --- client/src/Components/Screens/Home.js | 559 ++++++++++---------- client/src/Components/Screens/SinglePost.js | 359 ++++++------- 2 files changed, 433 insertions(+), 485 deletions(-) diff --git a/client/src/Components/Screens/Home.js b/client/src/Components/Screens/Home.js index 28bb38d..59f6232 100644 --- a/client/src/Components/Screens/Home.js +++ b/client/src/Components/Screens/Home.js @@ -1,309 +1,280 @@ -import React, { useState, useEffect, useContext } from "react"; -import "../../Styles/Home.css"; -import { Link } from "react-router-dom"; -import Loading from "./Loading"; -import { UserContext } from "../../App"; -import M from "materialize-css"; -import { relativeDate } from "../../Utils/date-util.js"; +import React, { useState, useEffect, useContext } from 'react' +import '../../Styles/Home.css' +import { Link } from 'react-router-dom' +import Loading from './Loading' +import { UserContext } from '../../App' +import M from 'materialize-css' +import { relativeDate } from '../../Utils/date-util.js'; function Home() { - const { state } = useContext(UserContext); - const [loading, setLoading] = useState(true); - const [miniLoading, setMiniLoading] = useState(false); - const [posts, setPosts] = useState([]); - useEffect(() => { - fetch("/allposts", { - headers: { - Authorization: "Bearer " + localStorage.getItem("jwt"), - }, - }) - .then((res) => res.json()) - .then((data) => { - setPosts(data.posts); - setLoading(false); - }) - .catch((err) => { - console.log(err); - setLoading(false); - }); - }, []); - const makeComment = (text, postId) => { - fetch("/comment", { - method: "put", - headers: { - "Content-Type": "application/json", - Authorization: "Bearer " + localStorage.getItem("jwt"), - }, - body: JSON.stringify({ - text, - postId, - }), - }) - .then((res) => res.json()) - .then((data) => { - const newData = posts.map((post) => { - if (post._id === data._id) { - return data; - } else { - return post; - } - }); - setPosts(newData); - }) - .catch((err) => { - console.log(err); - }); - }; + const { state } = useContext(UserContext) + const [loading, setLoading] = useState(true) + const [miniLoading, setMiniLoading] = useState(false) + const [posts, setPosts] = useState([]) + useEffect(() => { + fetch('/allposts', { + headers: { + "Authorization": "Bearer " + localStorage.getItem("jwt") + } + }) + .then(res => res.json()) + .then(data => { + setPosts(data.posts) + setLoading(false) + }) + .catch(err => { + console.log(err) + setLoading(false) + }) + }, []) - const likePost = (id) => { - setMiniLoading(true); - fetch("/like", { - method: "put", - headers: { - "Content-Type": "application/json", - Authorization: "Bearer " + localStorage.getItem("jwt"), - }, - body: JSON.stringify({ - postId: id, - }), - }) - .then((res) => res.json()) - .then((data) => { - const newData = posts.map((post) => { - if (post._id === data._id) { - return data; - } else { - return post; - } - }); - setPosts(newData); - setMiniLoading(false); - }) - .catch((err) => { - setMiniLoading(false); - console.log(err); - }); - }; + const makeComment = (text, postId) => { + fetch('/comment', { + method: "put", + headers: { + "Content-Type": "application/json", + "Authorization": "Bearer " + localStorage.getItem("jwt") + }, + body: JSON.stringify({ + text, + postId + }) + }).then(res => res.json()) + .then(data => { + const newData = posts.map(post => { + if (post._id === data._id) { + return data + } else { + return post + } + }) + setPosts(newData) + }) + .catch(err => { + console.log(err) + }) + } - const unlikePost = (id) => { - setMiniLoading(true); - fetch("/unlike", { - method: "put", - headers: { - "Content-Type": "application/json", - Authorization: "Bearer " + localStorage.getItem("jwt"), - }, - body: JSON.stringify({ - postId: id, - }), - }) - .then((res) => res.json()) - .then((data) => { - const newData = posts.map((post) => { - if (post._id === data._id) { - return data; - } else { - return post; - } - }); - setPosts(newData); - setMiniLoading(false); - }) - .catch((err) => { - setMiniLoading(false); - console.log(err); - }); - }; + const likePost = (id) => { + setMiniLoading(true) + fetch('/like', { + method: "put", + headers: { + "Content-Type": "application/json", + "Authorization": "Bearer " + localStorage.getItem("jwt") + }, + body: JSON.stringify({ + postId: id + }) + }).then(res => res.json()) + .then(data => { + const newData = posts.map(post => { + if (post._id === data._id) { + return data + } else { + return post + } + }) + setPosts(newData) + setMiniLoading(false) + }) + .catch(err => { + setMiniLoading(false) + console.log(err) + }) + } - const deletePost = (postId) => { - fetch(`/deletepost/${postId}`, { - method: "delete", - headers: { - Authorization: "Bearer " + localStorage.getItem("jwt"), - }, - }) - .then((res) => res.json()) - .then((result) => { - const newData = posts.filter((post) => { - return post._id !== result._id; - }); - setPosts(newData); - M.Toast.dismissAll(); - M.toast({ html: "Post deleted", classes: "#43a047 green darken-1" }); - }) - .catch((err) => console.log(err)); - }; + const unlikePost = (id) => { + setMiniLoading(true) + fetch('/unlike', { + method: "put", + headers: { + "Content-Type": "application/json", + "Authorization": "Bearer " + localStorage.getItem("jwt") + }, + body: JSON.stringify({ + postId: id + }) + }).then(res => res.json()) + .then(data => { + const newData = posts.map(post => { + if (post._id === data._id) { + return data + } else { + return post + } + }) + setPosts(newData) + setMiniLoading(false) + }) + .catch(err => { + setMiniLoading(false) + console.log(err) + }) + } - const deleteComment = (postId, commentId) => { - fetch(`/deletecomment/${commentId}`, { - method: "put", - headers: { - "Content-Type": "application/json", - Authorization: "Bearer " + localStorage.getItem("jwt"), - }, - body: JSON.stringify({ - postId, - }), - }) - .then((res) => res.json()) - .then((data) => { - const newData = posts.map((post) => { - if (post._id === data._id) { - return data; - } else { - return post; - } - }); - setPosts(newData); - M.Toast.dismissAll(); - M.toast({ - html: "Comment deleted", - classes: "#43a047 green darken-1", - displayLength: 1800, - }); - }) - .catch((err) => { - console.log(err); - }); - }; + const deletePost = (postId) => { + fetch(`/deletepost/${postId}`, { + method: "delete", + headers: { + "Authorization": "Bearer " + localStorage.getItem("jwt") + } + }).then(res => res.json()) + .then(result => { + const newData = posts.filter(post => { + return post._id !== result._id + }) + setPosts(newData) + M.Toast.dismissAll() + M.toast({ html: "Post deleted", classes: "#43a047 green darken-1" }) + }) + .catch(err => console.log(err)) + } - if (loading || !posts) { - return ; - } else { - return ( -
-
- -
- create - Create Post -
- -
- {posts.map((post, index) => { - let name = ""; - if (state._id === post.postedBy._id) { - name = "You"; - } else { - name = post.postedBy.name; - } - return ( -
-
- none - - {" "} - {name} - - {post.postedBy._id === state._id && ( - - deletePost(post._id)} - > - delete_forever - - - )} -
-
- post_img -
-
-
- {miniLoading ? ( -
- ) : ( -
- {post.likes.includes(state._id) ? ( - unlikePost(post._id)} - className="unlike material-icons" - > - thumb_up - - ) : ( - likePost(post._id)} - className="like material-icons" - > - thumb_up - - )} -
- )} + const deleteComment = (postId, commentId) => { + fetch(`/deletecomment/${commentId}`, { + method: "put", + headers: { + "Content-Type": "application/json", + "Authorization": "Bearer " + localStorage.getItem("jwt") + }, + body: JSON.stringify({ + postId + }) + }).then(res => res.json()) + .then(data => { + const newData = posts.map(post => { + if (post._id === data._id) { + return data + } else { + return post + } + }) + setPosts(newData) + M.Toast.dismissAll() + M.toast({ html: "Comment deleted", classes: "#43a047 green darken-1", displayLength: 1800 }) + }) + .catch(err => { + console.log(err) + }) + } - - {relativeDate(post.createdAt)} - + if (loading || !posts) { + return ( + + ) + } else { + return ( +
+
+ +
+ create + Create Post +
+
+ { + posts.map((post, index) => { -

{post.likes.length} likes

-

{post.body}

+ let name = "" + if (state._id === post.postedBy._id) { + name = "You" + } else { + name = post.postedBy.name + } + return ( +
+
+ none + {name} + { + post.postedBy._id === state._id + && + + deletePost(post._id)}>delete_forever + + } +
+
+ post_img +
+
+ + +

{post.likes.length} likes

+

{post.body}

-
-
Comments
-
- {post.comments.map((comment, index) => { - return ( - <> -
- - {comment.postedBy._id === state._id - ? "You" - : comment.postedBy.name} - {" "} - : {comment.text} - {comment.postedBy._id === state._id && ( - - - deleteComment(post._id, comment._id) - } - className="unlike material-icons" - > - delete - - - )} -
-
- - ); - })} -
-
+
+
Comments
+
+ { + + post.comments.map((comment, index) => { + + return ( + <> +
{ + comment.postedBy._id === state._id ? + "You" + : + comment.postedBy.name + } : {comment.text} + { + comment.postedBy._id === state._id && + + deleteComment(post._id, comment._id)} className="unlike material-icons">delete + + } +
+
+ + ) + }) + } +
+
+ +
{ + e.preventDefault(); + makeComment(e.target[0].value, post._id) + e.target[0].value = "" + } + }> + +
+
+
+ ) + }) + } -
{ - e.preventDefault(); - makeComment(e.target[0].value, post._id); - e.target[0].value = ""; - }} - > - -
-
- ); - })} -
- ); - } + ) + } } -export default Home; +export default Home \ No newline at end of file diff --git a/client/src/Components/Screens/SinglePost.js b/client/src/Components/Screens/SinglePost.js index 32a5c6d..bed9810 100644 --- a/client/src/Components/Screens/SinglePost.js +++ b/client/src/Components/Screens/SinglePost.js @@ -1,248 +1,225 @@ -import React, { useState, useEffect, useContext } from "react"; -import "../../Styles/SinglePost.css"; -import Loading from "./Loading"; -import { useParams } from "react-router-dom"; -import "../../Styles/Home.css"; -import { Link } from "react-router-dom"; -import { UserContext } from "../../App"; -import M from "materialize-css"; -import { relativeDate } from "../../Utils/date-util.js"; +import React, { useState, useEffect, useContext } from 'react' +import '../../Styles/SinglePost.css' +import Loading from './Loading' +import { useParams } from 'react-router-dom' +import '../../Styles/Home.css' +import { Link } from 'react-router-dom' +import { UserContext } from '../../App' +import M from 'materialize-css' +import { relativeDate } from '../../Utils/date-util.js'; + function SinglePost() { - const { state } = useContext(UserContext); - const [miniLoading, setMiniLoading] = useState(false); - const [post, setPost] = useState(null); - const { id } = useParams(); + + const { state } = useContext(UserContext) + const [miniLoading, setMiniLoading] = useState(false) + const [post, setPost] = useState(null) + const { id } = useParams() useEffect(() => { fetch(`/singlepost/${id}`, { headers: { - Authorization: "Bearer " + localStorage.getItem("jwt"), - }, + "Authorization": "Bearer " + localStorage.getItem("jwt") + } }) - .then((res) => res.json()) - .then((result) => { - setPost(result.post); - }) - .catch((err) => console.log(err)); - }, []); + .then(res => res.json()) + .then(result => { + setPost(result.post) + + }).catch(err => console.log(err)) + + }, []) + + const makeComment = (text, postId) => { - fetch("/comment", { + fetch('/comment', { method: "put", headers: { "Content-Type": "application/json", - Authorization: "Bearer " + localStorage.getItem("jwt"), + "Authorization": "Bearer " + localStorage.getItem("jwt") }, body: JSON.stringify({ text, - postId, - }), - }) - .then((res) => res.json()) - .then((data) => { - setPost(data); + postId + }) + }).then(res => res.json()) + .then(data => { + setPost(data) }) - .catch((err) => { - console.log(err); - }); - }; + .catch(err => { + console.log(err) + }) + } const likePost = (id) => { - setMiniLoading(true); - fetch("/like", { + setMiniLoading(true) + fetch('/like', { method: "put", headers: { "Content-Type": "application/json", - Authorization: "Bearer " + localStorage.getItem("jwt"), + "Authorization": "Bearer " + localStorage.getItem("jwt") }, body: JSON.stringify({ - postId: id, - }), - }) - .then((res) => res.json()) - .then((data) => { - setPost(data); - setMiniLoading(false); + postId: id }) - .catch((err) => { - setMiniLoading(false); - console.log(err); - }); - }; + }).then(res => res.json()) + .then(data => { + setPost(data) + setMiniLoading(false) + }) + .catch(err => { + setMiniLoading(false) + console.log(err) + }) + } const unlikePost = (id) => { - setMiniLoading(true); - fetch("/unlike", { + setMiniLoading(true) + fetch('/unlike', { method: "put", headers: { "Content-Type": "application/json", - Authorization: "Bearer " + localStorage.getItem("jwt"), + "Authorization": "Bearer " + localStorage.getItem("jwt") }, body: JSON.stringify({ - postId: id, - }), - }) - .then((res) => res.json()) - .then((data) => { - setPost(data); - setMiniLoading(false); + postId: id + }) + }).then(res => res.json()) + .then(data => { + setPost(data) + setMiniLoading(false) }) - .catch((err) => { - setMiniLoading(false); - console.log(err); - }); - }; + .catch(err => { + setMiniLoading(false) + console.log(err) + }) + } const deletePost = (postId) => { fetch(`/deletepost/${postId}`, { method: "delete", headers: { - Authorization: "Bearer " + localStorage.getItem("jwt"), - }, - }) - .then((res) => res.json()) - .then((result) => { - setPost(result); - M.Toast.dismissAll(); - M.toast({ html: "Post deleted", classes: "#43a047 green darken-1" }); + "Authorization": "Bearer " + localStorage.getItem("jwt") + } + }).then(res => res.json()) + .then(result => { + setPost(result) + M.Toast.dismissAll() + M.toast({ html: "Post deleted", classes: "#43a047 green darken-1" }) }) - .catch((err) => console.log(err)); - }; + .catch(err => console.log(err)) + } const deleteComment = (postId, commentId) => { fetch(`/deletecomment/${commentId}`, { method: "put", headers: { "Content-Type": "application/json", - Authorization: "Bearer " + localStorage.getItem("jwt"), + "Authorization": "Bearer " + localStorage.getItem("jwt") }, body: JSON.stringify({ - postId, - }), - }) - .then((res) => res.json()) - .then((data) => { - setPost(data); - M.Toast.dismissAll(); - M.toast({ - html: "Comment deleted", - classes: "#43a047 green darken-1", - displayLength: 1800, - }); + postId }) - .catch((err) => { - console.log(err); - }); - }; - - return post ? ( -
-
- none - res.json()) + .then(data => { + setPost(data) + M.Toast.dismissAll() + M.toast({ html: "Comment deleted", classes: "#43a047 green darken-1", displayLength: 1800 }) + }) + .catch(err => { + console.log(err) + }) + } + + return ( + post ? +
+
+ none + - {" "} - - {post.postedBy._id === state._id ? "You" : post.postedBy.name} - - - {post.postedBy._id === state._id && ( - - deletePost(post._id)} - > - delete_forever - - - )} -
-
- post_img -
-
-
- {miniLoading ? ( -
- ) : ( -
- {post.likes.includes(state._id) ? ( - unlikePost(post._id)} - className="unlike material-icons" - > - thumb_up - - ) : ( - likePost(post._id)} - className="like material-icons" - > - thumb_up - - )} + > {post.postedBy._id === state._id ? "You" : post.postedBy.name} + { + post.postedBy._id === state._id + && + + deletePost(post._id)}>delete_forever + + } +
+
+ post_img +
+
+ - )} + +

{post.likes.length} likes

+

{post.body}

- {relativeDate(post.createdAt)} -
+
+
Comments
+
+ { + + post.comments.map((comment, index) => { -

{post.likes.length} likes

-

{post.body}

- -
-
Comments
-
- {post.comments.map((comment, index) => { - return ( - <> -
- - {comment.postedBy._id === state._id - ? "You" - : comment.postedBy.name} - {" "} - : {comment.text} - {comment.postedBy._id === state._id && ( - - deleteComment(post._id, comment._id)} - className="unlike material-icons" - > - delete - - - )} -
-
- - ); - })} + return ( + <> +
{ + comment.postedBy._id === state._id ? + "You" + : + comment.postedBy.name + } : {comment.text} + { + comment.postedBy._id === state._id && + + deleteComment(post._id, comment._id)} className="unlike material-icons">delete + + } +
+
+ + ) + }) + } +
-
-
{ + { e.preventDefault(); - makeComment(e.target[0].value, post._id); - e.target[0].value = ""; - }} - > - -
+ makeComment(e.target[0].value, post._id) + e.target[0].value = "" + } + }> + + +
-
- ) : ( - - ); + : + ) } -export default SinglePost; +export default SinglePost \ No newline at end of file From 3fce2b7fc187f4e626c196ac9a30ab92b253ac69 Mon Sep 17 00:00:00 2001 From: Matteo A Date: Mon, 12 Oct 2020 23:22:32 +0200 Subject: [PATCH 5/5] fix(post): fix post date timezone management --- client/src/Utils/date-util.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/src/Utils/date-util.js b/client/src/Utils/date-util.js index ea43ee6..2739578 100644 --- a/client/src/Utils/date-util.js +++ b/client/src/Utils/date-util.js @@ -2,7 +2,10 @@ export const relativeDate = (timestamp) => { const NB_DAYS_YEAR = 365; // nb days on a year const NB_HOURS_DAY = 24; // nb hours on a day const NB_MINUTES_HOUR = 60; // nb minutes on a hour - const diffMs = Date.now() - new Date(timestamp).getTime(); + const now = new Date(); + const utcNow = new Date(now.toUTCString()); + const utcDate = new Date(new Date(timestamp).toUTCString()) + const diffMs = utcNow.getTime() - utcDate.getTime() const diffMinutes = Math.floor(diffMs / 60000); const diffHours = Math.floor(diffMinutes / NB_MINUTES_HOUR);