diff --git a/convex/users.ts b/convex/users.ts index c018b8b..64e8400 100644 --- a/convex/users.ts +++ b/convex/users.ts @@ -103,4 +103,26 @@ export const getMe = query({ }, }); -// TODO: add getGroupMembers query -- later +export const getGroupMembers = query({ + args: { conversationId: v.id("conversations") }, + handler: async (ctx, args) => { + const identity = await ctx.auth.getUserIdentity(); + + if (!identity) { + throw new ConvexError("Unauthorized"); + } + + const conversation = await ctx.db + .query("conversations") + .filter((q) => q.eq(q.field("_id"), args.conversationId)) + .first(); + if (!conversation) { + throw new ConvexError("Conversation not found"); + } + + const users = await ctx.db.query("users").collect(); + const groupMembers = users.filter((user) => conversation.participants.includes(user._id)); + + return groupMembers; + }, +}); diff --git a/package-lock.json b/package-lock.json index ae83500..4e82962 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,7 +25,8 @@ "react-hot-toast": "^2.4.1", "svix": "^1.21.0", "tailwind-merge": "^2.2.2", - "tailwindcss-animate": "^1.0.7" + "tailwindcss-animate": "^1.0.7", + "zustand": "^4.5.2" }, "devDependencies": { "@types/node": "^20", @@ -6791,6 +6792,33 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zustand": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.2.tgz", + "integrity": "sha512-2cN1tPkDVkwCy5ickKrI7vijSjPksFRfqS6237NzT0vqSsztTNnQdHw9mmN7uBdk3gceVXU0a+21jFzFzAc9+g==", + "dependencies": { + "use-sync-external-store": "1.2.0" + }, + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "@types/react": ">=16.8", + "immer": ">=9.0.6", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + } + } } } } diff --git a/package.json b/package.json index bcdc7ea..dffc153 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,8 @@ "react-hot-toast": "^2.4.1", "svix": "^1.21.0", "tailwind-merge": "^2.2.2", - "tailwindcss-animate": "^1.0.7" + "tailwindcss-animate": "^1.0.7", + "zustand": "^4.5.2" }, "devDependencies": { "@types/node": "^20", diff --git a/src/components/home/conversation.tsx b/src/components/home/conversation.tsx index 148cac2..5d18454 100644 --- a/src/components/home/conversation.tsx +++ b/src/components/home/conversation.tsx @@ -4,6 +4,7 @@ import { MessageSeenSvg } from "@/lib/svgs"; import { ImageIcon, Users, VideoIcon } from "lucide-react"; import { useQuery } from "convex/react"; import { api } from "../../../convex/_generated/api"; +import { useConversationStore } from "@/store/chat-store"; const Conversation = ({ conversation }: { conversation: any }) => { const conversationImage = conversation.groupImage || conversation.image; @@ -11,11 +12,18 @@ const Conversation = ({ conversation }: { conversation: any }) => { const lastMessage = conversation.lastMessage; const lastMessageType = lastMessage?.messageType; const me = useQuery(api.users.getMe); - // + + const { setSelectedConversation, selectedConversation } = useConversationStore(); + const activeBgClass = selectedConversation?._id === conversation._id; return ( <> -
+
setSelectedConversation(conversation)} + > {conversation.isOnline && (
diff --git a/src/components/home/group-members-dialog.tsx b/src/components/home/group-members-dialog.tsx index d5df782..46d521f 100644 --- a/src/components/home/group-members-dialog.tsx +++ b/src/components/home/group-members-dialog.tsx @@ -1,4 +1,3 @@ -import { users } from "@/dummy-data/db"; import { Dialog, DialogContent, @@ -9,8 +8,16 @@ import { } from "@/components/ui/dialog"; import { Avatar, AvatarFallback, AvatarImage } from "../ui/avatar"; import { Crown } from "lucide-react"; +import { Conversation } from "@/store/chat-store"; +import { useQuery } from "convex/react"; +import { api } from "../../../convex/_generated/api"; -const GroupMembersDialog = () => { +type GroupMembersDialogProps = { + selectedConversation: Conversation; +}; + +const GroupMembersDialog = ({ selectedConversation }: GroupMembersDialogProps) => { + const users = useQuery(api.users.getGroupMembers, { conversationId: selectedConversation._id }); return ( @@ -39,7 +46,9 @@ const GroupMembersDialog = () => { {/* johndoe@gmail.com */} {user.name || user.email.split("@")[0]} - {user.admin && } + {user._id === selectedConversation.admin && ( + + )}
diff --git a/src/components/home/right-panel.tsx b/src/components/home/right-panel.tsx index b5fbf91..0ba95f6 100644 --- a/src/components/home/right-panel.tsx +++ b/src/components/home/right-panel.tsx @@ -5,13 +5,14 @@ import MessageInput from "./message-input"; import MessageContainer from "./message-container"; import ChatPlaceHolder from "@/components/home/chat-placeholder"; import GroupMembersDialog from "./group-members-dialog"; +import { useConversationStore } from "@/store/chat-store"; const RightPanel = () => { - const selectedConversation = true; + const { selectedConversation, setSelectedConversation } = useConversationStore(); if (!selectedConversation) return ; - const conversationName = "John Doe"; - const isGroup = true; + const conversationName = selectedConversation.groupName || selectedConversation.name; + const conversationImage = selectedConversation.groupImage || selectedConversation.image; return (
@@ -20,14 +21,16 @@ const RightPanel = () => {
- +

{conversationName}

- {isGroup && } + {selectedConversation.isGroup && ( + + )}
@@ -35,7 +38,7 @@ const RightPanel = () => { - + setSelectedConversation(null)} />
diff --git a/src/store/chat-store.ts b/src/store/chat-store.ts new file mode 100644 index 0000000..d08e0f5 --- /dev/null +++ b/src/store/chat-store.ts @@ -0,0 +1,30 @@ +import { Id } from "../../convex/_generated/dataModel"; +import { create } from "zustand"; + +export type Conversation = { + _id: Id<"conversations">; + image?: string; + participants: Id<"users">[]; + isGroup: boolean; + name?: string; + groupImage?: string; + groupName?: string; + admin?: Id<"users">; + isOnline?: boolean; + lastMessage?: { + _id: Id<"messages">; + conversation: Id<"conversations">; + content: string; + sender: Id<"users">; + }; +}; + +type ConversationStore = { + selectedConversation: Conversation | null; + setSelectedConversation: (conversation: Conversation | null) => void; +}; + +export const useConversationStore = create((set) => ({ + selectedConversation: null, + setSelectedConversation: (conversation) => set({ selectedConversation: conversation }), +}));