diff --git a/exm-web/app/(main)/chats/detail/page.tsx b/exm-web/app/(main)/chats/detail/page.tsx index ba3eaf60f1..ccc52a82a3 100644 --- a/exm-web/app/(main)/chats/detail/page.tsx +++ b/exm-web/app/(main)/chats/detail/page.tsx @@ -1,15 +1,29 @@ +"use client" + +import { useState } from "react" import RightSideBar from "@/modules/chat/component/RightSideBar" import Messages from "@/modules/chat/component/messages/Messages" export default function Detail() { + const [showSidebar, setShowSidebar] = useState(false) + + const handleToggle = () => { + setShowSidebar(!showSidebar) + } + return ( <> -
- -
-
- +
+
+ {showSidebar && ( +
+ +
+ )} ) } diff --git a/exm-web/app/(main)/chats/layout.tsx b/exm-web/app/(main)/chats/layout.tsx index adb6454d64..2230b4266a 100644 --- a/exm-web/app/(main)/chats/layout.tsx +++ b/exm-web/app/(main)/chats/layout.tsx @@ -7,7 +7,7 @@ interface ILayoutProps { export default function ChatLayout({ children }: ILayoutProps) { return ( <> -
+
{children} diff --git a/exm-web/app/(main)/layout.tsx b/exm-web/app/(main)/layout.tsx index f180b74c3b..43df884a7f 100644 --- a/exm-web/app/(main)/layout.tsx +++ b/exm-web/app/(main)/layout.tsx @@ -13,7 +13,7 @@ export default function RootLayout({ children }: ILayoutProps) {
<> -
+
{children}
diff --git a/exm-web/components/AttachmentWithChatPreview.tsx b/exm-web/components/AttachmentWithChatPreview.tsx index b44a795e82..60c4cf856b 100644 --- a/exm-web/components/AttachmentWithChatPreview.tsx +++ b/exm-web/components/AttachmentWithChatPreview.tsx @@ -21,8 +21,8 @@ export const AttachmentWithChatPreview = ({ } return ( - ) @@ -102,13 +107,13 @@ export const FilePreview = ({ <> -
+
image
diff --git a/exm-web/components/hooks/useUsers.tsx b/exm-web/components/hooks/useUsers.tsx index ea651a23ad..2cc68e6f07 100644 --- a/exm-web/components/hooks/useUsers.tsx +++ b/exm-web/components/hooks/useUsers.tsx @@ -12,6 +12,7 @@ type IOption = { export interface IUseFeedDetail { loading: boolean userOptions: IOption[] + users: IUser[] } export const useUsers = ({ @@ -43,5 +44,6 @@ export const useUsers = ({ return { loading, userOptions, + users: users || [] } } diff --git a/exm-web/components/select/SelectUsers.tsx b/exm-web/components/select/SelectUsers.tsx index 2653d01144..264060a680 100644 --- a/exm-web/components/select/SelectUsers.tsx +++ b/exm-web/components/select/SelectUsers.tsx @@ -31,9 +31,14 @@ const SelectUsers = ({ return ( <> {loading && !reload && !searchValue ? ( - + ) : ( {
- <> - {renderPinnedChats()} - {renderChats()} - + {renderChats()} {!loading && chats.length < chatsCount && (
@@ -126,7 +207,7 @@ const ChatList = () => {
)}
- +
) } diff --git a/exm-web/modules/chat/component/GroupDetail.tsx b/exm-web/modules/chat/component/GroupDetail.tsx new file mode 100644 index 0000000000..44839fd302 --- /dev/null +++ b/exm-web/modules/chat/component/GroupDetail.tsx @@ -0,0 +1,227 @@ +"use client" + +import { useState } from "react" +import { currentUserAtom } from "@/modules/JotaiProiveder" +import { IUser } from "@/modules/auth/types" +import { useAtomValue } from "jotai" +import { Bell, BellOff, ChevronRight, LogOut } from "lucide-react" + +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog" +import Image from "@/components/ui/image" +import { useToast } from "@/components/ui/use-toast" + +import useChatsMutation from "../hooks/useChatsMutation" +import AddParticipant from "./AddParticipant" +import ParticipantList from "./ParticipantList" +import { GroupChatAction } from "./form/GroupChatAction" +import { PinnedMessages } from "./messages/PinnedMessages" + +const UserDetail = ({ + chatDetail, + setShowSidebar, +}: { + chatDetail: any + setShowSidebar: () => void +}) => { + const { toast } = useToast() + const callBack = (result: string) => { + if (result === "success") { + return toast({ + description: chatDetail.muteUserIds.includes(currentUser?._id) + ? "Unmuted chat" + : `Muted chat`, + }) + } + } + const { toggleMute } = useChatsMutation({ callBack }) + const [openMembers, setOpenMembers] = useState(false) + const [openChangeName, setOpenChangeName] = useState(false) + const [openChangeImage, setOpenChangeImage] = useState(false) + const currentUser = useAtomValue(currentUserAtom) + + const renderPinnedMessage = () => { + return + } + + const renderChatImage = (size?: string) => { + if (chatDetail && chatDetail.featuredImage.length > 0) { + return ( + avatar + ) + } + + return ( +
+ avatar + avatar +
+ ) + } + + const renderMembers = () => { + const memberNames = chatDetail.participantUsers.map( + (user: IUser) => (user.details.fullName || user.email) + "," + ) + + return ( + setOpenMembers(!openMembers)} + > + +
+
+
{renderChatImage("small")}
+
+

{chatDetail.participantUsers.length} members

+

+ {memberNames} +

+
+
+ +
+
+ + + + + {chatDetail.participantUsers.length} Members + + + + +
+ ) + } + + const renderNameChangeAction = () => { + return ( + setOpenChangeName(!openChangeName)} + > + +

+ {chatDetail.name} +

+
+ + +
+ ) + } + + const renderFeatureImageChangeAction = () => { + return ( + setOpenChangeImage(!openChangeImage)} + > + {renderChatImage()} + + + + ) + } + + const renderActions = () => { + const muted = chatDetail.muteUserIds.includes(currentUser?._id) + return ( +
+ +
+
toggleMute(chatDetail._id)} + > + {muted ? : } +
+ {muted ? "Unmute" : "Mute"} +
+
+
+ +
+ Leave +
+
+ ) + } + + return ( + <> +
setShowSidebar()} + > + +
+ +
+
+
+ {renderFeatureImageChangeAction()} +
+
+
+ + {renderNameChangeAction()} + {renderActions()} +
+ +
+ {renderMembers()} + {renderPinnedMessage()} +
+ + ) +} + +export default UserDetail diff --git a/exm-web/modules/chat/component/ParticipantItem.tsx b/exm-web/modules/chat/component/ParticipantItem.tsx index 2c46fa91b5..c4a71e255f 100644 --- a/exm-web/modules/chat/component/ParticipantItem.tsx +++ b/exm-web/modules/chat/component/ParticipantItem.tsx @@ -92,7 +92,7 @@ const ParticipantItem = ({ return ( -
+
@@ -122,7 +122,7 @@ const ParticipantItem = ({ } return ( -
+
@@ -135,7 +135,7 @@ const ParticipantItem = ({ alt="avatar" width={60} height={60} - className="w-12 h-12 rounded-full object-cover" + className="w-12 h-12 rounded-full object-cover border border-primary" />
@@ -143,9 +143,9 @@ const ParticipantItem = ({

{participant?.details?.fullName || participant?.email} + {participant.isAdmin ? " (Admin)" : ""}

- {participant.isAdmin ? "Admin " : ""} {participant?.details?.position || ""}

diff --git a/exm-web/modules/chat/component/ParticipantList.tsx b/exm-web/modules/chat/component/ParticipantList.tsx index 56f9d12f1c..ed188e8363 100644 --- a/exm-web/modules/chat/component/ParticipantList.tsx +++ b/exm-web/modules/chat/component/ParticipantList.tsx @@ -1,104 +1,39 @@ "use client" -import { useState } from "react" import { currentUserAtom } from "@/modules/JotaiProiveder" import { IUser } from "@/modules/auth/types" 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 LoadingPost from "@/components/ui/loadingPost" -import SelectUsers from "@/components/select/SelectUsers" - -import useChatsMutation from "../hooks/useChatsMutation" import { IChat } from "../types" +import AddParticipant from "./AddParticipant" import ParticipantItem from "./ParticipantItem" const ParticipantList = ({ chat }: { chat: IChat }) => { const currentUser = useAtomValue(currentUserAtom) || ({} as IUser) - const [userIds, setUserIds] = useState([] as any) - const [open, setOpen] = useState(false) - - const callBack = (result: string) => { - if (result === "success") { - setOpen(false) - } - } - - const { addOrRemoveMember, loading: mutationLoading } = useChatsMutation({ - callBack, - }) - - const addMember = () => { - setUserIds([]) - addOrRemoveMember(chat._id, "add", userIds) - } const isAdmin = (chat?.participantUsers || []).find( (pUser) => pUser._id === currentUser._id )?.isAdmin || false - const renderAdd = () => { - const renderForm = () => { - return ( - - - Add member - - - {mutationLoading ? : null} - - - - - - ) - } - - return ( - setOpen(!open)}> - -
-
- -
-
-

Add member

-
-
-
- - {open ? renderForm() : null} -
- ) - } - return ( -
- {chat.participantUsers.map((user: any, index: number) => ( - - ))} - - {isAdmin && renderAdd()} -
+ <> +
+
+ {chat.participantUsers.map((user: any, index: number) => ( + + ))} +
+
+
+ +
+ ) } diff --git a/exm-web/modules/chat/component/RightSideBar.tsx b/exm-web/modules/chat/component/RightSideBar.tsx index 8772ea348e..c99cf6f8f5 100644 --- a/exm-web/modules/chat/component/RightSideBar.tsx +++ b/exm-web/modules/chat/component/RightSideBar.tsx @@ -1,24 +1,22 @@ "use client" -import { useState } from "react" import { currentUserAtom } from "@/modules/JotaiProiveder" import { useAtomValue } from "jotai" -import { PenSquareIcon } from "lucide-react" - -import { Dialog, DialogTrigger } from "@/components/ui/dialog" -import Image from "@/components/ui/image" import { useChatDetail } from "../hooks/useChatDetail" -import ParticipantList from "./ParticipantList" +import GroupDetail from "./GroupDetail" import UserDetail from "./UserDetail" -import { GroupChatAction } from "./form/GroupChatAction" -const RightSideBar = () => { +const RightSideBar = ({ + setShowSidebar, + showSidebar, +}: { + setShowSidebar: () => void + showSidebar: boolean +}) => { const currentUser = useAtomValue(currentUserAtom) const { chatDetail, loading } = useChatDetail() - const [open, setOpen] = useState(false) - if (loading) { return null } @@ -29,61 +27,22 @@ const RightSideBar = () => { ? users?.filter((u) => u._id !== currentUser?._id)[0] : users?.[0] - const renderAction = () => { - return ( - setOpen(!open)}> - -
- -
-
- - -
- ) - } - const renderGroup = () => { return ( - <> -
-
-
-
- avatar -
-
- -

- {chatDetail.name} -

-
- {renderAction()} -
- - - + ) } const renderDirect = () => { - return + return } return ( -
-

Details

+
{chatDetail?.type === "group" ? renderGroup() : renderDirect()}
) diff --git a/exm-web/modules/chat/component/SharedFiles.tsx b/exm-web/modules/chat/component/SharedFiles.tsx new file mode 100644 index 0000000000..c46fe3e112 --- /dev/null +++ b/exm-web/modules/chat/component/SharedFiles.tsx @@ -0,0 +1,202 @@ +"use client" + +import { useState } from "react" +import { Link } from "lucide-react" + +import { readFile } from "@/lib/utils" +import { + Dialog, + DialogContent, + DialogHeader, + DialogTrigger, +} from "@/components/ui/dialog" +import Image from "@/components/ui/image" + +import { AttachmentWithPreview } from "../../../components/AttachmentWithPreview" + +const SharedFiles = () => { + const [activeTabIndex, setActiveTabIndex] = useState(0) + + const handleTabClick = (index: number) => { + setActiveTabIndex(index) + } + + const renderFileSize = (size: number) => { + if (size > 1000000) { + return <>({Math.round(size / 1000000)}MB) + } + if (size > 1000) { + return <>({Math.round(size / 1000)}kB) + } + } + + const renderDatas = (type: string, item: any) => { + if (type === "link") { + return ( + +
+ +
+
{item.src}
+
+ ) + } + + return ( + +
+ +
+
+

{item.name}

+

{renderFileSize(item.size)}

+
+
+ ) + } + + const attachments = [ + { + _id: "6537493773b63c941c44f033", + url: "0.7998292006692962Screenshot2023-10-17at12.17.32.png", + name: "Screenshot 2023-10-17 at 12.17.32.png", + size: 772101, + type: "image/png", + }, + { + _id: "6537493773b63c941c44f032", + url: "0.976131914500465Screenshot2023-10-19at17.51.45.png", + name: "Screenshot 2023-10-19 at 17.51.45.png", + size: 4384, + type: "image/png", + }, + { + _id: "6537493773b63c941c44f031", + url: "0.2742031156384068Screenshot2023-10-19at17.57.12.png", + name: "Screenshot 2023-10-19 at 17.57.12.png", + size: 4034, + type: "image/png", + }, + { + _id: "6537493773b63c941c44f030", + url: "0.12714214593478235Screenshot2023-10-19at17.57.17.png", + name: "Screenshot 2023-10-19 at 17.57.17.png", + size: 3997, + type: "image/png", + }, + { + _id: "6537493773b63c941c4", + url: "https://images.unsplash.com/photo-1697909623126-e2ecf6f66869?auto=format&fit=crop&q=80&w=2667&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", + name: "Screenshot 2023-10-19 at 17.57.17.png", + size: 3997, + type: "image/png", + }, + ] + + const renderMedia = () => { + return ( +
+ {attachments.map((att, index) => ( + + +
+ image +
+
+ + + + +
+ ))} +
+ ) + } + + const renderFiles = () => { + return [ + { + name: "payment.docx", + size: 32250, + type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + url: "0.09960727060171326payment.docx", + _id: "65373ffc73b63c941c44f02e", + }, + { + name: "payment.docx", + size: 32250, + type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + url: "0.09960727060171326payment.docx", + _id: "65373ffc73b63c941c44f02e", + }, + { + name: "payment.docx", + size: 32250, + type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + url: "0.09960727060171326payment.docx", + _id: "65373ffc73b63c941c44f02e", + }, + ].map((item) => renderDatas("file", item)) + } + + const renderLinks = () => { + return [ + { src: "https://office.erxes.io/" }, + { src: "https://fb.com/" }, + { src: "https://www.youtube.com/" }, + { src: "https://github.com/" }, + { src: "https://office.erxes.io/" }, + { src: "https://fb.com/" }, + { src: "https://www.youtube.com/" }, + { src: "https://github.com/" }, + { src: "https://office.erxes.io/" }, + { src: "https://fb.com/" }, + { src: "https://www.youtube.com/" }, + { src: "https://github.com/" }, + { src: "https://office.erxes.io/" }, + { src: "https://fb.com/" }, + { src: "https://www.youtube.com/" }, + { src: "https://github.com/" }, + ].map((item) => renderDatas("link", item)) + } + + return ( +
+
+ {["Media", "Files", "Links"].map((type, index) => ( + + ))} +
+
+ {activeTabIndex === 0 && renderMedia()} + {activeTabIndex === 1 && renderFiles()} + {activeTabIndex === 2 && renderLinks()} +
+
+ ) +} + +export default SharedFiles diff --git a/exm-web/modules/chat/component/UserDetail.tsx b/exm-web/modules/chat/component/UserDetail.tsx index 323a49b3a9..05f94d6d97 100644 --- a/exm-web/modules/chat/component/UserDetail.tsx +++ b/exm-web/modules/chat/component/UserDetail.tsx @@ -1,31 +1,41 @@ "use client" import { IUser } from "@/modules/auth/types" +import { ChevronRight } from "lucide-react" import Image from "@/components/ui/image" -const UserDetail = ({ user }: { user: IUser }) => { +import { PinnedMessages } from "./messages/PinnedMessages" + +const UserDetail = ({ user, setShowSidebar }: { user: IUser, setShowSidebar: () => void }) => { + const renderPinnedMessage = () => { + return + } + return ( <> -
+
setShowSidebar()}> + +
+
-
+
avatar
-

+

{user?.details?.fullName || user?.email}

{user?.details?.position ? ( - + {" "} {user?.details?.position} @@ -34,20 +44,29 @@ const UserDetail = ({ user }: { user: IUser }) => {
-
-

Email

+
+

Email

{user?.email || "-"}

-
-

Phone

+
+

Phone

{user?.details?.operatorPhone || "-"}

-
-

Employee ID

+
+

Employee ID

{user?.employeeId || "-"}

+
+

Departments

+ {/*

{departments.length === 0 ? "-" : departments[0]}

*/} +
+
+

Branches

+ {/*

{user?.branches || "-"}

*/} +
+ {renderPinnedMessage()}
) diff --git a/exm-web/modules/chat/component/form/ChatForm.tsx b/exm-web/modules/chat/component/form/ChatForm.tsx index 96ae85bfc7..aeb9880958 100644 --- a/exm-web/modules/chat/component/form/ChatForm.tsx +++ b/exm-web/modules/chat/component/form/ChatForm.tsx @@ -101,7 +101,6 @@ export const ChatForm = ({ name="userIds" render={({ field }) => ( - Select users ( - Group chat Name @@ -134,8 +133,8 @@ export const ChatForm = ({ /> ) : null} - diff --git a/exm-web/modules/chat/component/form/GroupChatAction.tsx b/exm-web/modules/chat/component/form/GroupChatAction.tsx index b5f7f58ea2..bd5a2f9c77 100644 --- a/exm-web/modules/chat/component/form/GroupChatAction.tsx +++ b/exm-web/modules/chat/component/form/GroupChatAction.tsx @@ -38,9 +38,11 @@ const FormSchema = z.object({ export const GroupChatAction = ({ chat, setOpen, + type, }: { chat: IChat setOpen: (open: boolean) => void + type: string }) => { const callBack = (result: string) => { if (result === "success") { @@ -86,6 +88,50 @@ export const GroupChatAction = ({ form.reset({ ...defaultValues }) }, [chat]) + const renderFormField = () => { + if (type === "name") { + return ( + ( + + + + + + + )} + /> + ) + } + + return ( + <> + {featuredImage && featuredImage.length === 0 && ( + + )} + + {featuredImage && featuredImage.length > 0 && ( + + )} + + ) + } + return ( @@ -95,41 +141,7 @@ export const GroupChatAction = ({ {loading ? : null}
- ( - - Group chat Name - - - - - - )} - /> - - {featuredImage && featuredImage.length === 0 && ( - - )} - - {featuredImage && featuredImage.length > 0 && ( - - )} - + {renderFormField()}