From fc05dd1a64fb933a5c97338b6ac13390dbaa64d8 Mon Sep 17 00:00:00 2001 From: "Kartikey S. Chauhan" Date: Sun, 2 Jun 2024 20:58:06 +0530 Subject: [PATCH 1/8] feat: add option to delete posts from web UI --- components/post.js | 29 +++++++++++++++++++++++++++++ components/posts.js | 1 + pages/api/web/post/delete.js | 25 +++++++++++++++++++++++++ public/posts.css | 25 +++++++++++++++++++++++++ 4 files changed, 80 insertions(+) create mode 100644 pages/api/web/post/delete.js diff --git a/components/post.js b/components/post.js index 3b93d4ff..c2b95494 100644 --- a/components/post.js +++ b/components/post.js @@ -7,6 +7,7 @@ import Content from './content' import Video from './video' import Image from 'next/image' import Reaction from './reaction' +import { useState } from 'react' import EmojiPicker from 'emoji-picker-react' const imageFileTypes = ['jpg', 'jpeg', 'png', 'gif', 'webp'] @@ -28,6 +29,7 @@ const Post = ({ profile = false, user = { username: 'abc', + id: 'abc', avatar: '', displayStreak: false, streakCount: 0 @@ -44,6 +46,30 @@ const Post = ({ swrKey, authSession }) => { + const [isVisible, setIsVisible] = useState(true); + + const deletePost = async (id) => { + try { + const response = await fetch('/api/web/post/delete', { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ id }) + }); + const responseText = await response.text() + if (responseText.includes("Post Deleted")){ + setIsVisible(false); + } + } catch (error) { + console.error('Error:', error); + } + }; + + if (!isVisible) { + return null; + } + return ( <>
)}
+
{reactions.map(reaction => ( )} +
+ deletePost(id)} />
diff --git a/components/posts.js b/components/posts.js index a0d98e02..5265c75a 100644 --- a/components/posts.js +++ b/components/posts.js @@ -70,6 +70,7 @@ const Posts = ({ posts = [], swrKey = null }) => { {posts.map(post => ( { + const session = await getServerSession(req, res, authOptions); + + if (!session?.user) { + console.log('Unauthorized access attempt'); + return res.status(401).send({message: "Unauthorized"}); + } + + try { + const update = await prisma.updates.delete({ + where: { id: req.body.id }, + }); + + console.log('API Response:', update); + + return res.status(200).send({message: "Post Deleted"}); + } catch (e) { + console.error('Error deleting post:', e); + return res.status(500).json({ error: true, message: 'Internal Server Error' }); + } +}; diff --git a/public/posts.css b/public/posts.css index dedca7a4..2bf64dc2 100644 --- a/public/posts.css +++ b/public/posts.css @@ -24,6 +24,7 @@ text-decoration: none; display: flex; align-items: center; + justify-content: space-between; margin-bottom: 8px; line-height: 1; } @@ -40,6 +41,7 @@ .post-header-container { padding-left: 8px; + flex-grow: 1; } .post-header-name { @@ -122,6 +124,7 @@ a.post-text-mention { align-items: center; margin-top: 16px; } + .post-attachment { border-radius: 6px; overflow: hidden; @@ -160,6 +163,7 @@ a.post-attachment:first-child:last-child { flex-wrap: wrap; margin-top: 16px; margin-bottom: -12px; + justify-content: space-between; } .post-reaction { @@ -198,3 +202,24 @@ a.post-attachment:first-child:last-child { width: 24px; height: 24px; } + +.delete-button { + color: var(--colors-background); + background-color: #ec3750; + border-color: black; +} + +.delete-button:hover { + transform: scale(1.2); + color: var(--colors-background); + animation: wiggle 0.5s ease-in-out infinite; +} + +@keyframes wiggle { + 0%, 100% { + transform: rotate(-5deg) scale(1.2); + } + 50% { + transform: rotate(5deg) scale(1.2); + } +} From 99a53515c4555ae6d2ad5153e3e560acbfd6ff78 Mon Sep 17 00:00:00 2001 From: "Kartikey S. Chauhan" Date: Mon, 3 Jun 2024 15:48:55 +0530 Subject: [PATCH 2/8] fix: button only appears if authenticated user is the owner of the post --- components/post.js | 85 ++++++++++++++++++++++++------------ pages/api/web/session/get.js | 31 +++++++++++++ 2 files changed, 88 insertions(+), 28 deletions(-) create mode 100644 pages/api/web/session/get.js diff --git a/components/post.js b/components/post.js index c2b95494..724ff69e 100644 --- a/components/post.js +++ b/components/post.js @@ -7,7 +7,7 @@ import Content from './content' import Video from './video' import Image from 'next/image' import Reaction from './reaction' -import { useState } from 'react' +import { useState, useEffect } from 'react' import EmojiPicker from 'emoji-picker-react' const imageFileTypes = ['jpg', 'jpeg', 'png', 'gif', 'webp'] @@ -34,6 +34,7 @@ const Post = ({ displayStreak: false, streakCount: 0 }, + sessionID = 'abc', text, attachments = [], mux = [], @@ -41,13 +42,25 @@ const Post = ({ postedAt, slackUrl, muted = false, - openEmojiPicker = () => {}, + openEmojiPicker = () => { }, authStatus, swrKey, authSession }) => { const [isVisible, setIsVisible] = useState(true); - + const [sessionUserId, setSessionUserId] = useState(null); + + useEffect(() => { + if (authStatus === 'authenticated') { + const fetchSessionUserID = async () => { + const id = await getSessionUserID(user.id); + setSessionUserId(id); + }; + fetchSessionUserID(); + } +}, [user.id, authStatus]); + + const deletePost = async (id) => { try { const response = await fetch('/api/web/post/delete', { @@ -55,10 +68,10 @@ const Post = ({ headers: { 'Content-Type': 'application/json', }, - body: JSON.stringify({ id }) + body: JSON.stringify({ id }) }); const responseText = await response.text() - if (responseText.includes("Post Deleted")){ + if (responseText.includes("Post Deleted")) { setIsVisible(false); } } catch (error) { @@ -67,7 +80,7 @@ const Post = ({ }; if (!isVisible) { - return null; + return null; } return ( @@ -106,11 +119,10 @@ const Post = ({ @{user.username} {`${user.streakCount <= 7 ? user.streakCount : '7+'}`} @@ -180,24 +192,24 @@ const Post = ({ )}
-
- {reactions.map(reaction => ( - - ))} - {authStatus == 'authenticated' && ( -
openEmojiPicker(id)}> - + -
- )} +
+ {reactions.map(reaction => ( + + ))} + {authStatus == 'authenticated' && ( +
openEmojiPicker(id)}> + + +
+ )}
- deletePost(id)} /> + {( authStatus == 'authenticated' && sessionUserId === user.id) && deletePost(id)} />}
@@ -205,3 +217,20 @@ const Post = ({ } export default Post + +const getSessionUserID = async (id) => { + try { + const response = await fetch('/api/web/session/get', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ id }) + }); + + const responseText = JSON.parse(await response.text()); + return responseText.message; + } catch (error) { + console.error('Error:', error); + } +} \ No newline at end of file diff --git a/pages/api/web/session/get.js b/pages/api/web/session/get.js new file mode 100644 index 00000000..0b20b052 --- /dev/null +++ b/pages/api/web/session/get.js @@ -0,0 +1,31 @@ +import { getServerSession } from 'next-auth/next'; +import { authOptions } from '../../auth/[...nextauth]'; +import prisma from '../../../../lib/prisma'; + +export default async (req, res) => { + const session = await getServerSession(req, res, authOptions); + + if (!session?.user) { + console.log('Unauthorized access attempt'); + return res.status(401).send({ message: "Unauthorized" }); + } + + try { + const update = await prisma.session.findFirst({ + where: { + userId: req.body.id + }, + orderBy: { + expires: 'desc' + } + }); + if (update) { + const userId = update.userId; + return res.status(200).send({ message: userId }); + } + return res.status(200).send({ message: false }); + } catch (e) { + console.error('Error deleting post:', e); + return res.status(500).json({ error: true, message: 'Internal Server Error' }); + } +}; From 882b15e9ebb4187a4a73eeeb517c1a781565d46b Mon Sep 17 00:00:00 2001 From: "Kartikey S. Chauhan" Date: Mon, 3 Jun 2024 20:22:07 +0530 Subject: [PATCH 3/8] Resolve comments --- components/post.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/post.js b/components/post.js index 724ff69e..6e5546c0 100644 --- a/components/post.js +++ b/components/post.js @@ -228,7 +228,7 @@ const getSessionUserID = async (id) => { body: JSON.stringify({ id }) }); - const responseText = JSON.parse(await response.text()); + const responseText = await response.json(); return responseText.message; } catch (error) { console.error('Error:', error); From 9b5e057b9ee8f38672821de3d8c92134cf64dbbd Mon Sep 17 00:00:00 2001 From: "Kartikey S. Chauhan" Date: Thu, 13 Jun 2024 08:02:32 +0530 Subject: [PATCH 4/8] Adds toast! --- components/post.js | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/components/post.js b/components/post.js index 6e5546c0..380b63a4 100644 --- a/components/post.js +++ b/components/post.js @@ -8,6 +8,7 @@ import Video from './video' import Image from 'next/image' import Reaction from './reaction' import { useState, useEffect } from 'react' +import toast from 'react-hot-toast' import EmojiPicker from 'emoji-picker-react' const imageFileTypes = ['jpg', 'jpeg', 'png', 'gif', 'webp'] @@ -62,21 +63,24 @@ const Post = ({ const deletePost = async (id) => { - try { - const response = await fetch('/api/web/post/delete', { + toast.promise( + fetch('/api/web/post/delete', { method: 'DELETE', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ id }) - }); - const responseText = await response.text() - if (responseText.includes("Post Deleted")) { - setIsVisible(false); + }).then(response => response.text()).then(responseText => { + if (responseText.includes("Post Deleted")) { + setIsVisible(false); + } + }), + { + loading: 'Deleting post...', + success: 'Post Deleted Successfully!', + error: 'Error deleting post.', } - } catch (error) { - console.error('Error:', error); - } + ); }; if (!isVisible) { From e0eed1658f2e8e49e045df02c8248ceeaaa94e6e Mon Sep 17 00:00:00 2001 From: JosiasAurel Date: Sat, 31 Aug 2024 05:53:14 +0100 Subject: [PATCH 5/8] use auth session passed down from parent component into post --- components/post.js | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/components/post.js b/components/post.js index 380b63a4..33db1046 100644 --- a/components/post.js +++ b/components/post.js @@ -1,5 +1,4 @@ import { convertTimestampToDate } from '../lib/dates' -import { proxy } from '../lib/images' import { filter } from 'lodash' import Icon from '@hackclub/icons' import Link from 'next/link' @@ -9,7 +8,6 @@ import Image from 'next/image' import Reaction from './reaction' import { useState, useEffect } from 'react' import toast from 'react-hot-toast' -import EmojiPicker from 'emoji-picker-react' const imageFileTypes = ['jpg', 'jpeg', 'png', 'gif', 'webp'] @@ -49,18 +47,6 @@ const Post = ({ authSession }) => { const [isVisible, setIsVisible] = useState(true); - const [sessionUserId, setSessionUserId] = useState(null); - - useEffect(() => { - if (authStatus === 'authenticated') { - const fetchSessionUserID = async () => { - const id = await getSessionUserID(user.id); - setSessionUserId(id); - }; - fetchSessionUserID(); - } -}, [user.id, authStatus]); - const deletePost = async (id) => { toast.promise( @@ -213,7 +199,7 @@ const Post = ({ )} - {( authStatus == 'authenticated' && sessionUserId === user.id) && deletePost(id)} />} + {( authStatus == 'authenticated' && authSession.user.id === user.id) && deletePost(id)} />} From 5e17482fb6c8ef9c9f4d91e17acb19be589bebc2 Mon Sep 17 00:00:00 2001 From: JosiasAurel Date: Sat, 31 Aug 2024 05:53:41 +0100 Subject: [PATCH 6/8] remove userID prop --- components/posts.js | 1 - 1 file changed, 1 deletion(-) diff --git a/components/posts.js b/components/posts.js index 5265c75a..a0d98e02 100644 --- a/components/posts.js +++ b/components/posts.js @@ -70,7 +70,6 @@ const Posts = ({ posts = [], swrKey = null }) => { {posts.map(post => ( Date: Sat, 31 Aug 2024 05:59:11 +0100 Subject: [PATCH 7/8] remove func to get session user id --- components/post.js | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/components/post.js b/components/post.js index 33db1046..16191734 100644 --- a/components/post.js +++ b/components/post.js @@ -206,21 +206,4 @@ const Post = ({ ) } -export default Post - -const getSessionUserID = async (id) => { - try { - const response = await fetch('/api/web/session/get', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ id }) - }); - - const responseText = await response.json(); - return responseText.message; - } catch (error) { - console.error('Error:', error); - } -} \ No newline at end of file +export default Post \ No newline at end of file From 7e23d597d1b901dde724add87bcece45d7f6ffb6 Mon Sep 17 00:00:00 2001 From: JosiasAurel Date: Sat, 31 Aug 2024 05:59:58 +0100 Subject: [PATCH 8/8] remove get.js --- pages/api/web/session/get.js | 31 ------------------------------- 1 file changed, 31 deletions(-) delete mode 100644 pages/api/web/session/get.js diff --git a/pages/api/web/session/get.js b/pages/api/web/session/get.js deleted file mode 100644 index 0b20b052..00000000 --- a/pages/api/web/session/get.js +++ /dev/null @@ -1,31 +0,0 @@ -import { getServerSession } from 'next-auth/next'; -import { authOptions } from '../../auth/[...nextauth]'; -import prisma from '../../../../lib/prisma'; - -export default async (req, res) => { - const session = await getServerSession(req, res, authOptions); - - if (!session?.user) { - console.log('Unauthorized access attempt'); - return res.status(401).send({ message: "Unauthorized" }); - } - - try { - const update = await prisma.session.findFirst({ - where: { - userId: req.body.id - }, - orderBy: { - expires: 'desc' - } - }); - if (update) { - const userId = update.userId; - return res.status(200).send({ message: userId }); - } - return res.status(200).send({ message: false }); - } catch (e) { - console.error('Error deleting post:', e); - return res.status(500).json({ error: true, message: 'Internal Server Error' }); - } -};