layout.tsx
file is the main layout for the application. Every page is wrapped under this layout.- I've just added a Providers for the application. Everything else is just barebone.
- The
page.tsx
contains componentHome
which is the main page for the application. - There is nothing at our home page. It's just a blank page with SignOut button. Since it's protected route only authenticated users can access this page.
- Techincally the home page for a legit authenticated user is
/dashboard
.
- In next.js, we can create an API route by creating a file in
app/api
directory. - Our API contains 3 major routes:
/api/auth/
- For authentication, fully handled by next-auth./api/friends
- For managing friends of the user./api/message
- For managing messages between friends.
- The auth API contains a
[...nextauth]
catch all route, because that's how next-auth works. It will be able to get all the URL params and query params which is required for authentication. - It is the convention to use
route.ts
file for defining the routes and their handlers in Next.js. - This file is mostly barebones which is just exposing the NextAuth handler for GET and POST requests.
- This handler uses
authOptions
which are imported fromlib/auth
authOptions
define all of the configurations of next-auth. It's a simple object with all the required configurations.
- This part defines 3 major routes:
/api/friends/add
- For sending friend requests./api/friends/accept
- For accepting friend requests./api/friends/deny
- For rejecting friend requests.
- In next.js for backend API to work properly, we need to export a component named as the methods of request type. For example for
POST
request we need to export a component namedPOST
.
-
Exposes a POST handler.
-
First the body of the request is parsed using
req.json()
-
Validations --
- Check if the email is a valid email.
- Check if the user with that email exists in the database.
- Check if the user is not trying to add himself.
- Check if friend request is already sent to the user.
- Check if the user is not trying to add a friend who is already a friend.
-
If all the validations pass, then we add the friend request to the database and trigger a notification to
pusherServer
. -
At places we can validate if the session is present or not. If not present, then the user is not authenticated to perform that action.
const session = await getServerSession(authOptions) if (!session) { return new Response('Unauthorized', { status: 401 }) }
- Exposes a POST handler.
- First the body of the request is parsed using
req.json()
- Validations --
- Check if the id is a valid id.
- Check if the user is logged in. If not then return unauthorized.
- Check if both the users are not already friends.
- Check if there is a friend request from the user. Without a friend request, the user cannot accept the friend.
- If all the validations pass, we fetch data of both users from the database using the ids.
- We add both users to each other's friend list.
- Trigger a notification to
pusherServer
.
- Exposes a POST handler.
- First the body of the request is parsed using
req.json()
- Validations --
- Check if the user is logged in. If not then return unauthorized.
- Check if the id is a valid id.
- Check if there is a friend request from the user. Without a friend request, the user cannot deny the friend.
- If all the validations pass, we delete the friend request from the database.
- We don't need to trigger a notification to
pusherServer
because the user is just denying the friend request. No UI updation is required at the friend request sender's end.
- API route is
/api/message/send
- Exposes a POST handler.
- The message text and
chatId
is extracted from the request body. - Validations --
- Check if the user is logged in. If not then return unauthorized.
- Extract Ids of both users from the
chatId
. If the current user's id doesn't match with the any of the ids, then return unauthorized. - Confirm that both users are friends. If not then return unauthorized.
- Construct the message object and validate it using
messageValidator
. - Save the message to the database.
- Trigger a notification to
pusherServer
.
- There is just a single page which is shown at
/login
- Functions
loginWithGoogle()
- Sets the loading state to true.
- Calls the
signIn
function fromnext-auth
with the provider asgoogle
. - Shows a toast if there is an error.
- Finally sets the loading state to false.
- Contains 4 pages
/dashboard
- The main dashboard page. Recent chats and friends are shown here./dashboard/add
- For adding friends./dashboard/chat
- For chatting with friends./dashboard/request
- For accepting or denying friend requests.
- There is a
loading.tsx
page in all the paths (add
,chat
,request
). Next.js automatically shows this page when the page is loading. - The main page is mostly barebones which renders a
AddFriendForm
component.
- Contains a parameter
chatId
which is the id of the chat between the user and the friend in the URL. - Chat id is obtained from the query params.
- If there is no session, then not found page is shown.
- Validations checks are done to ensure that only the user who is part of the chat can access the chat.
- Chat partner's data is fetched from the database using the id obtained from
chatId
. - Messages are loading using function
getChatMessages()
. - Functions
getChatMessages()
- Fetches the chat messages between the user and the friend using the
chatId
. - Parses the response and sets the messages in the state.
- Reverse the messages array to show the latest messages at the bottom.
- Validates if the message data contains the required fields using validator
messageArrayValidator
. - Returns the messages array.
- If there is an error, then it returns a not found page using nextjs's
notFound()
function.
- Fetches the chat messages between the user and the friend using the
- session is validated, if not found then not found page is shown.
- Ids of the friend who sent requests are fetched for the current user.
- Data about the users who sent the requests is fetched from the database using the ids.
- The page is rendered using the
FriendRequests
component.