Skip to content

Commit

Permalink
feat: Implemented user liked and bookmarked tweets functionality in u…
Browse files Browse the repository at this point in the history
…ser profile
  • Loading branch information
pratyushsingha committed Mar 12, 2024
1 parent b56ee71 commit e17084d
Show file tree
Hide file tree
Showing 10 changed files with 268 additions and 125 deletions.
4 changes: 4 additions & 0 deletions src/components/Index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ import Profile from "@/pages/auth/Profile";
import UserDetails from "@/pages/auth/UserDetails";
import InputDiv from "./InputDiv";
import PassStrengthBar from "./PaawordStrengthBar";
import Tweets from "@/pages/Tweets";
import BookmarkedTweets from "@/pages/BookmarkedTweets";

export {
sidebarItems,
Expand Down Expand Up @@ -86,4 +88,6 @@ export {
CardTitle,
InputDiv,
PassStrengthBar,
Tweets,
BookmarkedTweets,
};
18 changes: 10 additions & 8 deletions src/components/Sidebar.jsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import { Link } from "react-router-dom";
import { sidebarItems, Button } from "./Index";
const Sidebar = () => {
return (
<div className="sm:col-span-2 sticky start-0 bottom-0 top-0 left-0 right-0">
<div className="flex flex-col space-y-3">
{sidebarItems.map((item) => (
<Button
variant="ghost"
key={item._id}
className="flex space-x-3 justify-start"
>
{item.icon}
<p className="hidden sm:block">{item.title}</p>
</Button>
<Link key={item._id} to={`${item.path}`}>
<Button
variant="ghost"
className="flex space-x-3 justify-start"
>
{item.icon}
<p className="hidden sm:block">{item.title}</p>
</Button>
</Link>
))}
</div>
</div>
Expand Down
89 changes: 80 additions & 9 deletions src/components/TweetCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useContext, useRef } from "react";
import { Link } from "react-router-dom";
import moment from "moment";
import { Heart, Bookmark, Share2, MessageCircle, Copy } from "lucide-react";
import axios from "axios";

import {
Label,
Expand All @@ -16,22 +17,87 @@ import {
DialogTrigger,
Button,
useToast,
AppContext,
} from "@/components/Index";

const TweetCard = ({ tweet, bookMarkTweet, toggleLike }) => {
const TweetCard = ({
tweet,
setTweets,
removeFromBookmarks,
removeFromLikes,
}) => {
const { toast } = useToast();
const inputRef = useRef();

const handleCopy = () => {
inputRef.current?.select();
window.navigator.clipboard.writeText(
`${window.location.href}tweet/${tweet._id}`
`${import.meta.env.VITE_FRONTEND_URL}/tweet/${tweet._id}`
);
toast({
title: "Copied to clipboard",
});
};

const toggleLike = async (tweetId, e) => {
e.preventDefault();
try {
const response = await axios.post(
`${import.meta.env.VITE_BACKEND_URL}/like/tweet/${tweetId}`,
{},
{ withCredentials: true }
);
const updatedTweet = response.data.data[0];
setTweets((prevTweets) =>
prevTweets.map((tweet) =>
tweet._id === updatedTweet._id ? updatedTweet : tweet
)
);

if (typeof removeFromLikes === "function" && !updatedTweet.isLiked) {
removeFromLikes(tweetId);
}
} catch (error) {
console.log(error);
toast({
variant: "destructive",
title: "error",
description: `${error.message}`,
});
}
};

const bookMarkTweet = async (tweetId, e) => {
e.preventDefault();
try {
const response = await axios.post(
`${import.meta.env.VITE_BACKEND_URL}/bookmarks/${tweetId}`,
{},
{ withCredentials: true }
);

const updatedTweet = response.data.data[0];
setTweets((prevTweets) =>
prevTweets.map((tweet) =>
tweet._id === updatedTweet._id ? updatedTweet : tweet
)
);
if (
typeof removeFromBookmarks === "function" &&
!updatedTweet.isBookmarked
) {
removeFromBookmarks(tweetId);
}
} catch (error) {
console.log(error);
toast({
variant: "destructive",
title: "error",
description: `${error.message}`,
});
}
};

return (
<div className="relative mb-2 w-full last:mb-0 sm:mb-4">
<div className="flex border-b border-t border-slate p-4 text-white rounded sm:border-l sm:border-r">
Expand All @@ -42,18 +108,21 @@ const TweetCard = ({ tweet, bookMarkTweet, toggleLike }) => {
? "https://i.postimg.cc/Pxd7wvnh/image.png"
: tweet?.ownerDetails?.avatar
}
alt={
tweet.isAnonymous ? "Anonymous" : tweet?.ownerDetails?.username
}
alt={tweet.isAnonymous ? "Anonymous" : tweet.ownerDetails?.username}
className="h-full w-full rounded-full object-cover"
/>
</div>
<div className="pl-4 pt-1">
<div className="mb-2 flex justify-between items-center gap-x-2">
<div className="w-full">
<h2 className="inline-block font-bold">
{tweet.isAnonymous ? "Anonymous" : tweet.ownerDetails.username}
</h2>
{tweet.ownerDetails && (
<h2 className="inline-block font-bold">
{tweet.isAnonymous
? "Anonymous"
: tweet.ownerDetails.username}
</h2>
)}

<span className="ml-2 inline-block text-sm text-gray-400">
{moment(tweet.updatedAt, "YYYYMMDD").fromNow()}
</span>
Expand Down Expand Up @@ -123,7 +192,9 @@ const TweetCard = ({ tweet, bookMarkTweet, toggleLike }) => {
</Label>
<Input
id="link"
defaultValue={`${window.location.href}tweet/${tweet._id}`}
defaultValue={`${
import.meta.env.VITE_FRONTEND_URL
}/tweet/${tweet._id}`}
readOnly
ref={inputRef}
/>
Expand Down
6 changes: 6 additions & 0 deletions src/main.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ import {
TweetDetails,
Profile,
UserDetails,
Tweets,
BookmarkedTweets
} from "@/components/Index";
import "./index.css";
import LikedTweets from "./pages/LikedTweets";

const router = createBrowserRouter([
{
Expand All @@ -25,6 +28,9 @@ const router = createBrowserRouter([
path: "/profile/:username",
element: <Profile />,
children: [
{ path: "/profile/:username/", element: <Tweets /> },
{ path: "/profile/:username/bookmarkedTweets", element: <BookmarkedTweets /> },
{ path: "/profile/:username/likedTweets", element: <LikedTweets /> },
{ path: "/profile/:username/edit", element: <UserDetails /> },
],
},
Expand Down
60 changes: 60 additions & 0 deletions src/pages/BookmarkedTweets.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { useEffect, useState } from "react";
import { Spinner, TweetCard, useToast } from "@/components/Index";
import axios from "axios";

const BookmarkedTweets = () => {
const { toast } = useToast();
const [loading, setLoading] = useState(false);
const [tweets, setTweets] = useState([]);

const bookmarkedTweets = async () => {
setLoading(true);
try {
const response = await axios.get(
`${import.meta.env.VITE_BACKEND_URL}/bookmarks`,
{
withCredentials: true,
}
);
// console.log(response.data.data[0].bookmarkedTweet)
setTweets(response.data.data[0].bookmarkedTweet);
setLoading(false);
} catch (error) {
console.log(error);
toast({
variant: "destructive",
title: "error",
description: `${error.message}`,
});
setLoading(false);
}
};

const removeFromBookmarks = (tweetId) => {
setTweets((prevTweets) =>
prevTweets.filter((tweet) => tweet._id !== tweetId)
);
toast({
title: "Removed from your bookmarks",
});
};

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

return loading ? (
<Spinner />
) : (
tweets.map((tweet) => (
<TweetCard
key={tweet._id}
tweet={tweet}
setTweets={setTweets}
removeFromBookmarks={removeFromBookmarks}
/>
))
);
};

export default BookmarkedTweets;
57 changes: 1 addition & 56 deletions src/pages/Home.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,56 +34,6 @@ const Home = () => {
}
};

const toggleLike = async (tweetId, e) => {
e.preventDefault();
try {
const response = await axios.post(
`${import.meta.env.VITE_BACKEND_URL}/like/tweet/${tweetId}`,
{},
{ withCredentials: true }
);
const updatedTweet = response.data.data[0];
setTweets((prevTweets) =>
prevTweets.map((tweet) =>
tweet._id === updatedTweet._id ? updatedTweet : tweet
)
);
} catch (error) {
console.log(error);
toast({
variant: "destructive",
title: "error",
description: `${error.message}`,
});
}
};

const bookMarkTweet = async (tweetId, e) => {
e.preventDefault();
try {
const response = await axios.post(
`${import.meta.env.VITE_BACKEND_URL}/bookmarks/${tweetId}`,
{},
{ withCredentials: true }
);
// console.log(response.data.data[0]);

const updatedTweet = response.data.data[0];
setTweets((prevTweets) =>
prevTweets.map((tweet) =>
tweet._id === updatedTweet._id ? updatedTweet : tweet
)
);
} catch (error) {
console.log(error);
toast({
variant: "destructive",
title: "error",
description: `${error.message}`,
});
}
};

useEffect(() => {
getFeedTweets();
}, [page]);
Expand All @@ -97,12 +47,7 @@ const Home = () => {
<>
<TweetBox />
{tweets.map((tweet, index) => (
<TweetCard
key={index}
tweet={tweet}
toggleLike={toggleLike}
bookMarkTweet={bookMarkTweet}
/>
<TweetCard key={index} tweet={tweet} setTweets={setTweets} />
))}
</>
);
Expand Down
58 changes: 58 additions & 0 deletions src/pages/LikedTweets.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { Spinner, TweetCard, useToast } from "@/components/Index";
import axios from "axios";
import React, { useEffect, useState } from "react";

const LikedTweets = () => {
const { toast } = useToast();
const [loading, setLoading] = useState(false);
const [tweets, setTweets] = useState([]);

const userTweets = async () => {
setLoading(true);
try {
const response = await axios.get(
`${import.meta.env.VITE_BACKEND_URL}/like/tweets`,
{
withCredentials: true,
}
);
console.log(response);
setTweets(response.data.data[0].likedTweets);
setLoading(false);
} catch (error) {
console.log(error);
toast({
variant: "destructive",
title: "error",
description: `${error.message}`,
});
setLoading(false);
}
};

const removeFromLikes = (tweetId) => {
setTweets((prevTweets) =>
prevTweets.filter((tweet) => tweet._id !== tweetId)
);
toast({
title: "Removed from your likes",
});
};

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

loading && <Spinner />;

return tweets.map((tweet) => (
<TweetCard
key={tweet._id}
tweet={tweet}
setTweets={setTweets}
removeFromLikes={removeFromLikes}
/>
));
};

export default LikedTweets;
Loading

0 comments on commit e17084d

Please sign in to comment.