-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
--- <details open="true"><summary>Generated summary (powered by <a href="https://app.graphite.dev">Graphite</a>)</summary> > ## TL;DR > This pull request includes several changes to different files. It adds functionality for following and unfollowing users, updates React components to handle follow and unfollow actions, imports a new library for displaying toast messages, creates new functions for checking if a user is being followed and following a user, and modifies the database schema to include fields for user relationships. > > ## What changed > - Added functions for following and unfollowing users > - Updated React components to handle follow and unfollow actions > - Imported a new library for displaying toast messages > - Created new functions for checking if a user is being followed and following a user > - Modified the database schema to include fields for user relationships > > ## How to test > 1. Run the application and navigate to the UserPage component > 2. Verify that the Actions component is rendered with the correct props > 3. Click the "Follow" or "Unfollow" button and observe the transition state > 4. Check if the API call is successful and the appropriate toast message is displayed > 5. Verify that the button is disabled while the transition is pending > 6. Test the new functions for checking if a user is being followed and following a user > 7. Verify that the database schema has been updated with the new fields for user relationships > > ## Why make this change > - The code adds functionality for following and unfollowing users, which enhances the user experience and allows users to connect with each other. > - The React component updates improve the user interface and provide visual feedback for follow and unfollow actions. > - The addition of the toast message library enhances the user experience by displaying success or error messages for follow and unfollow actions. > - The new functions for checking if a user is being followed and following a user provide important functionality for managing user relationships. > - The modifications to the database schema allow for more efficient querying and management of user relationships. </details>
- Loading branch information
Showing
10 changed files
with
300 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
"use server"; | ||
|
||
import { followUser, unfollowUser } from "@/lib/follow-service"; | ||
import { revalidatePath } from "next/cache"; | ||
|
||
export const onFollow = async (id: string) => { | ||
try { | ||
const followedUser = await followUser(id); | ||
|
||
revalidatePath("/"); | ||
|
||
if (followedUser) { | ||
revalidatePath(`/${followedUser.following.username}`); | ||
} | ||
|
||
return followedUser; | ||
} catch (error) { | ||
throw new Error("Interal Error"); | ||
} | ||
}; | ||
|
||
export const onUnfollow = async (id: string) => { | ||
try { | ||
const unfollowedUser = await unfollowUser(id); | ||
|
||
revalidatePath("/"); | ||
|
||
if (unfollowedUser) { | ||
revalidatePath(`/${unfollowedUser.following.username}`); | ||
} | ||
|
||
return unfollowedUser; | ||
} catch (error) { | ||
throw new Error("Internal Error"); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
"use client"; | ||
|
||
import { onFollow, onUnfollow } from "@/actions/follow"; | ||
import { Button } from "@/components/ui/button"; | ||
import { useTransition } from "react"; | ||
import { toast } from "sonner"; | ||
|
||
interface ActionsProps { | ||
isFollowing: boolean; | ||
userId: string; | ||
} | ||
|
||
export const Actions = ({ isFollowing, userId }: ActionsProps) => { | ||
const [isPending, startTransition] = useTransition(); | ||
|
||
const handleFollow = () => { | ||
startTransition(() => { | ||
onFollow(userId) | ||
.then((data) => | ||
toast.success(`You are now following ${data.following.username}`) | ||
) | ||
.catch(() => toast.error("Something went wrong")); | ||
}); | ||
}; | ||
|
||
const handleUnfollow = () => { | ||
startTransition(() => { | ||
onUnfollow(userId) | ||
.then((data) => | ||
toast.success(`You have unfollowed ${data.following.username}`) | ||
) | ||
.catch(() => toast.error("Something went wrong")); | ||
}); | ||
}; | ||
|
||
const onClick = () => { | ||
if (isFollowing) { | ||
handleUnfollow(); | ||
} else { | ||
handleFollow(); | ||
} | ||
}; | ||
|
||
return ( | ||
<> | ||
<Button disabled={isPending} onClick={onClick} variant="primary"> | ||
{isFollowing ? "Unfollow" : "Follow"} | ||
</Button> | ||
</> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { getUserByUsername } from "@/lib/user-service"; | ||
import { notFound } from "next/navigation"; | ||
import React from "react"; | ||
import { Actions } from "./_components/actions"; | ||
import { isFollowingUser } from "@/lib/follow-service"; | ||
|
||
interface UserPageProps { | ||
params: { | ||
username: string; | ||
}; | ||
} | ||
|
||
const UserPage = async ({ params }: UserPageProps) => { | ||
const user = await getUserByUsername(params.username); | ||
|
||
if (!user) { | ||
notFound(); | ||
} | ||
|
||
const isFollowing = await isFollowingUser(params.username); | ||
|
||
return ( | ||
<div> | ||
<Actions isFollowing={isFollowing} userId={user.id} /> | ||
</div> | ||
); | ||
}; | ||
|
||
export default UserPage; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
import { getSelf } from "@/lib/auth-service"; | ||
import { db } from "@/lib/db"; | ||
|
||
export const isFollowingUser = async (id: string) => { | ||
try { | ||
const self = await getSelf(); | ||
|
||
const otherUser = await db.user.findUnique({ | ||
where: { id }, | ||
}); | ||
|
||
if (!otherUser) { | ||
throw new Error("User not found"); | ||
} | ||
|
||
if (otherUser.id === self.id) { | ||
return true; | ||
} | ||
|
||
const existingFollow = await db.follow.findFirst({ | ||
where: { | ||
followerId: self.id, | ||
followingId: otherUser.id, | ||
}, | ||
}); | ||
|
||
return !!existingFollow; | ||
} catch { | ||
return false; | ||
} | ||
}; | ||
|
||
export const followUser = async (id: string) => { | ||
const self = await getSelf(); | ||
|
||
const otherUser = await db.user.findUnique({ | ||
where: { id }, | ||
}); | ||
|
||
if (!otherUser) { | ||
throw new Error("User not found"); | ||
} | ||
|
||
if (otherUser.id === self.id) { | ||
throw new Error("Cannot follow yourself"); | ||
} | ||
|
||
const existingFollow = await db.follow.findFirst({ | ||
where: { | ||
followerId: self.id, | ||
followingId: otherUser.id, | ||
}, | ||
}); | ||
|
||
if (existingFollow) { | ||
throw new Error("Already Following"); | ||
} | ||
|
||
const follow = await db.follow.create({ | ||
data: { | ||
followerId: self.id, | ||
followingId: otherUser.id, | ||
}, | ||
include: { | ||
following: true, | ||
follower: true, | ||
}, | ||
}); | ||
|
||
return follow; | ||
}; | ||
|
||
export const unfollowUser = async (id: string) => { | ||
const self = await getSelf(); | ||
|
||
const otherUser = await db.user.findUnique({ | ||
where: { | ||
id, | ||
}, | ||
}); | ||
|
||
if (!otherUser) { | ||
throw new Error("User not found"); | ||
} | ||
|
||
if (otherUser.id === self.id) { | ||
throw new Error("Cannot unfollow yourself"); | ||
} | ||
|
||
const existingFollow = await db.follow.findFirst({ | ||
where: { | ||
followerId: self.id, | ||
followingId: otherUser.id, | ||
}, | ||
}); | ||
|
||
if (!existingFollow) { | ||
throw new Error("Not following"); | ||
} | ||
|
||
const follow = await db.follow.delete({ | ||
where: { | ||
id: existingFollow.id, | ||
}, | ||
include: { | ||
following: true, | ||
}, | ||
}); | ||
|
||
return follow; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,36 @@ | ||
import { db } from "./db"; | ||
import { db } from "@/lib/db"; | ||
import { getSelf } from "@/lib/auth-service"; | ||
|
||
export const getRecommended = async () => { | ||
const users = await db.user.findMany({ | ||
orderBy: { | ||
createAt: "desc", | ||
let userId; | ||
|
||
try { | ||
const self = await getSelf(); | ||
userId = self.id; | ||
} catch { | ||
userId = null; | ||
} | ||
|
||
let users = []; | ||
|
||
if (userId) { | ||
users = await db.user.findMany({ | ||
where: { | ||
NOT: { | ||
id: userId, | ||
}, | ||
}, | ||
orderBy: { | ||
createAt: "desc", | ||
}, | ||
}); | ||
} else { | ||
users = await db.user.findMany({ | ||
orderBy: { | ||
createAt: "desc", | ||
}, | ||
}); | ||
} | ||
|
||
return users; | ||
return users; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { db } from "@/lib/db"; | ||
|
||
export const getUserByUsername = async (username: string) => { | ||
const user = await db.user.findUnique({ | ||
where: { | ||
username, | ||
}, | ||
}); | ||
|
||
return user; | ||
}; |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters