@pubuduth-aplicy/chat-ui 2.1.51 → 2.1.53

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.
@@ -51,7 +51,22 @@ const Messages = () => {
51
51
  const handleNewMessage = (newMessage: any) => {
52
52
  newMessage.shouldShake = true;
53
53
  console.log("📩 New message received:", newMessage);
54
- setMessages((prevMessages) => [...prevMessages, newMessage[1]]);
54
+ // setMessages((prevMessages) => [...prevMessages, newMessage[1]]);
55
+ setMessages(prevMessages => {
56
+ console.log("prevMessages", prevMessages);
57
+
58
+ const isDuplicate = prevMessages.some(msg =>
59
+ msg._id === newMessage[1]._id ||
60
+ (msg.isOptimistic && msg.senderId === userId && msg.message === newMessage[1].message)
61
+ );
62
+ console.log('isDuplicate', isDuplicate);
63
+
64
+ if (isDuplicate) {
65
+ return prevMessages;
66
+ }
67
+
68
+ return [...prevMessages, newMessage[1]];
69
+ });
55
70
  };
56
71
 
57
72
  // const handleNewMessage = (newMessage: any) => {
@@ -72,7 +87,7 @@ const Messages = () => {
72
87
  status: string;
73
88
  }) => {
74
89
  setMessages((prev) =>
75
- prev.map((msg) => (msg.id === messageId ? { ...msg, status } : msg))
90
+ prev.map((msg) => (msg._id === messageId ? { ...msg, status } : msg))
76
91
  );
77
92
  };
78
93
 
@@ -1,3 +1,4 @@
1
+ /* eslint-disable @typescript-eslint/no-unused-vars */
1
2
  // import { useSocketContext } from "../../context/SocketContext";
2
3
  // import useConversation from "../../zustand/useConversation";
3
4
 
@@ -12,7 +12,29 @@ const Conversations = () => {
12
12
  // const { loading, conversations } = useGetConversations();
13
13
  return (
14
14
  <div className="chatSidebarConversations">
15
- <h2 className="text-lg font-semibold text-gray-700">All Chats</h2>
15
+ <h2 className="text-lg font-semibold text-gray-700">All Messages</h2>
16
+ {(!conversations || conversations.length === 0) && (
17
+ <div className="flex flex-col items-center justify-center p-8 text-center">
18
+ <div className="flex h-16 w-16 items-center justify-center rounded-full bg-gray-100 mb-4">
19
+ <svg
20
+ xmlns="http://www.w3.org/2000/svg"
21
+ width="32"
22
+ height="32"
23
+ viewBox="0 0 24 24"
24
+ fill="none"
25
+ stroke="currentColor"
26
+ strokeWidth="2"
27
+ strokeLinecap="round"
28
+ strokeLinejoin="round"
29
+ className="text-gray-500"
30
+ >
31
+ <path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z" />
32
+ </svg>
33
+ </div>
34
+ <h3 className="text-xl font-semibold mb-1">No Conversations</h3>
35
+ <p className="text-gray-500 text-sm mb-4">There are no conversations under &quot;All messages&quot;</p>
36
+ </div>
37
+ )}
16
38
  {conversations?.map((conversation: any, idx: any) => (
17
39
  <Conversation
18
40
  key={conversation._id}
@@ -21,9 +43,11 @@ const Conversations = () => {
21
43
  />
22
44
  ))}
23
45
 
46
+
47
+
24
48
  {/* {loading ? <span className='loading loading-spinner mx-auto'></span> : null} */}
25
49
  </div>
26
50
  );
27
51
  };
28
52
 
29
- export default Conversations;
53
+ export default Conversations;
@@ -22,12 +22,20 @@ const {userId} =useChatContext()
22
22
  return
23
23
  }
24
24
 
25
- const conversation = data?.find((c: { _id: string; participantDetails: { username: string } }) =>
25
+ const conversation = data?.find((c: { _id: string; participantDetails: { username: string; firstname?: string; idpic?: string } }) =>
26
26
  c.participantDetails.username.toLowerCase().includes(search.toLowerCase())
27
27
  );
28
28
 
29
29
  if (conversation) {
30
- setSelectedConversation(conversation);
30
+ const updatedConversation = {
31
+ ...conversation,
32
+ participantDetails: {
33
+ ...conversation.participantDetails,
34
+ firstname: conversation.participantDetails.username || "Unknown",
35
+ idpic: conversation.participantDetails.profilePic || "default-idpic.png",
36
+ },
37
+ };
38
+ setSelectedConversation(updatedConversation);
31
39
  setSearch("");
32
40
  }
33
41
  console.error("No such user found!");
@@ -50,6 +58,10 @@ const {userId} =useChatContext()
50
58
  </div>
51
59
  </form>
52
60
  </>
61
+
62
+
63
+
64
+
53
65
  )
54
66
  }
55
67
 
@@ -2,12 +2,11 @@ import Conversations from "./Conversations";
2
2
  import SearchInput from "./SearchInput";
3
3
 
4
4
  export const Sidebar = () => {
5
- return (
6
- <div className='chatSidebarMain'>
5
+ return (
6
+ <div className=''>
7
7
  <SearchInput />
8
8
  <div className='divider px-3'></div>
9
9
  <Conversations />
10
-
11
- </div>
12
- )
10
+ </div>
11
+ )
13
12
  }
@@ -1,11 +1,15 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { FileType } from "../components/common/FilePreview";
2
3
  import { getApiClient } from "../lib/api/apiClient";
3
4
  import { Path } from "../lib/api/endpoint";
4
5
 
5
- export const sendMessage = async ({ chatId,senderId, message }: { chatId: any; senderId:any; message: string }) => {
6
+ export const sendMessage = async ({ chatId,senderId, message,attachments }: { chatId: any; senderId:any; message: string,attachments: { type: FileType; url: string; name: string; size: number; }[] }) => {
6
7
  const apiClient = getApiClient();
8
+ console.log("sendMessage", chatId, senderId, message, attachments); // Log the parameters
9
+
7
10
  const response = await apiClient.post(`${Path.sendmessage}/${chatId}/${senderId}`, {
8
- message:message
11
+ message:message,
12
+ attachments:attachments
9
13
  })
10
14
  return response.data;
11
15
  };
@@ -1,4 +1,5 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { FileType } from "../components/common/FilePreview";
2
3
  import { create } from "zustand";
3
4
 
4
5
  interface ChatUIState {
@@ -16,7 +17,23 @@ interface ChatUIState {
16
17
  setSelectedConversation: (
17
18
  selectedConversation: ChatUIState["selectedConversation"]
18
19
  ) => void;
19
- messages: { id: string; text: string; sender: string; status: string }[];
20
+ messages: {
21
+ _id: string;
22
+ text: string;
23
+ senderId: string;
24
+ status: string ;
25
+ isOptimistic:boolean;
26
+ message:string;
27
+ createdAt: string;
28
+ media: {
29
+ type: FileType;
30
+ url: string;
31
+ name: string;
32
+ size: number;
33
+ uploadProgress: number;
34
+ uploadError:string
35
+ }[];
36
+ isUploading: boolean;}[];
20
37
  setMessages: (messages: ChatUIState["messages"] | ((prev: ChatUIState["messages"]) => ChatUIState["messages"])) => void;
21
38
  updateMessageStatus: (messageId: string, status: string) => void;
22
39
  toggleChat: () => void;
@@ -38,7 +55,7 @@ const useChatUIStore = create<ChatUIState>((set) => ({
38
55
  updateMessageStatus: (messageId, status) =>
39
56
  set((state) => ({
40
57
  messages: state.messages.map((msg) =>
41
- msg.id === messageId ? { ...msg, status } : msg
58
+ msg._id === messageId ? { ...msg, status } : msg
42
59
  ),
43
60
  })),
44
61
  setSelectedConversation: (selectedConversation) => set({ selectedConversation }),
@@ -50,8 +50,8 @@
50
50
  display: flex;
51
51
  padding-top: 0.5rem;
52
52
  padding-bottom: 0.5rem;
53
+ width: 100%;
53
54
  padding-left: 1rem;
54
- padding-right: 1rem;
55
55
  /* flex-basis: 0px; */
56
56
  shrink: 1;
57
57
  gap: 1rem;
@@ -453,6 +453,10 @@ font-size: 12px;
453
453
  color: blue;
454
454
  }
455
455
 
456
+ .text-sm{
457
+ font-size: .875rem;
458
+ }
459
+
456
460
  /* @media (min-width: 640px) {
457
461
  .grid-container {
458
462
  height: 450px;
@@ -476,7 +480,7 @@ color: blue;
476
480
 
477
481
  @media (min-width: 768px) {
478
482
  .grid-container {
479
- /* height: 550px; */
483
+ height: 550px;
480
484
  grid-template-columns: repeat(9, minmax(0, 1fr));
481
485
  }
482
486
 
@@ -744,8 +748,9 @@ align-items: center;
744
748
  gap: 12px;
745
749
  padding: 12px;
746
750
  border-radius: 8px;
751
+ border-bottom: .5px solid lightgray;
747
752
  background-color: white;
748
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
753
+ /* box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); */
749
754
  cursor: pointer;
750
755
  transition: background-color 0.3s ease-in-out;
751
756
  }
@@ -842,7 +847,7 @@ background-color: #ccc;
842
847
  margin-bottom: 10px;
843
848
  }
844
849
 
845
- .file-preview {
850
+ /*.file-preview {
846
851
  position: relative;
847
852
  width: 120px;
848
853
  height: 120px;
@@ -850,8 +855,67 @@ background-color: #ccc;
850
855
  overflow: hidden;
851
856
  background: #f5f5f5;
852
857
  border: 1px solid #eaeaea;
858
+ }*/
859
+
860
+ .file-preview {
861
+ position: relative;
862
+ width: 246px;
863
+ height: 140px; /* Increased height to accommodate filename */
864
+ border-radius: 12px;
865
+ overflow: hidden;
866
+ background: linear-gradient(135deg, #f9f9f9, #e9ecef);
867
+ border: 1px solid #dcdcdc;
868
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05);
869
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
870
+ display: flex;
871
+ flex-direction: column;
872
+ align-items: center;
873
+ justify-content: space-between;
874
+ cursor: pointer;
875
+ padding: 8px;
876
+ }
877
+
878
+ .file-preview:hover {
879
+ transform: scale(1.03);
880
+ box-shadow: 0 6px 14px rgba(0, 0, 0, 0.1);
881
+ }
882
+
883
+ .file-preview img,
884
+ .file-preview video,
885
+ .file-preview .file-icon {
886
+ width: 100%;
887
+ height: 90px;
888
+ object-fit: cover;
889
+ border-radius: 8px;
890
+ }
891
+ .file-preview-document span,
892
+ .file-name {
893
+ display: block;
894
+ font-size: 13px;
895
+ font-weight: 500;
896
+ color: #333;
897
+ overflow: hidden;
898
+ text-overflow: ellipsis;
899
+ white-space: nowrap;
900
+ max-width: 100%;
901
+ line-height: 1.2;
902
+ text-align: center;
903
+ padding: 0 4px;
853
904
  }
854
905
 
906
+ /* Filename text styling */
907
+ .file-preview .filename {
908
+ margin-top: 6px;
909
+ font-size: 12px;
910
+ color: #333;
911
+ text-align: center;
912
+ width: 100%;
913
+ white-space: nowrap;
914
+ overflow: hidden;
915
+ text-overflow: ellipsis;
916
+ }
917
+
918
+
855
919
  .file-preview-content {
856
920
  width: 100%;
857
921
  height: 100%;
@@ -894,11 +958,11 @@ background-color: #ccc;
894
958
  white-space: nowrap;
895
959
  }
896
960
 
897
- .file-name {
961
+ /*.file-name {
898
962
  display: block;
899
963
  overflow: hidden;
900
964
  text-overflow: ellipsis;
901
- }
965
+ }*/
902
966
 
903
967
  .file-size {
904
968
  color: #777;
@@ -974,3 +1038,198 @@ background-color: #ccc;
974
1038
  .attachment-options button:hover {
975
1039
  background: #f5f5f5;
976
1040
  }
1041
+
1042
+
1043
+ .media-grid {
1044
+ display: grid;
1045
+ gap: 0.5rem;
1046
+ /* margin-top: 0.5rem; */
1047
+ }
1048
+
1049
+ .media-item {
1050
+ background: #f3f4f6;
1051
+ border-radius: 0.375rem; /* reduced from 0.75rem */
1052
+ padding: 0.5rem;
1053
+ overflow: hidden;
1054
+ display: flex;
1055
+ flex-direction: column;
1056
+ align-items: start;
1057
+ width: 246px;
1058
+ }
1059
+
1060
+ .media-content{
1061
+ width: 100%;
1062
+ object-fit: cover;
1063
+ }
1064
+
1065
+ .media-preview {
1066
+ max-width: 100%;
1067
+ max-height: 200px;
1068
+ border-radius: 0.375rem; /* reduced from 0.5rem */
1069
+ object-fit: cover;
1070
+ }
1071
+
1072
+ .download-button {
1073
+ font-size: 0.75rem;
1074
+ color: #3b82f6;
1075
+ margin-top: 0.25rem;
1076
+ text-decoration: underline;
1077
+ }
1078
+
1079
+ .file-link {
1080
+ font-weight: bold;
1081
+ color: #1f2937;
1082
+ margin-top: 0.25rem;
1083
+ }
1084
+
1085
+ .chat-bubble {
1086
+ background-color: #e5e7eb;
1087
+ /* padding: 0.5rem 0.75rem; */
1088
+ border-radius: 0.375rem;
1089
+ margin-top: 0.5rem;
1090
+ max-width: 100%;
1091
+ word-break: break-word;
1092
+ }
1093
+
1094
+ .download-btn {
1095
+ font-size: 0.75rem;
1096
+ color: #3b82f6;
1097
+ margin-top: 0.25rem;
1098
+ background: none;
1099
+ border: none;
1100
+ cursor: pointer;
1101
+ }
1102
+
1103
+ .download-btn:disabled {
1104
+ cursor: wait;
1105
+ opacity: 0.6;
1106
+ }
1107
+
1108
+ .document-preview {
1109
+ position: relative;
1110
+ width: 246px;
1111
+ height: 60px; /* Increased height to accommodate filename */
1112
+ border-radius: 12px;
1113
+ overflow: hidden;
1114
+ background: linear-gradient(135deg, #f9f9f9, #e9ecef);
1115
+ border: 1px solid #dcdcdc;
1116
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05);
1117
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
1118
+ display: flex;
1119
+ /* flex-direction: column; */
1120
+ align-items: center;
1121
+ /* justify-content: space-between; */
1122
+ cursor: pointer;
1123
+ padding: 8px;
1124
+ }
1125
+
1126
+
1127
+ /* Spinner loader */
1128
+ .loader {
1129
+ width: 16px;
1130
+ height: 16px;
1131
+ border: 2px solid #3b82f6;
1132
+ border-top: 2px solid transparent;
1133
+ border-radius: 50%;
1134
+ animation: spin 0.8s linear infinite;
1135
+ display: inline-block;
1136
+ vertical-align: middle;
1137
+ }
1138
+
1139
+ @keyframes spin {
1140
+ 0% { transform: rotate(0deg); }
1141
+ 100% { transform: rotate(360deg); }
1142
+ }
1143
+
1144
+
1145
+ /* Add these styles to your CSS file */
1146
+ .download-progress-container {
1147
+ position: relative;
1148
+ width: 24px;
1149
+ height: 24px;
1150
+ border-radius: 50%;
1151
+ background: rgba(0, 0, 0, 0.1);
1152
+ overflow: hidden;
1153
+ display: flex;
1154
+ align-items: center;
1155
+ justify-content: center;
1156
+ }
1157
+
1158
+ .download-progress {
1159
+ position: absolute;
1160
+ left: 0;
1161
+ bottom: 0;
1162
+ height: 100%;
1163
+ background: #2196f3;
1164
+ z-index: 1;
1165
+ }
1166
+
1167
+ .cancel-download {
1168
+ position: relative;
1169
+ z-index: 2;
1170
+ color: white;
1171
+ font-size: 12px;
1172
+ }
1173
+
1174
+ /* Existing styles for your chat component */
1175
+ .media-item {
1176
+ position: relative;
1177
+ }
1178
+
1179
+ .download-btn {
1180
+ /* position: absolute; */
1181
+ bottom: 8px;
1182
+ right: 8px;
1183
+ width: 30px;
1184
+ height: 30px;
1185
+ border-radius: 50%;
1186
+ background: rgba(255, 255, 255, 0.8);
1187
+ border: none;
1188
+ display: flex;
1189
+ align-items: center;
1190
+ justify-content: center;
1191
+ cursor: pointer;
1192
+ transition: all 0.2s ease;
1193
+ }
1194
+
1195
+ .download-btn:hover {
1196
+ background: rgba(255, 255, 255, 1);
1197
+ }
1198
+
1199
+
1200
+
1201
+ /* Blurred background preview */
1202
+ .media-preview-background {
1203
+ position: absolute;
1204
+ top: 0;
1205
+ left: 0;
1206
+ width: 100%;
1207
+ height: 100%;
1208
+ overflow: hidden;
1209
+ }
1210
+
1211
+
1212
+ /* Circular progress container (updated to be on top of blurred background) */
1213
+ .circular-progress-container {
1214
+ position: relative;
1215
+ display: flex;
1216
+ justify-content: center;
1217
+ align-items: center;
1218
+ width: 100%;
1219
+ height: 100%;
1220
+ }
1221
+
1222
+ /* Error message (on top of blurred background) */
1223
+ .upload-error {
1224
+ position: relative;
1225
+ display: flex;
1226
+ justify-content: center;
1227
+ align-items: center;
1228
+ width: 100%;
1229
+ height: 100%;
1230
+ color: #f44336;
1231
+ font-weight: bold;
1232
+ background-color: rgba(0, 0, 0, 0.3);
1233
+ }
1234
+
1235
+ /* Rest of the CSS remains the same as previous implementation */
package/src/types/type.ts CHANGED
@@ -69,4 +69,4 @@ export interface ConversationProps {
69
69
  lastIdx: boolean;
70
70
  }
71
71
 
72
- export type MessageStatus = 'sent' | 'delivered' | 'read';
72
+ export type MessageStatus = 'sent' | 'delivered' | 'read' | 'sending' | 'failed';