Build a Real-Time Slack Clone With Nextjs, React, Tailwind, Auth.js | Part 2/2 (2024)

Code With AntonioAbout 8 min readMay 27, 2025Watch original
THE SUMMARYAI-generated

Slack Clone Part 2 YouTube Transcript Summary

Key Concepts:

  • Emoji selection tool implementation
  • Image upload functionality
  • Submit functionality implementation
  • Message schema and creation
  • Message loading and population
  • Image upload implementation
  • Conversation ID handling
  • Message editing and deletion
  • Reactions implementation
  • Thread functionality
  • One-on-one conversation implementation
  • User profile implementation
  • Role change and remove/leave workspace functionality
  • Deployment to Vercel

1. Dynamic Text Modification:

  • The text below the editor component is made dynamic, only displaying when the variant is "create".
  • A dynamic class name is added using CN library to control opacity and transition based on input emptiness.
  • Example: CN(defaultClass, isEmpty ? 'opacity-0 transition' : 'opacity-100')

2. Emoji Selection Tool Implementation:

  • Two packages are installed: emoji-mart/data and emoji-mart/react.
  • An EmojiPopover component is created for reusable emoji selection.
  • The component uses Popover and Tooltip components from shadcn-ui.
  • A complex structure is required to combine Popover and Tooltip functionality.
  • Two states are used: popoverOpen and tooltipOpen.
  • The Picker component from emoji-mart/react is used to display emojis.
  • The onEmojiSelect function inserts the selected emoji into the text area using quill.insertText.
  • The index of the current selection is used to insert the emoji at the correct position.

3. Image Upload Functionality:

  • State variables image and setImage are added to control image selection.
  • An imageElementRef is created using useRef to access the file input element.
  • A "Phantom input" (hidden file input) is used to trigger the file selection dialog.
  • The onClick event of the image button triggers the click event of the Phantom input.
  • The selected image is displayed below the editor using URL.createObjectURL.
  • A delete button is added to remove the selected image.

4. Submit Functionality Implementation:

  • A handleSubmit method is created to handle form submission.
  • The handleSubmit method accepts body (text content) and image (file) as arguments.
  • The handleSubmit method is assigned to the onsubmit method of the chat input.
  • The on submit and onclick save methods in the editor component are updated to call the handleSubmit method.
  • The quill.getContents method is used to retrieve the text content as a Delta object.
  • The JSON.stringify method is used to serialize the Delta object.
  • The image state is passed to the handleSubmit method.
  • The use Effect hook is used to handle form submission when the user presses Enter.
  • The quill.getText method is used to retrieve the text content as a plain text string.
  • The is Empty function is used to check if the input is empty.
  • The submit ref.current is called conditionally to prevent errors when the ref is empty.

5. Message Schema and Creation:

  • A new table called messages is defined in the Convex schema.
  • The messages table has the following fields: body (string), image (optional ID of _storage), memberID (ID of members), workspaceID (ID of workspaces), channelID (optional ID of channels), parentMessageID (optional ID of messages), updatedAt (optional number), and conversationID (optional ID of conversations).
  • Indexes are added to the messages table for efficient querying.
  • A create mutation is created to insert new messages into the messages table.
  • The create mutation retrieves the user ID using auth.getUserID.
  • The create mutation retrieves the member ID using a helper function called getMember.
  • The create mutation inserts the message into the messages table with the appropriate fields.
  • A hook called useCreateMessage is created to use the create mutation in the React component.

6. Message Loading and Population:

  • A get query is created to load messages from the messages table.
  • The get query accepts channelID, conversationID, and parentMessageID as arguments.
  • The get query uses pagination to load messages in batches.
  • Helper functions are created to populate user, member, reactions, and thread information for each message.
  • The populateUser function retrieves the user object from the users table.
  • The populateMember function retrieves the member object from the members table.
  • The populateReactions function retrieves the reactions for a specific message from the reactions table.
  • The populateThread function retrieves the replies for a specific message from the messages table.
  • A useGetMessages hook is created to use the get query in the React component.
  • The useGetMessages hook uses usePaginatedQuery to handle pagination.
  • The useGetMessages hook returns the results, status, and loadMore method.

7. Image Upload Implementation:

  • A new endpoint called generateUploadURL is created in the Convex functions.
  • The generateUploadURL endpoint generates a pre-signed URL for uploading files to Convex storage.
  • A hook called useGenerateUploadURL is created to use the generateUploadURL endpoint in the React component.
  • The handle Submit method is updated to upload the image to Convex storage using the pre-signed URL.
  • The fetch API is used to upload the image to the pre-signed URL.
  • The storageID of the uploaded image is retrieved from the response.
  • The storageID is then assigned to the image field of the message object.

8. Conversation ID Handling:

  • The schema is updated to include a conversationID field in the messages table.
  • The create mutation is updated to handle the conversationID field.
  • A special case is handled where the conversationID is not provided but the parentMessageID is provided.
  • In this case, the conversationID is retrieved from the parent message.
  • The useCreateMessage hook is updated to include the conversationID field.
  • The get query is updated to handle the conversationID field.
  • A similar edge case is handled in the get query where the conversationID is not provided but the parentMessageID is provided.

9. Message Editing and Deletion:

  • An update mutation is created to update the body of a message.
  • A remove mutation is created to delete a message.
  • Hooks are created for both mutations.
  • The message component is updated to include edit and delete buttons.
  • The edit button toggles the editing state of the message.
  • The delete button opens a confirmation dialog.
  • The CN library is used to dynamically style the message based on its editing and deleting states.

10. Reactions Implementation:

  • A toggle mutation is created to add or remove reactions from a message.
  • A hook is created for the mutation.
  • The message component is updated to display reactions.
  • The reactions are normalized on the backend to count the number of users who reacted with the same emoji.
  • The message component is updated to allow users to add or remove reactions by clicking on the emoji.

11. Thread Functionality:

  • The nqs package is installed to manage the parent message ID in the URL.
  • A useParentMessageID hook is created to manage the parent message ID.
  • A usePanel hook is created to manage the state of the thread panel.
  • The layout component is updated to render the thread panel when the parent message ID is present in the URL.
  • A thread component is created to display the thread messages.
  • The thread component uses the useGetMessages hook to load the replies for the parent message.
  • The thread component includes a chat input for adding new replies.

12. One-on-One Conversation Implementation:

  • A new route is created for one-on-one conversations.
  • A createOrGet mutation is created to find or create a conversation between two members.
  • A hook is created for the mutation.
  • The page component is updated to use the createOrGet mutation to retrieve the conversation ID.
  • A conversation component is created to display the messages in the one-on-one conversation.
  • The conversation component reuses the existing message list and chat input components.

13. User Profile Implementation:

  • A new route is created for user profiles.
  • A getByID query is created to retrieve member information.
  • A hook is created for the query.
  • The page component is updated to use the getByID query to retrieve the member information.
  • A profile component is created to display the member information.

14. Role Change and Remove/Leave Workspace Functionality:

  • An update mutation is created to update the role of a member.
  • A remove mutation is created to remove a member from the workspace.
  • Hooks are created for both mutations.
  • The profile component is updated to include options for changing the role and removing the member.
  • The options are only displayed to admins.
  • The profile component is updated to include a leave button for non-admin users.
  • Confirmation dialogs are added for all actions.

15. Deployment to Vercel:

  • A new GitHub repository is created.
  • The project is pushed to the GitHub repository.
  • The project is imported into Vercel.
  • The build command is overwritten to include the Convex deploy command.
  • The Convex deploy key environment variable is set.
  • The Google and GitHub authentication environment variables are set.

Main Takeaways:

  • The video demonstrates the implementation of a complex Slack clone feature by feature.
  • It emphasizes the importance of reusable components and hooks.
  • It showcases the power of Convex for building real-time applications.
  • It provides a detailed guide on deploying a Convex application to Vercel.
  • It highlights the importance of careful state management and error handling.
  • It provides a comprehensive overview of the key concepts and techniques used in modern web development.

AI summaries can miss context or contain errors. Check important details against the original video.

Go a little deeper.

Have a question about this video? Load its transcript to open the video chat.