@pubuduth-aplicy/chat-ui 2.1.71 → 2.1.74

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.
@@ -3,73 +3,98 @@ import { FileType } from "../components/common/FilePreview";
3
3
  import { getApiClient } from "../lib/api/apiClient";
4
4
  import { Path } from "../lib/api/endpoint";
5
5
 
6
- export const sendMessage = async ({ chatId,senderId, message,attachments }: { chatId: any; senderId:any; message: string,attachments: { type: FileType; url: string; name: string; size: number; }[] }) => {
7
- const apiClient = getApiClient();
8
- console.log("sendMessage", chatId, senderId, message, attachments); // Log the parameters
9
-
10
- const response = await apiClient.post(`${Path.sendmessage}/${chatId}/${senderId}`, {
11
- message:message,
12
- attachments:attachments
13
- })
14
- return response.data;
6
+ export const sendMessage = async (params: {
7
+ receiverId: string;
8
+ senderId: string;
9
+ message: string;
10
+ attachments: { type: FileType; url: string; name: string; size: number }[];
11
+ bookingId?: string;
12
+ serviceTitle?: string;
13
+ type?: "personal" | "service";
14
+ serviceId?: string;
15
+ }) => {
16
+ const {
17
+ receiverId,
18
+ senderId,
19
+ message,
20
+ attachments,
21
+ bookingId,
22
+ serviceTitle,
23
+ type,
24
+ serviceId,
25
+ } = params;
26
+ const apiClient = getApiClient();
27
+
28
+ const response = await apiClient.post(
29
+ `${Path.sendmessage}/${receiverId}/${senderId}`,
30
+ {
31
+ message,
32
+ attachments,
33
+ bookingId,
34
+ serviceTitle,
35
+ type,
36
+ serviceId,
37
+ }
38
+ );
39
+ return response.data;
15
40
  };
16
41
 
17
42
 
18
- export const fetchMessages = async (chatId: string|undefined, userid: string,pagenum:number) => {
19
- const apiClient = getApiClient();
20
- try {
21
- const response = await apiClient.get(`${Path.getmessage}/${chatId}/${userid}`,{
22
- params: { pagenum, limit: 20 },
23
- });
24
- console.log(response); // Check the full response
25
- return response.data; // Ensure 'data' exists or adjust accordingly
26
- } catch (error) {
27
- console.error("Error fetching messages:", error);
28
- return []; // Return a default empty array on error
29
- }
43
+ export const fetchMessages = async (chatId: string | undefined, userid: string, pagenum: number) => {
44
+ const apiClient = getApiClient();
45
+ try {
46
+ const response = await apiClient.get(`${Path.getmessage}/${chatId}/${userid}`, {
47
+ params: { pagenum, limit: 20 },
48
+ });
49
+ console.log(response); // Check the full response
50
+ return response.data; // Ensure 'data' exists or adjust accordingly
51
+ } catch (error) {
52
+ console.error("Error fetching messages:", error);
53
+ return []; // Return a default empty array on error
54
+ }
30
55
  };
31
56
 
32
57
  export const setEditMessage = async ({
33
- messageId,
34
- userId,
35
- newMessage
36
- }: {
37
- messageId: string;
38
- userId: string;
39
- newMessage: string;
40
- }) => {
41
- const apiClient = getApiClient();
42
- try {
43
- const response = await apiClient.put(`${Path.editMessage}/${messageId}`, {
44
- userId,
45
- newMessage
46
- });
47
- return response.data;
48
- } catch (error) {
49
- console.error("Error editing message:", error);
50
- throw error;
51
- }
52
- };
58
+ messageId,
59
+ userId,
60
+ newMessage
61
+ }: {
62
+ messageId: string;
63
+ userId: string;
64
+ newMessage: string;
65
+ }) => {
66
+ const apiClient = getApiClient();
67
+ try {
68
+ const response = await apiClient.put(`${Path.editMessage}/${messageId}`, {
69
+ userId,
70
+ newMessage
71
+ });
72
+ return response.data;
73
+ } catch (error) {
74
+ console.error("Error editing message:", error);
75
+ throw error;
76
+ }
77
+ };
53
78
 
54
79
 
55
80
  export const deleteMessage = async ({
56
- messageId,
57
- userId
58
- }: {
59
- messageId: string;
60
- userId: string;
61
- }) => {
62
- const apiClient = getApiClient();
63
- try {
64
- const response = await apiClient.delete(
65
- `${Path.deleteMessage}/${messageId}`,
66
- {
67
- data: { userId } // Sending userId in the request body
68
- }
69
- );
70
- return response.data;
71
- } catch (error) {
72
- console.error("Error deleting message:", error);
73
- throw error;
74
- }
75
- };
81
+ messageId,
82
+ userId
83
+ }: {
84
+ messageId: string;
85
+ userId: string;
86
+ }) => {
87
+ const apiClient = getApiClient();
88
+ try {
89
+ const response = await apiClient.delete(
90
+ `${Path.deleteMessage}/${messageId}`,
91
+ {
92
+ data: { userId } // Sending userId in the request body
93
+ }
94
+ );
95
+ return response.data;
96
+ } catch (error) {
97
+ console.error("Error deleting message:", error);
98
+ throw error;
99
+ }
100
+ };
@@ -12,35 +12,42 @@ interface ChatUIState {
12
12
  firstname: string;
13
13
  idpic: string;
14
14
  };
15
+ unreadMessageIds?: string[];
15
16
  _id: string;
17
+ type?: 'personal' | 'service';
18
+ bookingId?: string;
19
+ title?: string;
20
+ serviceId?: string;
21
+ serviceTitle?: string;
16
22
  } | null;
17
23
  setSelectedConversation: (
18
24
  selectedConversation: ChatUIState["selectedConversation"]
19
25
  ) => void;
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;}[];
26
+ messages: {
27
+ _id: string;
28
+ text: string;
29
+ senderId: string;
30
+ status: string;
31
+ isOptimistic: boolean;
32
+ message: string;
33
+ createdAt: string;
34
+ media: {
35
+ type: FileType;
36
+ url: string;
37
+ name: string;
38
+ size: number;
39
+ uploadProgress: number;
40
+ uploadError: string
41
+ }[];
42
+ isUploading: boolean;
43
+ }[];
37
44
  setMessages: (messages: ChatUIState["messages"] | ((prev: ChatUIState["messages"]) => ChatUIState["messages"])) => void;
38
45
  updateMessageStatus: (messageId: string, status: string) => void;
39
46
  toggleChat: () => void;
40
- incrementUnreadCount: () => void;
41
47
  onlineUsers: string[];
42
48
  setOnlineUsers: (users: string[]) => void;
43
- resetUnreadCount: () => void;
49
+ searchTerm: string;
50
+ setSearchTerm: (searchTerm: string) => void;
44
51
  }
45
52
 
46
53
  const useChatUIStore = create<ChatUIState>((set) => ({
@@ -62,8 +69,8 @@ const useChatUIStore = create<ChatUIState>((set) => ({
62
69
  toggleChat: () => set((state) => ({ isChatOpen: !state.isChatOpen })),
63
70
  onlineUsers: [],
64
71
  setOnlineUsers: (users) => set({ onlineUsers: users }),
65
- incrementUnreadCount: () => set((state) => ({ unreadCount: state.unreadCount + 1 })),
66
- resetUnreadCount: () => set({ unreadCount: 0 }),
72
+ searchTerm: "",
73
+ setSearchTerm: (searchTerm) => set({ searchTerm }),
67
74
  }));
68
75
 
69
76
  export default useChatUIStore;
@@ -51,13 +51,15 @@
51
51
  display: flex;
52
52
  padding: 0.5rem 1rem;
53
53
  width: 100%;
54
- border: 1px solid #ccc; /* Consistent border color */
54
+ border: 1px solid #ccc;
55
+ /* Consistent border color */
55
56
  border-radius: 4px;
56
57
  gap: 1rem;
57
58
  justify-content: flex-start;
58
59
  align-items: center;
59
60
  height: 2.5rem;
60
- background-color: rgb(248, 249, 249); /* Move bg color here */
61
+ background-color: rgb(248, 249, 249);
62
+ /* Move bg color here */
61
63
  }
62
64
 
63
65
  .chatSidebarSearchbarImg {
@@ -77,9 +79,12 @@
77
79
  font-weight: 400;
78
80
  width: 100%;
79
81
  max-width: 600px;
80
- border: none !important; /* Force no border */
81
- background: transparent; /* Inherit from container */
82
- box-shadow: none !important; /* Remove any shadow */
82
+ border: none !important;
83
+ /* Force no border */
84
+ background: transparent;
85
+ /* Inherit from container */
86
+ box-shadow: none !important;
87
+ /* Remove any shadow */
83
88
  }
84
89
 
85
90
  .chatSidebarSearchbarContainer:focus-within {
@@ -379,7 +384,8 @@
379
384
  width: 40px;
380
385
  height: 40px;
381
386
  padding: 0;
382
- border-radius: 6px; /* or 0px for sharp corners */
387
+ border-radius: 6px;
388
+ /* or 0px for sharp corners */
383
389
  cursor: pointer;
384
390
  display: inline-flex;
385
391
  align-items: center;
@@ -435,23 +441,23 @@
435
441
  position: relative;
436
442
  }
437
443
 
438
- .amk7{
439
- position: absolute;
440
- top: 0;
441
- display: block;
442
- width: 8px;
443
- height: 13px;
444
- right: -8px;
444
+ .amk7 {
445
+ position: absolute;
446
+ top: 0;
447
+ display: block;
448
+ width: 8px;
449
+ height: 13px;
450
+ right: -8px;
445
451
  }
446
452
 
447
- :root{
448
- font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
453
+ :root {
454
+ font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
449
455
  }
450
456
 
451
457
  .chat-bubble {
452
458
 
453
459
  background-color: #f3f4f6;
454
- border-radius: 0.5rem ;
460
+ border-radius: 0.5rem;
455
461
  /* padding: 0.5rem; */
456
462
  font-size: 14px;
457
463
  max-width: 20rem;
@@ -1191,17 +1197,17 @@ font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe U
1191
1197
  /* margin-top: 0.5rem; */
1192
1198
  }
1193
1199
 
1194
- .media-item {
1200
+ .media-item {
1195
1201
  background: #f3f4f6;
1196
1202
  border-radius: 0.375rem;
1197
1203
  /* reduced from 0.75rem */
1198
- padding: 0.5rem;
1204
+ padding: 0.5rem;
1199
1205
  overflow: hidden;
1200
1206
  display: flex;
1201
1207
  flex-direction: column;
1202
1208
  align-items: start;
1203
1209
  width: 246px;
1204
- }
1210
+ }
1205
1211
 
1206
1212
  /* .media-grid {
1207
1213
  display: grid;
@@ -1243,15 +1249,15 @@ font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe U
1243
1249
  position: relative;
1244
1250
  width: 246px;
1245
1251
  height: 100%; */
1246
- /* aspect-ratio: 1; */
1247
- /* overflow: hidden;
1252
+ /* aspect-ratio: 1; */
1253
+ /* overflow: hidden;
1248
1254
  } */
1249
1255
 
1250
1256
  /* .media-item img {
1251
1257
  width: 100%;
1252
1258
  height: 100%;
1253
1259
  object-fit: cover; */
1254
- /* display: block; */
1260
+ /* display: block; */
1255
1261
  /* } */
1256
1262
 
1257
1263
  /* Adjust aspect ratio for single media */
@@ -1277,7 +1283,8 @@ font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe U
1277
1283
  .four-media-item
1278
1284
  {
1279
1285
  width: 100%;
1280
- } */ */
1286
+ } */
1287
+ */
1281
1288
 
1282
1289
  /* Optional: Add overlay for additional items count */
1283
1290
  .media-item.count-overlay {
@@ -1351,7 +1358,7 @@ font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe U
1351
1358
 
1352
1359
  .document-preview {
1353
1360
  position: relative;
1354
- width: 226px;
1361
+ width: 226px;
1355
1362
  height: 60px;
1356
1363
  /* Increased height to accommodate filename */
1357
1364
  border-radius: 12px;
@@ -1560,6 +1567,7 @@ font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe U
1560
1567
  background-color: #f44336;
1561
1568
  color: white;
1562
1569
  }
1570
+
1563
1571
  .system-message.booking-details {
1564
1572
  display: flex;
1565
1573
  flex-direction: column;
@@ -1637,4 +1645,172 @@ font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe U
1637
1645
  margin: 16px auto;
1638
1646
  padding: 20px;
1639
1647
  }
1648
+ }
1649
+
1650
+ .circular-progress-container {
1651
+ position: relative;
1652
+ width: 100%;
1653
+ height: 120px;
1654
+ border-radius: 12px;
1655
+ overflow: hidden;
1656
+ display: flex;
1657
+ align-items: center;
1658
+ justify-content: center;
1659
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
1660
+ }
1661
+
1662
+ .media-preview-background {
1663
+ position: absolute;
1664
+ top: 0;
1665
+ left: 0;
1666
+ width: 100%;
1667
+ height: 100%;
1668
+ /* z-index: 1; */
1669
+ }
1670
+
1671
+ .blurred-preview {
1672
+ width: 100%;
1673
+ object-fit: cover;
1674
+ filter: blur(3px) brightness(0.6);
1675
+ }
1676
+
1677
+ .circular-progress {
1678
+ position: relative;
1679
+ z-index: 2;
1680
+ display: flex;
1681
+ align-items: center;
1682
+ justify-content: center;
1683
+ width: 80px;
1684
+ height: 80px;
1685
+ }
1686
+
1687
+ .circular-progress-svg {
1688
+ width: 100%;
1689
+ height: 100%;
1690
+ transform: rotate(-90deg);
1691
+ }
1692
+
1693
+ .circular-progress-track {
1694
+ fill: none;
1695
+ stroke: rgba(255, 255, 255, 0.3);
1696
+ stroke-width: 3;
1697
+ }
1698
+
1699
+ .circular-progress-bar {
1700
+ fill: none;
1701
+ stroke: #ffffff;
1702
+ stroke-width: 3;
1703
+ stroke-linecap: round;
1704
+ transition: stroke-dasharray 0.5s ease-in-out;
1705
+ filter: drop-shadow(0 0 4px rgba(255, 255, 255, 0.5));
1706
+ }
1707
+
1708
+ .circular-progress-text {
1709
+ position: absolute;
1710
+ top: 50%;
1711
+ left: 50%;
1712
+ transform: translate(-50%, -50%);
1713
+ color: #ffffff;
1714
+ font-size: 16px;
1715
+ font-weight: 700;
1716
+ text-shadow: 0 2px 4px rgba(0, 0, 0, 0.8);
1717
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
1718
+ }
1719
+
1720
+ /* Smooth animation for progress updates */
1721
+ .circular-progress-bar {
1722
+ animation: progress-smooth 0.3s ease-out;
1723
+ }
1724
+
1725
+ @keyframes progress-smooth {
1726
+ from {
1727
+ opacity: 0.7;
1728
+ }
1729
+
1730
+ to {
1731
+ opacity: 1;
1732
+ }
1733
+ }
1734
+
1735
+ /* Pulse animation while uploading */
1736
+ .circular-progress-container:not([data-complete="true"]) .circular-progress {
1737
+ animation: upload-pulse 2s ease-in-out infinite;
1738
+ }
1739
+
1740
+ @keyframes upload-pulse {
1741
+
1742
+ 0%,
1743
+ 100% {
1744
+ transform: scale(1);
1745
+ opacity: 1;
1746
+ }
1747
+
1748
+ 50% {
1749
+ transform: scale(1.05);
1750
+ opacity: 0.9;
1751
+ }
1752
+ }
1753
+
1754
+ /* Completion state */
1755
+ .circular-progress-container[data-complete="true"] .circular-progress-bar {
1756
+ stroke: #22c55e;
1757
+ animation: completion-flash 0.6s ease-out;
1758
+ }
1759
+
1760
+ .circular-progress-container[data-complete="true"] .circular-progress-text {
1761
+ color: #22c55e;
1762
+ }
1763
+
1764
+ @keyframes completion-flash {
1765
+ 0% {
1766
+ stroke: #ffffff;
1767
+ }
1768
+
1769
+ 50% {
1770
+ stroke: #22c55e;
1771
+ filter: drop-shadow(0 0 8px rgba(34, 197, 94, 0.8));
1772
+ }
1773
+
1774
+ 100% {
1775
+ stroke: #22c55e;
1776
+ filter: drop-shadow(0 0 4px rgba(34, 197, 94, 0.5));
1777
+ }
1778
+ }
1779
+
1780
+ /* Error state */
1781
+ .circular-progress-container[data-error="true"] .circular-progress-bar {
1782
+ stroke: #ef4444;
1783
+ }
1784
+
1785
+ .circular-progress-container[data-error="true"] .circular-progress-text {
1786
+ color: #ef4444;
1787
+ }
1788
+
1789
+ /* Responsive adjustments */
1790
+ @media (max-width: 768px) {
1791
+ .circular-progress-container {
1792
+ width: 100px;
1793
+ height: 100px;
1794
+ }
1795
+
1796
+ .circular-progress {
1797
+ width: 70px;
1798
+ height: 70px;
1799
+ }
1800
+
1801
+ .circular-progress-text {
1802
+ font-size: 14px;
1803
+ }
1804
+ }
1805
+
1806
+ /* Optional: Add a subtle background overlay */
1807
+ .circular-progress-container::before {
1808
+ content: '';
1809
+ position: absolute;
1810
+ top: 0;
1811
+ left: 0;
1812
+ width: 100%;
1813
+ height: 100%;
1814
+ background: rgba(0, 0, 0, 0.2);
1815
+ /* z-index: 1; */
1640
1816
  }
package/src/types/type.ts CHANGED
@@ -21,54 +21,51 @@ export interface ParticipantDetails {
21
21
  export interface Conversation {
22
22
  _id: string;
23
23
  createdAt: string;
24
- lastMessage:{
24
+ lastMessage: {
25
25
  _id: string;
26
26
  senderId: string;
27
27
  message: string;
28
+ media: string[];
29
+ type?: 'user' | 'system' | 'system-completion';
30
+ status: MessageStatus;
28
31
  chatId: string;
29
32
  createdAt: string;
30
33
  updatedAt: string;
31
34
  __v: number;
32
- },
35
+ };
33
36
  updatedAt: string;
34
37
  __v: number;
35
38
  participantDetails: ParticipantDetails;
39
+ participants?: string[];
40
+ // readReceipts?: string[] | [];
41
+ unreadMessageIds: string[];
42
+ type?: string | undefined;
43
+ bookingId?: string;
44
+ serviceId?: string;
45
+ unreadMessageCount?: number
46
+ serviceTitle?: string;
47
+ }
48
+
49
+ export interface ServiceConversationGroup {
50
+ serviceId: string;
51
+ serviceTitle: string;
52
+ conversations: Conversation[];
36
53
  }
37
54
 
38
- export interface ServiceInfo {
39
- conversationsWithParticipantDetails: Conversation[];
55
+ export interface ParticipantGroup {
56
+ participantDetails: ParticipantDetails;
57
+ personalConversation: Conversation | null;
58
+ serviceConversations: ServiceConversationGroup[];
40
59
  }
41
60
 
42
61
  export interface ApiResponse {
43
62
  success: boolean;
44
63
  message: string;
45
- serviceInfo: Conversation[];
64
+ serviceInfo: ParticipantGroup[];
46
65
  }
47
66
 
48
67
  export interface ConversationProps {
49
- conversation: {
50
- lastMessage:{
51
- _id: string;
52
- senderId: string;
53
- message: string;
54
- media:string[];
55
- type?:'user' | 'system' | 'system-completion';
56
- status: MessageStatus;
57
- chatId: string;
58
- createdAt: string;
59
- updatedAt: string;
60
- __v: number;
61
- },
62
- participantDetails: {
63
- _id: string;
64
- profilePic: string;
65
- firstname: string;
66
- idpic: string;
67
-
68
- },
69
- unreadMessageIds: string[];
70
- _id: string;
71
- };
68
+ conversation: Conversation;
72
69
  lastIdx: boolean;
73
70
  }
74
71