diff --git a/exm-web/app/(main)/chats/detail/page.tsx b/exm-web/app/(main)/chats/detail/page.tsx
index da4ac9fdd8..5a895d1dab 100644
--- a/exm-web/app/(main)/chats/detail/page.tsx
+++ b/exm-web/app/(main)/chats/detail/page.tsx
@@ -1,9 +1,15 @@
+import RightSideBar from "@/modules/chat/component/RightSideBar"
import Messages from "@/modules/chat/component/messages/Messages"
export default function Detail() {
return (
-
diff --git a/exm-web/modules/chat/component/ParticipantItem.tsx b/exm-web/modules/chat/component/ParticipantItem.tsx
new file mode 100644
index 0000000000..34bf79f779
--- /dev/null
+++ b/exm-web/modules/chat/component/ParticipantItem.tsx
@@ -0,0 +1,134 @@
+"use client"
+
+import { useState } from "react"
+import { IUser } from "@/modules/auth/types"
+import {
+ AlertTriangleIcon,
+ CheckCircleIcon,
+ ShieldOffIcon,
+ UserXIcon,
+ XCircleIcon,
+} from "lucide-react"
+
+import { readFile } from "@/lib/utils"
+import Avatar from "@/components/ui/avatar"
+import { Button } from "@/components/ui/button"
+import {
+ Dialog,
+ DialogContent,
+ DialogFooter,
+ DialogTrigger,
+} from "@/components/ui/dialog"
+
+import useChatsMutation from "../hooks/useChatsMutation"
+
+const ParticipantItem = ({
+ participant,
+ chatId,
+ isAdmin,
+}: {
+ participant: IUser
+ chatId: string
+ isAdmin: boolean
+}) => {
+ const [open, setOpen] = useState(false)
+ const [showAction, setShowAction] = useState(false)
+
+ const { makeOrRemoveAdmin, addOrRemoveMember } = useChatsMutation()
+
+ const adminMutation = () => {
+ makeOrRemoveAdmin(chatId, participant._id)
+ }
+
+ const userMutation = () => {
+ addOrRemoveMember(chatId, "remove", [participant._id])
+ }
+
+ const renderActionButtons = () => {
+ if (!isAdmin) {
+ return null
+ }
+
+ const renderForm = () => {
+ return (
+
+
+
+
+
+
+
+
+ )
+ }
+
+ return (
+
+
+
+
+
+
+ )
+ }
+
+ return (
+
setShowAction(true)}
+ onMouseLeave={() => setShowAction(false)}
+ >
+
+
+
+
+
+ {participant?.details?.fullName || participant?.email}
+
+
+ {participant.isAdmin ? "Admin " : ""}
+ {participant?.details?.position || ""}
+
+
+
+ {showAction ? renderActionButtons() : null}
+
+
+ )
+}
+
+export default ParticipantItem
diff --git a/exm-web/modules/chat/component/ParticipantList.tsx b/exm-web/modules/chat/component/ParticipantList.tsx
new file mode 100644
index 0000000000..ec2b25c23e
--- /dev/null
+++ b/exm-web/modules/chat/component/ParticipantList.tsx
@@ -0,0 +1,112 @@
+"use client"
+
+import { useState } from "react"
+import { queries } from "@/common/team/graphql"
+import { currentUserAtom } from "@/modules/JotaiProiveder"
+import { IUser } from "@/modules/auth/types"
+import { useQuery } from "@apollo/client"
+import { useAtomValue } from "jotai"
+import { PlusIcon } from "lucide-react"
+
+import { Button } from "@/components/ui/button"
+import {
+ Dialog,
+ DialogContent,
+ DialogHeader,
+ DialogTitle,
+ DialogTrigger,
+} from "@/components/ui/dialog"
+import { FacetedFilter } from "@/components/ui/faceted-filter"
+import { Input } from "@/components/ui/input"
+
+import useChatsMutation from "../hooks/useChatsMutation"
+import { IChat } from "../types"
+import ParticipantItem from "./ParticipantItem"
+
+const ParticipantList = ({ chat }: { chat: IChat }) => {
+ const currentUser = useAtomValue(currentUserAtom) || ({} as IUser)
+ const [userIds, setUserIds] = useState([])
+ const [open, setOpen] = useState(false)
+
+ const { data: usersData, loading } = useQuery(queries.users)
+
+ const { users } = usersData || {}
+
+ const { addOrRemoveMember } = useChatsMutation()
+
+ const addMember = () => {
+ addOrRemoveMember(chat._id, "add", userIds)
+ setOpen(false)
+ }
+
+ const isAdmin =
+ (chat?.participantUsers || []).find(
+ (pUser) => pUser._id === currentUser._id
+ )?.isAdmin || false
+
+ const renderAdd = () => {
+ const renderForm = () => {
+ return (
+
+
+ Create bravo
+
+
+ {loading ? (
+
+ ) : (
+ ({
+ label: user?.details?.fullName || user.email,
+ value: user._id,
+ }))}
+ title="Users"
+ values={userIds}
+ onSelect={setUserIds}
+ />
+ )}
+
+
+ )
+ }
+
+ return (
+
+ )
+ }
+
+ return (
+
+ {chat.participantUsers.map((user: any, index: number) => (
+
+ ))}
+
+ {isAdmin && renderAdd()}
+
+ )
+}
+
+export default ParticipantList
diff --git a/exm-web/modules/chat/component/RightSideBar.tsx b/exm-web/modules/chat/component/RightSideBar.tsx
new file mode 100644
index 0000000000..4d35cc3441
--- /dev/null
+++ b/exm-web/modules/chat/component/RightSideBar.tsx
@@ -0,0 +1,88 @@
+"use client"
+
+import { useState } from "react"
+import { currentUserAtom } from "@/modules/JotaiProiveder"
+import { useAtomValue } from "jotai"
+import { PenSquareIcon } from "lucide-react"
+
+import { readFile } from "@/lib/utils"
+import Avatar from "@/components/ui/avatar"
+import { Dialog, DialogTrigger } from "@/components/ui/dialog"
+
+import { useChatDetail } from "../hooks/useChatDetail"
+import ParticipantList from "./ParticipantList"
+import UserDetail from "./UserDetail"
+import { GroupChatAction } from "./form/GroupChatAction"
+
+const RightSideBar = () => {
+ const currentUser = useAtomValue(currentUserAtom)
+ const { chatDetail, loading } = useChatDetail()
+
+ const [open, setOpen] = useState(false)
+
+ if (loading) {
+ return null
+ }
+
+ const users: any[] = chatDetail?.participantUsers || []
+ const user: any =
+ users?.length > 1
+ ? users?.filter((u) => u._id !== currentUser?._id)[0]
+ : users?.[0]
+
+ const renderAction = () => {
+ return (
+
+ )
+ }
+
+ const renderGroup = () => {
+ return (
+ <>
+
+
+
+
+ {chatDetail.name}
+
+
+ {renderAction()}
+
+
+
+ >
+ )
+ }
+
+ const renderDirect = () => {
+ return
+ }
+
+ return (
+
+
Details
+ {chatDetail?.type === "group" ? renderGroup() : renderDirect()}
+
+ )
+}
+
+export default RightSideBar
diff --git a/exm-web/modules/chat/component/UserDetail.tsx b/exm-web/modules/chat/component/UserDetail.tsx
new file mode 100644
index 0000000000..a01d882e3e
--- /dev/null
+++ b/exm-web/modules/chat/component/UserDetail.tsx
@@ -0,0 +1,55 @@
+"use client"
+
+import { IUser } from "@/modules/auth/types"
+
+import { readFile } from "@/lib/utils"
+import Avatar from "@/components/ui/avatar"
+
+const UserDetail = ({ user }: { user: IUser }) => {
+ return (
+ <>
+
+
+
+
+
+ {user?.details?.fullName || user?.email}
+
+ {user?.details?.position ? (
+
+ {" "}
+ {user?.details?.position}
+
+ ) : null}
+
+
+
+
+
+
Email
+
{user?.email || "-"}
+
+
+
Phone
+
+ {user?.details?.operatorPhone || "-"}
+
+
+
+
Employee ID
+
{user?.employeeId || "-"}
+
+
+ >
+ )
+}
+
+export default UserDetail
diff --git a/exm-web/modules/chat/component/form/GroupChatAction.tsx b/exm-web/modules/chat/component/form/GroupChatAction.tsx
new file mode 100644
index 0000000000..14a8bbd84c
--- /dev/null
+++ b/exm-web/modules/chat/component/form/GroupChatAction.tsx
@@ -0,0 +1,81 @@
+"use client"
+
+import { useState } from "react"
+import Uploader from "@/modules/feed/component/form/uploader/Uploader"
+
+import { Button } from "@/components/ui/button"
+import {
+ DialogContent,
+ DialogHeader,
+ DialogTitle,
+} from "@/components/ui/dialog"
+import { Input } from "@/components/ui/input"
+import { Label } from "@/components/ui/label"
+import { AttachmentWithPreview } from "@/components/AttachmentWithPreview"
+
+import useChatsMutation from "../../hooks/useChatsMutation"
+import { IChat } from "../../types"
+
+export const GroupChatAction = ({
+ chat,
+ setOpen,
+}: {
+ chat: IChat
+ setOpen: (open: boolean) => void
+}) => {
+ const { chatEdit, loadingEdit } = useChatsMutation()
+
+ const [name, SetName] = useState(chat?.name || "")
+ const [featuredImage, setFeaturedImage] = useState(chat?.featuredImage || [])
+
+ const deleteImage = (index: number) => {
+ const updated = [...featuredImage]
+
+ updated.splice(index, 1)
+
+ setFeaturedImage(updated)
+ }
+
+ const editAction = () => {
+ chatEdit(chat._id, name, featuredImage)
+
+ if (!loadingEdit) {
+ setOpen(false)
+ }
+ }
+
+ return (
+ <>
+
+
+ Chat Item edit
+
+
+
+ SetName(e.target.value)}
+ />
+
+
+
+
+ {featuredImage && featuredImage.length > 0 && (
+
+ )}
+
+
+
+ >
+ )
+}
diff --git a/exm-web/modules/chat/hooks/useChatDetail.tsx b/exm-web/modules/chat/hooks/useChatDetail.tsx
new file mode 100644
index 0000000000..7d244c745b
--- /dev/null
+++ b/exm-web/modules/chat/hooks/useChatDetail.tsx
@@ -0,0 +1,29 @@
+import { useSearchParams } from "next/navigation"
+import { useQuery } from "@apollo/client"
+
+import { queries } from "../graphql"
+import { IChat } from "../types"
+
+export interface IUseChats {
+ loading: boolean
+ chatDetail: IChat
+}
+
+export const useChatDetail = (): IUseChats => {
+ const searchParams = useSearchParams()
+
+ const id = searchParams.get("id") as string
+
+ const { data, loading } = useQuery(queries.chatDetail, {
+ variables: { id },
+ })
+
+ const chatDetail = data ? (data || {}).chatDetail : {}
+
+ return {
+ loading,
+ chatDetail,
+ }
+}
+
+export const FETCH_MORE_PER_PAGE: number = 20
diff --git a/exm-web/modules/chat/hooks/useChatMessages.tsx b/exm-web/modules/chat/hooks/useChatMessages.tsx
index 1e09927078..4fcf295cfa 100644
--- a/exm-web/modules/chat/hooks/useChatMessages.tsx
+++ b/exm-web/modules/chat/hooks/useChatMessages.tsx
@@ -1,9 +1,6 @@
import { useEffect } from "react"
import { useSearchParams } from "next/navigation"
-import { currentUserAtom } from "@/modules/JotaiProiveder"
-import { IUser } from "@/modules/types"
import { useMutation, useQuery, useSubscription } from "@apollo/client"
-import { useAtomValue } from "jotai"
import { mutations, queries, subscriptions } from "../graphql"
import { IChatMessage } from "../types"
diff --git a/exm-web/modules/chat/hooks/useChatsMutation.tsx b/exm-web/modules/chat/hooks/useChatsMutation.tsx
index 1ad14d18bc..8ff1015420 100644
--- a/exm-web/modules/chat/hooks/useChatsMutation.tsx
+++ b/exm-web/modules/chat/hooks/useChatsMutation.tsx
@@ -19,15 +19,51 @@ const useChatsMutation = () => {
}
)
+ const [editChatMutation, { loading: loadingEdit }] = useMutation(
+ mutations.chatEdit
+ )
+
+ const [adminMutation] = useMutation(mutations.chatMakeOrRemoveAdmin)
+ const [memberMutation] = useMutation(mutations.chatAddOrRemoveMember)
+
const togglePinned = (chatId: string) => {
togglePinnedChat({
variables: { id: chatId },
})
}
+ const makeOrRemoveAdmin = (chatId: string, userId: string) => {
+ adminMutation({
+ variables: { id: chatId, userId },
+ refetchQueries: ["chats", "chatDetail"],
+ })
+ }
+
+ const chatEdit = (chatId: string, name?: string, featuredImage?: any[]) => {
+ editChatMutation({
+ variables: { _id: chatId, name, featuredImage },
+ refetchQueries: ["chats", "chatDetail"],
+ })
+ }
+
+ const addOrRemoveMember = (
+ chatId: string,
+ type: string,
+ userIds: string[]
+ ) => {
+ memberMutation({
+ variables: { id: chatId, type, userIds },
+ refetchQueries: ["chats", "chatDetail"],
+ })
+ }
+
return {
togglePinned,
+ makeOrRemoveAdmin,
+ addOrRemoveMember,
+ chatEdit,
loading,
+ loadingEdit,
}
}
diff --git a/exm-web/modules/chat/types.ts b/exm-web/modules/chat/types.ts
index 4f066e531f..59ded90c3a 100644
--- a/exm-web/modules/chat/types.ts
+++ b/exm-web/modules/chat/types.ts
@@ -16,7 +16,7 @@ export interface IChat {
name: string
type: string
isSeen: string
- featuredImage: string
+ featuredImage: any[]
createdAt: string
createdUser: IUser
participantUsers: IUser[]