@pubuduth-aplicy/chat-ui 2.1.6 → 2.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/components/Chat.tsx +4 -3
- package/src/components/messages/Message.tsx +42 -39
- package/src/components/messages/MessageContainer.tsx +3 -3
- package/src/components/messages/MessageInput.tsx +15 -9
- package/src/components/messages/Messages.tsx +47 -44
- package/src/components/sidebar/Conversation.tsx +2 -2
- package/src/hooks/mutations/useSendMessage.ts +25 -0
- package/src/hooks/queries/useChatApi.ts +17 -10
- package/src/lib/api/endpoint.ts +3 -3
- package/src/service/messageService.ts +16 -0
package/package.json
CHANGED
package/src/components/Chat.tsx
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import useChatUIStore from '../stores/Zustant';
|
|
2
|
+
import MessageContainer from './messages/MessageContainer';
|
|
2
3
|
import { Sidebar } from './sidebar/Sidebar'
|
|
3
4
|
// import MessageContainer from './components/messages/MessageContainer'
|
|
4
5
|
// import useConversation from '../../zustand/useConversation';
|
|
@@ -6,7 +7,7 @@ import { Sidebar } from './sidebar/Sidebar'
|
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
export const Chat = () => {
|
|
9
|
-
const { selectedConversation
|
|
10
|
+
const { selectedConversation } = useChatUIStore();
|
|
10
11
|
return (
|
|
11
12
|
<>
|
|
12
13
|
<div className='container mx-auto mb-5'>
|
|
@@ -16,14 +17,14 @@ export const Chat = () => {
|
|
|
16
17
|
<>
|
|
17
18
|
<div className={`xs:hidden md:grid md:col-span-3 border max-h-screen overflow-y-auto`}><Sidebar /></div>
|
|
18
19
|
<div className='md:col-span-4 border max-h-screen overflow-y-auto '>
|
|
19
|
-
|
|
20
|
+
<MessageContainer />
|
|
20
21
|
</div>
|
|
21
22
|
</>
|
|
22
23
|
) : (
|
|
23
24
|
<>
|
|
24
25
|
<div className='md:col-span-3 border max-h-screen overflow-y-auto '><Sidebar /></div>
|
|
25
26
|
<div className='xs:hidden md:grid md:col-span-4 border '>
|
|
26
|
-
|
|
27
|
+
<MessageContainer />
|
|
27
28
|
</div>
|
|
28
29
|
</>
|
|
29
30
|
)}
|
|
@@ -1,39 +1,42 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
//
|
|
7
|
-
|
|
8
|
-
//
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
|
+
|
|
3
|
+
import { useChatContext } from "../../providers/ChatProvider";
|
|
4
|
+
import useChatUIStore from "../../stores/Zustant";
|
|
5
|
+
|
|
6
|
+
// import { useAuthContext } from "../../context/AuthContext";
|
|
7
|
+
// import { extractTime } from "../../utils/extractTime";
|
|
8
|
+
// import useConversation from "../../zustand/useConversation";
|
|
9
|
+
interface MessageProps {
|
|
10
|
+
message: {
|
|
11
|
+
senderId: string;
|
|
12
|
+
message: string;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const Message = ({ message }: MessageProps) => {
|
|
17
|
+
|
|
18
|
+
const { userId } = useChatContext();
|
|
19
|
+
const fromMe = message.senderId === userId;
|
|
20
|
+
const bubbleBgColor = fromMe ? "bg-green-400" : "bg-blue-700";
|
|
21
|
+
const alignItems = fromMe ? "float-right" : "float-left";
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<>
|
|
26
|
+
<div className='flex-grow px-8 pt-8 max-h-screen text-left text-gray-700 overflow-y-auto'>
|
|
27
|
+
<div className="relative mb-6 text-left">
|
|
28
|
+
<div className="text-gray-700">
|
|
29
|
+
<div className={`relative ${alignItems} block rounded-md ${bubbleBgColor} py-3 px-4 text-white break-all overflow-wrap`}>
|
|
30
|
+
<p className="text-sm">{message.message}</p>
|
|
31
|
+
<div className='chat-footer opacity-50 text-xs flex gap-1 items-center float-right'>15.00</div>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
{/* <div className="clear-both flex text-gray-700" /> */}
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
</>
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export default Message
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useEffect } from "react";
|
|
2
2
|
// import useConversation from "../../zustand/useConversation";
|
|
3
3
|
import MessageInput from "./MessageInput";
|
|
4
|
-
|
|
4
|
+
import Messages from "./Messages";
|
|
5
5
|
import useChatUIStore from "../../stores/Zustant";
|
|
6
6
|
// import { Chat, CaretLeft } from "@phosphor-icons/react";
|
|
7
7
|
// import { useAuthContext } from "../../context/AuthContext";
|
|
@@ -31,7 +31,7 @@ const MessageContainer = () => {
|
|
|
31
31
|
<div className="grow shrink basis-0 flex-col justify-start items-start gap-1 inline-flex">
|
|
32
32
|
<div className="self-stretch justify-start items-center inline-flex">
|
|
33
33
|
<div className="grow shrink basis-0 text-slate-900 text-base font-semibold font-inter leading-tight">
|
|
34
|
-
{selectedConversation.
|
|
34
|
+
{selectedConversation.firstname}
|
|
35
35
|
</div>
|
|
36
36
|
</div>
|
|
37
37
|
</div>
|
|
@@ -57,7 +57,7 @@ const MessageContainer = () => {
|
|
|
57
57
|
</div>
|
|
58
58
|
</div> */}
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
<Messages />
|
|
61
61
|
<MessageInput />
|
|
62
62
|
</>
|
|
63
63
|
)}
|
|
@@ -1,21 +1,27 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
|
+
import { useMessageMutation } from '../../hooks/mutations/useSendMessage';
|
|
3
|
+
import { useChatContext } from '../../providers/ChatProvider';
|
|
4
|
+
import useChatUIStore from '../../stores/Zustant';
|
|
2
5
|
// import { PaperPlaneRight } from '@phosphor-icons/react'; // Assuming you're using icons from Phosphor Icons library
|
|
3
6
|
// import useSendMessage from '../../hooks/useSendMessage'; // Importing the useSendMessage hook
|
|
4
7
|
|
|
5
8
|
const MessageInput = () => {
|
|
9
|
+
const { socket, userId } = useChatContext();
|
|
10
|
+
const { selectedConversation } = useChatUIStore();
|
|
6
11
|
const [message, setMessage] = useState(""); // State for storing the message input
|
|
7
|
-
|
|
12
|
+
const { mutate: sendMessage } = useMessageMutation();
|
|
8
13
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
const handleSubmit = async (e) => {
|
|
15
|
+
e.preventDefault();
|
|
16
|
+
if (!message)
|
|
17
|
+
return;
|
|
18
|
+
sendMessage({selectedConversation?._id,message});
|
|
19
|
+
socket.emit('sendMessage', { selectedConversation._id, message })
|
|
20
|
+
setMessage("");
|
|
21
|
+
};
|
|
16
22
|
|
|
17
23
|
return (
|
|
18
|
-
<form className='px-4 my-3 sticky bottom-0'>
|
|
24
|
+
<form className='px-4 my-3 sticky bottom-0' onSubmit={handleSubmit}>
|
|
19
25
|
|
|
20
26
|
<div className='w-full '>
|
|
21
27
|
<input
|
|
@@ -1,51 +1,54 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
//
|
|
4
|
-
// import
|
|
5
|
-
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import { useEffect, useRef } from "react";
|
|
3
|
+
// import useGetMessages from "../../hooks/useGetMessages";
|
|
4
|
+
// import MessageSkeleton from "../skeletons/MessageSkeleton";
|
|
5
|
+
import Message from "./Message";
|
|
6
|
+
import { useChatContext } from "../../providers/ChatProvider";
|
|
7
|
+
import { useMessages } from "../../hooks/queries/useChatApi";
|
|
8
|
+
// import useListenMessages from "../../hooks/useListenMessages";
|
|
6
9
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
//
|
|
10
|
+
const Messages = () => {
|
|
11
|
+
const { userId } = useChatContext();
|
|
12
|
+
const { data: messages } = useMessages(userId);
|
|
13
|
+
// useListenMessages();
|
|
14
|
+
const lastMessageRef = useRef<HTMLDivElement>(null);
|
|
11
15
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
setTimeout(() => {
|
|
18
|
+
lastMessageRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
19
|
+
}, 100);
|
|
20
|
+
}, [messages]);
|
|
17
21
|
|
|
18
|
-
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
//
|
|
22
|
+
return (
|
|
23
|
+
// <div className='px-4 flex-1 overflow-auto'>
|
|
24
|
+
// {!loading &&
|
|
25
|
+
// messages.length > 0 &&
|
|
26
|
+
// messages.map((message) => (
|
|
27
|
+
// <div key={message._id} ref={lastMessageRef}>
|
|
28
|
+
// <Message message={message} />
|
|
29
|
+
// </div>
|
|
30
|
+
// ))}
|
|
27
31
|
|
|
28
|
-
//
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
//
|
|
32
|
-
//
|
|
32
|
+
// {loading && [...Array(3)].map((_, idx) => <MessageSkeleton key={idx} />)}
|
|
33
|
+
// {!loading && messages.length === 0 && (
|
|
34
|
+
// <p className='text-center'>Send a message to start the conversation</p>
|
|
35
|
+
// )}
|
|
36
|
+
// </div>
|
|
33
37
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
// {/* // ))} */}
|
|
38
|
+
<div className='px-4 flex-1 overflow-auto sm:px-6 lg:px-8'>
|
|
39
|
+
{messages.length > 0 &&
|
|
40
|
+
messages.map((message:any) => (
|
|
41
|
+
<div key={message._id} ref={lastMessageRef}>
|
|
42
|
+
<Message message={message} />
|
|
43
|
+
</div>
|
|
44
|
+
))}
|
|
42
45
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
{/* {loading && [...Array(3)].map((_, idx) => <MessageSkeleton key={idx} />)} */}
|
|
47
|
+
{messages.length === 0 && (
|
|
48
|
+
<p className='text-center'>Send a message to start the conversation</p>
|
|
49
|
+
)}
|
|
50
|
+
</div>
|
|
51
|
+
);
|
|
52
|
+
};
|
|
53
|
+
export default Messages;
|
|
51
54
|
|
|
@@ -28,12 +28,12 @@ console.log(conversation);
|
|
|
28
28
|
>
|
|
29
29
|
<img
|
|
30
30
|
className="w-12 h-12 relative rounded-[100px]"
|
|
31
|
-
src={conversation.profilePic}
|
|
31
|
+
src={conversation.profilePic|| conversation.idpic}
|
|
32
32
|
/>
|
|
33
33
|
<div className="grow shrink basis-0 flex-col justify-start items-start gap-1 inline-flex">
|
|
34
34
|
<div className="self-stretch justify-start items-center inline-flex">
|
|
35
35
|
<div className="grow shrink basis-0 text-slate-900 text-base font-semibold font-['Inter'] leading-tight">
|
|
36
|
-
{conversation.
|
|
36
|
+
{conversation.firstname}
|
|
37
37
|
</div>
|
|
38
38
|
</div>
|
|
39
39
|
</div>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
3
|
+
import { sendMessage } from "../../service/messageService";
|
|
4
|
+
|
|
5
|
+
export const useMessageMutation = () => {
|
|
6
|
+
const queryClient = useQueryClient();
|
|
7
|
+
return useMutation({
|
|
8
|
+
mutationFn: sendMessage,
|
|
9
|
+
onSuccess: () => {
|
|
10
|
+
console.log("Service submitted successfully!", "success");
|
|
11
|
+
queryClient.invalidateQueries({ queryKey: ['GET_ALL_CONVERSATION'] });
|
|
12
|
+
},
|
|
13
|
+
onError: (error: any) => {
|
|
14
|
+
console.error("Failed to submit service data:", error);
|
|
15
|
+
|
|
16
|
+
const errorMessage =
|
|
17
|
+
error?.response?.data?.errors[0]?.msg ||
|
|
18
|
+
"An error occurred while submitting service data.";
|
|
19
|
+
|
|
20
|
+
console.log("useSumbitServiceMutation :", errorMessage);
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
|
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
import { useQuery } from "@tanstack/react-query";
|
|
3
3
|
import { getAllConversationData } from "../../service/sidebarApi";
|
|
4
|
+
import { fetchMessages } from "../../service/messageService";
|
|
4
5
|
|
|
5
6
|
|
|
6
|
-
export const useGetConversations = (id:any) => {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
7
|
+
export const useGetConversations = (id: any) => {
|
|
8
|
+
return useQuery({
|
|
9
|
+
queryKey: ['GET_ALL_CONVERSATION', id],
|
|
10
|
+
queryFn: () =>
|
|
11
|
+
id ? getAllConversationData(id) : Promise.reject("No ID provided"),
|
|
12
|
+
staleTime: 1 * 60 * 1000,
|
|
13
|
+
enabled: !!id,
|
|
14
|
+
refetchOnWindowFocus: false,
|
|
15
|
+
});
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const useMessages = (chatId: string) => {
|
|
19
|
+
return useQuery({
|
|
20
|
+
queryKey:['messages', chatId],
|
|
21
|
+
queryFn: () => fetchMessages(chatId)});
|
|
22
|
+
};
|
package/src/lib/api/endpoint.ts
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import { apiClient } from "../lib/api/apiClient";
|
|
3
|
+
import { Path } from "../lib/api/endpoint";
|
|
4
|
+
|
|
5
|
+
export const sendMessage = async ({ chatId, message }: { chatId: any; message: string }) => {
|
|
6
|
+
const response = await apiClient.post(`${Path.sendmessage}/${chatId}`, {
|
|
7
|
+
message
|
|
8
|
+
})
|
|
9
|
+
return response.data;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
export const fetchMessages = async (chatId: string) => {
|
|
14
|
+
const response = await apiClient.get(`${Path.getconversation}/${chatId}`);
|
|
15
|
+
return response.data();
|
|
16
|
+
};
|