@droppii-org/chat-sdk 0.0.4 → 0.0.5
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/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +11 -4
- package/dist/components/AutoScrollAnchor.d.ts +0 -2
- package/dist/components/AutoScrollAnchor.d.ts.map +0 -1
- package/dist/components/AutoScrollAnchor.js +0 -12
- package/dist/components/AutoScrollAnchor.jsx +0 -11
- package/dist/components/ChatBubble.d.ts +0 -2
- package/dist/components/ChatBubble.d.ts.map +0 -1
- package/dist/components/ChatBubble.js +0 -18
- package/dist/components/ChatBubble.jsx +0 -80
- package/dist/components/ChatHeader.d.ts +0 -8
- package/dist/components/ChatHeader.d.ts.map +0 -1
- package/dist/components/ChatHeader.js +0 -32
- package/dist/components/ChatHeader.jsx +0 -72
- package/dist/components/ChatInput.d.ts +0 -3
- package/dist/components/ChatInput.d.ts.map +0 -1
- package/dist/components/ChatInput.js +0 -379
- package/dist/components/ChatInput.jsx +0 -444
- package/dist/components/ChatInputDemo.d.ts +0 -2
- package/dist/components/ChatInputDemo.d.ts.map +0 -1
- package/dist/components/ChatInputDemo.js +0 -38
- package/dist/components/ChatInputDemo.jsx +0 -53
- package/dist/components/ChatInputWithCustomIcon.d.ts +0 -16
- package/dist/components/ChatInputWithCustomIcon.d.ts.map +0 -1
- package/dist/components/ChatInputWithCustomIcon.js +0 -85
- package/dist/components/ChatInputWithCustomIcon.jsx +0 -167
- package/dist/components/ChatLayout.d.ts +0 -6
- package/dist/components/ChatLayout.d.ts.map +0 -1
- package/dist/components/ChatLayout.js +0 -48
- package/dist/components/ChatLayout.jsx +0 -122
- package/dist/components/ConversationItem.d.ts +0 -9
- package/dist/components/ConversationItem.d.ts.map +0 -1
- package/dist/components/ConversationItem.js +0 -27
- package/dist/components/ConversationItem.jsx +0 -51
- package/dist/components/ConversationList.d.ts +0 -8
- package/dist/components/ConversationList.d.ts.map +0 -1
- package/dist/components/ConversationList.js +0 -11
- package/dist/components/ConversationList.jsx +0 -22
- package/dist/components/DateDivider.d.ts +0 -7
- package/dist/components/DateDivider.d.ts.map +0 -1
- package/dist/components/DateDivider.js +0 -27
- package/dist/components/DateDivider.jsx +0 -28
- package/dist/components/EmojiPicker.d.ts +0 -4
- package/dist/components/EmojiPicker.d.ts.map +0 -1
- package/dist/components/EmojiPicker.js +0 -191
- package/dist/components/EmojiPicker.jsx +0 -229
- package/dist/components/ImageLightbox.d.ts +0 -8
- package/dist/components/ImageLightbox.d.ts.map +0 -1
- package/dist/components/ImageLightbox.js +0 -8
- package/dist/components/ImageLightbox.jsx +0 -16
- package/dist/components/ImagePreviewModal.d.ts +0 -12
- package/dist/components/ImagePreviewModal.d.ts.map +0 -1
- package/dist/components/ImagePreviewModal.js +0 -55
- package/dist/components/ImagePreviewModal.jsx +0 -84
- package/dist/components/MessageItem.d.ts +0 -3
- package/dist/components/MessageItem.d.ts.map +0 -1
- package/dist/components/MessageItem.js +0 -38
- package/dist/components/MessageItem.jsx +0 -99
- package/dist/components/MessageItemDemo.d.ts +0 -2
- package/dist/components/MessageItemDemo.d.ts.map +0 -1
- package/dist/components/MessageItemDemo.js +0 -166
- package/dist/components/MessageItemDemo.jsx +0 -179
- package/dist/components/MessageList.d.ts +0 -15
- package/dist/components/MessageList.d.ts.map +0 -1
- package/dist/components/MessageList.js +0 -243
- package/dist/components/MessageList.jsx +0 -306
- package/dist/components/MessageListDemo.d.ts +0 -2
- package/dist/components/MessageListDemo.d.ts.map +0 -1
- package/dist/components/MessageListDemo.js +0 -165
- package/dist/components/MessageListDemo.jsx +0 -183
- package/dist/components/StickerPicker.d.ts +0 -4
- package/dist/components/StickerPicker.d.ts.map +0 -1
- package/dist/components/StickerPicker.js +0 -68
- package/dist/components/StickerPicker.jsx +0 -106
- package/dist/components/SwipeIndicator.d.ts +0 -9
- package/dist/components/SwipeIndicator.d.ts.map +0 -1
- package/dist/components/SwipeIndicator.js +0 -24
- package/dist/components/SwipeIndicator.jsx +0 -28
- package/dist/components/TextFormattingToolbar.d.ts +0 -4
- package/dist/components/TextFormattingToolbar.d.ts.map +0 -1
- package/dist/components/TextFormattingToolbar.js +0 -29
- package/dist/components/TextFormattingToolbar.jsx +0 -52
- package/dist/components/TypingIndicator.d.ts +0 -6
- package/dist/components/TypingIndicator.d.ts.map +0 -1
- package/dist/components/TypingIndicator.js +0 -21
- package/dist/components/TypingIndicator.jsx +0 -27
- package/dist/components/VoiceWaveIcon.d.ts +0 -7
- package/dist/components/VoiceWaveIcon.d.ts.map +0 -1
- package/dist/components/VoiceWaveIcon.js +0 -5
- package/dist/components/VoiceWaveIcon.jsx +0 -11
- package/dist/context/ChatContext.d.ts +0 -72
- package/dist/context/ChatContext.d.ts.map +0 -1
- package/dist/context/ChatContext.js +0 -347
- package/dist/context/ChatContext.jsx +0 -346
- package/dist/hooks/useChat.d.ts +0 -5
- package/dist/hooks/useChat.d.ts.map +0 -1
- package/dist/hooks/useChat.js +0 -73
- package/dist/hooks/useConversationList.d.ts +0 -5
- package/dist/hooks/useConversationList.d.ts.map +0 -1
- package/dist/hooks/useConversationList.js +0 -9
- package/dist/hooks/useMessages.d.ts +0 -5
- package/dist/hooks/useMessages.d.ts.map +0 -1
- package/dist/hooks/useMessages.js +0 -192
- package/dist/hooks/useSocket.d.ts +0 -7
- package/dist/hooks/useSocket.d.ts.map +0 -1
- package/dist/hooks/useSocket.js +0 -120
- package/dist/hooks/useSwipeGesture.d.ts +0 -11
- package/dist/hooks/useSwipeGesture.d.ts.map +0 -1
- package/dist/hooks/useSwipeGesture.js +0 -54
- package/dist/hooks/useTextSelection.d.ts +0 -13
- package/dist/hooks/useTextSelection.d.ts.map +0 -1
- package/dist/hooks/useTextSelection.js +0 -132
- package/dist/hooks/useTyping.d.ts +0 -7
- package/dist/hooks/useTyping.d.ts.map +0 -1
- package/dist/hooks/useTyping.js +0 -64
- package/dist/index.d.ts +0 -28
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -29
- package/dist/types/chat.d.ts +0 -39
- package/dist/types/chat.d.ts.map +0 -1
- package/dist/types/chat.js +0 -1
- package/dist/types/index.d.ts +0 -86
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js +0 -1
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useChatContext } from "../context/ChatContext";
|
|
4
|
-
import { FileText, Download } from "lucide-react";
|
|
5
|
-
import Image from "next/image";
|
|
6
|
-
export function MessageItem({ message, isGrouped, onImageClick }) {
|
|
7
|
-
const { state } = useChatContext();
|
|
8
|
-
const isOwnMessage = message.isMine;
|
|
9
|
-
const sender = state.users[message.senderId];
|
|
10
|
-
const formatFileSize = (bytes) => {
|
|
11
|
-
if (bytes === 0)
|
|
12
|
-
return "0 Bytes";
|
|
13
|
-
const k = 1024;
|
|
14
|
-
const sizes = ["Bytes", "KB", "MB", "GB", "TB"];
|
|
15
|
-
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
16
|
-
return Number.parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
|
|
17
|
-
};
|
|
18
|
-
const renderTextMessage = (msg) => {
|
|
19
|
-
const content = msg.text || "";
|
|
20
|
-
// Simple regex to detect URLs and make them clickable
|
|
21
|
-
const linkRegex = /(https?:\/\/[^\s]+)/g;
|
|
22
|
-
const parts = content.split(linkRegex);
|
|
23
|
-
return (_jsx("div", { className: `px-3 py-2 sm:px-4 sm:py-2 rounded-2xl max-w-full break-words ${isOwnMessage ? "bg-blue-500 text-white" : "bg-gray-100 text-gray-900"} ${isGrouped ? (isOwnMessage ? "rounded-tr-md" : "rounded-tl-md") : ""}`, children: _jsx("p", { className: "text-sm sm:text-base whitespace-pre-wrap", children: parts.map((part, index) => linkRegex.test(part) ? (_jsx("a", { href: part, target: "_blank", rel: "noopener noreferrer", className: "underline text-blue-200 hover:text-blue-100", children: part }, index)) : (part)) }) }));
|
|
24
|
-
};
|
|
25
|
-
const renderMediaMessage = (msg) => {
|
|
26
|
-
var _a, _b;
|
|
27
|
-
const imageAttachments = ((_a = msg.attachments) === null || _a === void 0 ? void 0 : _a.filter((att) => att.type === "image")) || [];
|
|
28
|
-
return (_jsxs("div", { className: `flex flex-col gap-2 ${isOwnMessage ? "items-end" : "items-start"}`, children: [msg.text && (_jsx("div", { className: `px-3 py-2 sm:px-4 sm:py-2 rounded-2xl max-w-full break-words ${isOwnMessage ? "bg-blue-500 text-white" : "bg-gray-100 text-gray-900"} ${isGrouped ? (isOwnMessage ? "rounded-tr-md" : "rounded-tl-md") : ""}`, children: _jsx("p", { className: "text-sm sm:text-base whitespace-pre-wrap", children: msg.text }) })), _jsx("div", { className: `grid gap-2 ${imageAttachments.length > 1 ? "grid-cols-2" : "grid-cols-1"}`, children: (_b = msg.attachments) === null || _b === void 0 ? void 0 : _b.map((attachment, idx) => (_jsx("div", { className: `relative rounded-lg overflow-hidden ${isOwnMessage ? "bg-blue-100" : "bg-gray-100"}`, children: attachment.type === "image" ? (_jsxs(_Fragment, { children: [_jsx(Image, { src: attachment.url || "/placeholder.svg", alt: attachment.name || "Attached image", width: 200, height: 150, className: "w-full h-auto object-cover cursor-pointer", onClick: () => onImageClick === null || onImageClick === void 0 ? void 0 : onImageClick(attachment.id, imageAttachments.map((img) => ({ id: img.id, url: img.url, name: img.name }))) }), _jsx("div", { className: "absolute inset-0 bg-black/10 flex items-center justify-center opacity-0 hover:opacity-100 transition-opacity", children: _jsx("span", { className: "text-white text-xs font-medium p-1 rounded bg-black/50", children: "Xem \u1EA3nh" }) })] })) : (_jsxs("a", { href: attachment.url, download: attachment.name, className: "flex items-center p-3 space-x-2 text-gray-800 hover:bg-gray-200 transition-colors", children: [_jsx(FileText, { className: "w-5 h-5 flex-shrink-0" }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("span", { className: "block text-sm font-medium truncate", children: attachment.name || "File" }), _jsx("span", { className: "block text-xs text-gray-500", children: attachment.size ? formatFileSize(attachment.size) : "Unknown size" })] }), _jsx(Download, { className: "w-4 h-4 flex-shrink-0 text-gray-600" })] })) }, idx))) })] }));
|
|
29
|
-
};
|
|
30
|
-
const renderPromoMessage = (msg) => {
|
|
31
|
-
if (!msg.promoData)
|
|
32
|
-
return null;
|
|
33
|
-
const { imageUrl, title, description, buttonText, buttonUrl } = msg.promoData;
|
|
34
|
-
return (_jsxs("div", { className: "w-full max-w-xs mx-auto my-2 bg-white shadow-md rounded-lg overflow-hidden border border-gray-200", children: [_jsx("div", { className: "relative w-full h-32 bg-gray-200", children: _jsx(Image, { src: imageUrl || "/placeholder.svg", alt: title, fill: true, style: { objectFit: "cover" }, className: "rounded-t-lg" }) }), _jsxs("div", { className: "p-4", children: [_jsx("h3", { className: "text-base font-semibold text-gray-900 mb-1", children: title }), _jsx("p", { className: "text-sm text-gray-600 mb-3", children: description }), _jsx("a", { href: buttonUrl, target: "_blank", rel: "noopener noreferrer", className: "inline-flex items-center justify-center w-full px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium rounded-md transition-colors", children: buttonText })] })] }));
|
|
35
|
-
};
|
|
36
|
-
return (_jsx("div", { className: `flex ${isOwnMessage ? "justify-end" : "justify-start"} ${isGrouped ? "mt-0.5 sm:mt-1" : "mt-3 sm:mt-4"}`, children: _jsxs("div", { className: `flex items-end space-x-2 max-w-[85%] sm:max-w-xs lg:max-w-md ${isOwnMessage ? "flex-row-reverse space-x-reverse" : ""}`, style: message.type === "promo" ? { maxWidth: "none" } : {}, children: [message.type !== "promo" && !isOwnMessage && !isGrouped && (_jsx("img", { src: (sender === null || sender === void 0 ? void 0 : sender.avatar) || "/placeholder.svg?height=32&width=32&query=user", alt: (sender === null || sender === void 0 ? void 0 : sender.name) || "User", className: "w-6 h-6 sm:w-8 sm:h-8 rounded-full object-cover flex-shrink-0" })), message.type !== "promo" && !isOwnMessage && isGrouped && (_jsx("div", { className: "w-6 sm:w-8 flex-shrink-0" }) // Spacer for grouped messages
|
|
37
|
-
), _jsxs("div", { className: `flex flex-col ${isOwnMessage ? "items-end" : "items-start"}`, children: [message.type !== "promo" && !isGrouped && !isOwnMessage && (_jsx("span", { className: "text-xs text-gray-500 mb-1 px-3", children: (sender === null || sender === void 0 ? void 0 : sender.name) || "Unknown User" })), message.type === "text" && renderTextMessage(message), message.type === "media" && renderMediaMessage(message), message.type === "promo" && renderPromoMessage(message), message.type !== "promo" && (_jsx("div", { className: `flex items-center space-x-1 mt-1 px-2 ${isOwnMessage ? "flex-row-reverse space-x-reverse" : ""}`, children: isOwnMessage && (_jsx("svg", { className: "w-3 h-3 sm:w-4 sm:h-4 text-blue-500", fill: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { d: "M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z" }) })) }))] })] }) }));
|
|
38
|
-
}
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { useChatContext } from "../context/ChatContext";
|
|
3
|
-
import { FileText, Download } from "lucide-react";
|
|
4
|
-
import Image from "next/image";
|
|
5
|
-
export function MessageItem({ message, isGrouped, onImageClick }) {
|
|
6
|
-
const { state } = useChatContext();
|
|
7
|
-
const isOwnMessage = message.isMine;
|
|
8
|
-
const sender = state.users[message.senderId];
|
|
9
|
-
const formatFileSize = (bytes) => {
|
|
10
|
-
if (bytes === 0)
|
|
11
|
-
return "0 Bytes";
|
|
12
|
-
const k = 1024;
|
|
13
|
-
const sizes = ["Bytes", "KB", "MB", "GB", "TB"];
|
|
14
|
-
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
15
|
-
return Number.parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
|
|
16
|
-
};
|
|
17
|
-
const renderTextMessage = (msg) => {
|
|
18
|
-
const content = msg.text || "";
|
|
19
|
-
// Simple regex to detect URLs and make them clickable
|
|
20
|
-
const linkRegex = /(https?:\/\/[^\s]+)/g;
|
|
21
|
-
const parts = content.split(linkRegex);
|
|
22
|
-
return (<div className={`px-3 py-2 sm:px-4 sm:py-2 rounded-2xl max-w-full break-words ${isOwnMessage ? "bg-blue-500 text-white" : "bg-gray-100 text-gray-900"} ${isGrouped ? (isOwnMessage ? "rounded-tr-md" : "rounded-tl-md") : ""}`}>
|
|
23
|
-
<p className="text-sm sm:text-base whitespace-pre-wrap">
|
|
24
|
-
{parts.map((part, index) => linkRegex.test(part) ? (<a key={index} href={part} target="_blank" rel="noopener noreferrer" className="underline text-blue-200 hover:text-blue-100">
|
|
25
|
-
{part}
|
|
26
|
-
</a>) : (part))}
|
|
27
|
-
</p>
|
|
28
|
-
</div>);
|
|
29
|
-
};
|
|
30
|
-
const renderMediaMessage = (msg) => {
|
|
31
|
-
var _a, _b;
|
|
32
|
-
const imageAttachments = ((_a = msg.attachments) === null || _a === void 0 ? void 0 : _a.filter((att) => att.type === "image")) || [];
|
|
33
|
-
return (<div className={`flex flex-col gap-2 ${isOwnMessage ? "items-end" : "items-start"}`}>
|
|
34
|
-
{msg.text && (<div className={`px-3 py-2 sm:px-4 sm:py-2 rounded-2xl max-w-full break-words ${isOwnMessage ? "bg-blue-500 text-white" : "bg-gray-100 text-gray-900"} ${isGrouped ? (isOwnMessage ? "rounded-tr-md" : "rounded-tl-md") : ""}`}>
|
|
35
|
-
<p className="text-sm sm:text-base whitespace-pre-wrap">{msg.text}</p>
|
|
36
|
-
</div>)}
|
|
37
|
-
<div className={`grid gap-2 ${imageAttachments.length > 1 ? "grid-cols-2" : "grid-cols-1"}`}>
|
|
38
|
-
{(_b = msg.attachments) === null || _b === void 0 ? void 0 : _b.map((attachment, idx) => (<div key={idx} className={`relative rounded-lg overflow-hidden ${isOwnMessage ? "bg-blue-100" : "bg-gray-100"}`}>
|
|
39
|
-
{attachment.type === "image" ? (<>
|
|
40
|
-
<Image src={attachment.url || "/placeholder.svg"} alt={attachment.name || "Attached image"} width={200} height={150} className="w-full h-auto object-cover cursor-pointer" onClick={() => onImageClick === null || onImageClick === void 0 ? void 0 : onImageClick(attachment.id, imageAttachments.map((img) => ({ id: img.id, url: img.url, name: img.name })))}/>
|
|
41
|
-
<div className="absolute inset-0 bg-black/10 flex items-center justify-center opacity-0 hover:opacity-100 transition-opacity">
|
|
42
|
-
<span className="text-white text-xs font-medium p-1 rounded bg-black/50">Xem ảnh</span>
|
|
43
|
-
</div>
|
|
44
|
-
</>) : (<a href={attachment.url} download={attachment.name} className="flex items-center p-3 space-x-2 text-gray-800 hover:bg-gray-200 transition-colors">
|
|
45
|
-
<FileText className="w-5 h-5 flex-shrink-0"/>
|
|
46
|
-
<div className="flex-1 min-w-0">
|
|
47
|
-
<span className="block text-sm font-medium truncate">{attachment.name || "File"}</span>
|
|
48
|
-
<span className="block text-xs text-gray-500">
|
|
49
|
-
{attachment.size ? formatFileSize(attachment.size) : "Unknown size"}
|
|
50
|
-
</span>
|
|
51
|
-
</div>
|
|
52
|
-
<Download className="w-4 h-4 flex-shrink-0 text-gray-600"/>
|
|
53
|
-
</a>)}
|
|
54
|
-
</div>))}
|
|
55
|
-
</div>
|
|
56
|
-
</div>);
|
|
57
|
-
};
|
|
58
|
-
const renderPromoMessage = (msg) => {
|
|
59
|
-
if (!msg.promoData)
|
|
60
|
-
return null;
|
|
61
|
-
const { imageUrl, title, description, buttonText, buttonUrl } = msg.promoData;
|
|
62
|
-
return (<div className="w-full max-w-xs mx-auto my-2 bg-white shadow-md rounded-lg overflow-hidden border border-gray-200">
|
|
63
|
-
<div className="relative w-full h-32 bg-gray-200">
|
|
64
|
-
<Image src={imageUrl || "/placeholder.svg"} alt={title} fill style={{ objectFit: "cover" }} className="rounded-t-lg"/>
|
|
65
|
-
</div>
|
|
66
|
-
<div className="p-4">
|
|
67
|
-
<h3 className="text-base font-semibold text-gray-900 mb-1">{title}</h3>
|
|
68
|
-
<p className="text-sm text-gray-600 mb-3">{description}</p>
|
|
69
|
-
<a href={buttonUrl} target="_blank" rel="noopener noreferrer" className="inline-flex items-center justify-center w-full px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium rounded-md transition-colors">
|
|
70
|
-
{buttonText}
|
|
71
|
-
</a>
|
|
72
|
-
</div>
|
|
73
|
-
</div>);
|
|
74
|
-
};
|
|
75
|
-
return (<div className={`flex ${isOwnMessage ? "justify-end" : "justify-start"} ${isGrouped ? "mt-0.5 sm:mt-1" : "mt-3 sm:mt-4"}`}>
|
|
76
|
-
<div className={`flex items-end space-x-2 max-w-[85%] sm:max-w-xs lg:max-w-md ${isOwnMessage ? "flex-row-reverse space-x-reverse" : ""}`} style={message.type === "promo" ? { maxWidth: "none" } : {}} // Allow promo messages to take full width if needed
|
|
77
|
-
>
|
|
78
|
-
{message.type !== "promo" && !isOwnMessage && !isGrouped && (<img src={(sender === null || sender === void 0 ? void 0 : sender.avatar) || "/placeholder.svg?height=32&width=32&query=user"} alt={(sender === null || sender === void 0 ? void 0 : sender.name) || "User"} className="w-6 h-6 sm:w-8 sm:h-8 rounded-full object-cover flex-shrink-0"/>)}
|
|
79
|
-
|
|
80
|
-
{message.type !== "promo" && !isOwnMessage && isGrouped && (<div className="w-6 sm:w-8 flex-shrink-0"/> // Spacer for grouped messages
|
|
81
|
-
)}
|
|
82
|
-
|
|
83
|
-
<div className={`flex flex-col ${isOwnMessage ? "items-end" : "items-start"}`}>
|
|
84
|
-
{message.type !== "promo" && !isGrouped && !isOwnMessage && (<span className="text-xs text-gray-500 mb-1 px-3">{(sender === null || sender === void 0 ? void 0 : sender.name) || "Unknown User"}</span>)}
|
|
85
|
-
|
|
86
|
-
{message.type === "text" && renderTextMessage(message)}
|
|
87
|
-
{message.type === "media" && renderMediaMessage(message)}
|
|
88
|
-
{message.type === "promo" && renderPromoMessage(message)}
|
|
89
|
-
|
|
90
|
-
{message.type !== "promo" && (<div className={`flex items-center space-x-1 mt-1 px-2 ${isOwnMessage ? "flex-row-reverse space-x-reverse" : ""}`}>
|
|
91
|
-
{/* Status icon logic (from previous implementation) */}
|
|
92
|
-
{isOwnMessage && (<svg className="w-3 h-3 sm:w-4 sm:h-4 text-blue-500" fill="currentColor" viewBox="0 0 24 24">
|
|
93
|
-
<path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z"/>
|
|
94
|
-
</svg>)}
|
|
95
|
-
</div>)}
|
|
96
|
-
</div>
|
|
97
|
-
</div>
|
|
98
|
-
</div>);
|
|
99
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"MessageItemDemo.d.ts","sourceRoot":"","sources":["../../src/components/MessageItemDemo.tsx"],"names":[],"mappings":"AAMA,wBAAgB,eAAe,4CA2L9B"}
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { MessageItem } from "./MessageItem";
|
|
4
|
-
import { DateDivider } from "./DateDivider";
|
|
5
|
-
export function MessageItemDemo() {
|
|
6
|
-
// Demo messages showcasing all message types
|
|
7
|
-
const demoMessages = [
|
|
8
|
-
// Text message from other user
|
|
9
|
-
{
|
|
10
|
-
id: "demo-1",
|
|
11
|
-
senderId: "user-2",
|
|
12
|
-
type: "text",
|
|
13
|
-
text: "Hey! How are you doing today? 😊",
|
|
14
|
-
createdAt: new Date(Date.now() - 3600000).toISOString(),
|
|
15
|
-
isMine: false,
|
|
16
|
-
},
|
|
17
|
-
// Text message from current user
|
|
18
|
-
{
|
|
19
|
-
id: "demo-2",
|
|
20
|
-
senderId: "current-user",
|
|
21
|
-
type: "text",
|
|
22
|
-
text: "I'm doing great! Thanks for asking. Check out this link: https://example.com",
|
|
23
|
-
createdAt: new Date(Date.now() - 3000000).toISOString(),
|
|
24
|
-
isMine: true,
|
|
25
|
-
},
|
|
26
|
-
// Media message with text and image from other user
|
|
27
|
-
{
|
|
28
|
-
id: "demo-3",
|
|
29
|
-
senderId: "user-2",
|
|
30
|
-
type: "media",
|
|
31
|
-
text: "Look at this beautiful sunset I captured! 📸",
|
|
32
|
-
attachments: [
|
|
33
|
-
{
|
|
34
|
-
id: "demo-3-1",
|
|
35
|
-
type: "image",
|
|
36
|
-
url: "/placeholder.svg?height=300&width=400",
|
|
37
|
-
name: "sunset.jpg",
|
|
38
|
-
size: 245760,
|
|
39
|
-
},
|
|
40
|
-
],
|
|
41
|
-
createdAt: new Date(Date.now() - 2400000).toISOString(),
|
|
42
|
-
isMine: false,
|
|
43
|
-
},
|
|
44
|
-
// Media message with multiple images from current user
|
|
45
|
-
{
|
|
46
|
-
id: "demo-4",
|
|
47
|
-
senderId: "current-user",
|
|
48
|
-
type: "media",
|
|
49
|
-
text: "My vacation photos! 🏖️",
|
|
50
|
-
attachments: [
|
|
51
|
-
{
|
|
52
|
-
id: "demo-4-1",
|
|
53
|
-
type: "image",
|
|
54
|
-
url: "/placeholder.svg?height=200&width=300",
|
|
55
|
-
name: "beach1.jpg",
|
|
56
|
-
size: 180000,
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
id: "demo-4-2",
|
|
60
|
-
type: "image",
|
|
61
|
-
url: "/placeholder.svg?height=200&width=300",
|
|
62
|
-
name: "beach2.jpg",
|
|
63
|
-
size: 195000,
|
|
64
|
-
},
|
|
65
|
-
],
|
|
66
|
-
createdAt: new Date(Date.now() - 1800000).toISOString(),
|
|
67
|
-
isMine: true,
|
|
68
|
-
},
|
|
69
|
-
// Media message with file from other user
|
|
70
|
-
{
|
|
71
|
-
id: "demo-5",
|
|
72
|
-
senderId: "user-2",
|
|
73
|
-
type: "media",
|
|
74
|
-
text: "Here's the document you requested",
|
|
75
|
-
attachments: [
|
|
76
|
-
{
|
|
77
|
-
id: "demo-5-1",
|
|
78
|
-
type: "file",
|
|
79
|
-
url: "/placeholder.svg?height=200&width=200",
|
|
80
|
-
name: "project-proposal.pdf",
|
|
81
|
-
size: 1024000,
|
|
82
|
-
},
|
|
83
|
-
],
|
|
84
|
-
createdAt: new Date(Date.now() - 1200000).toISOString(),
|
|
85
|
-
isMine: false,
|
|
86
|
-
},
|
|
87
|
-
// Media message with mixed attachments from current user
|
|
88
|
-
{
|
|
89
|
-
id: "demo-6",
|
|
90
|
-
senderId: "current-user",
|
|
91
|
-
type: "media",
|
|
92
|
-
text: "Screenshot and the related document",
|
|
93
|
-
attachments: [
|
|
94
|
-
{
|
|
95
|
-
id: "demo-6-1",
|
|
96
|
-
type: "image",
|
|
97
|
-
url: "/placeholder.svg?height=400&width=300",
|
|
98
|
-
name: "screenshot.png",
|
|
99
|
-
size: 156000,
|
|
100
|
-
},
|
|
101
|
-
{
|
|
102
|
-
id: "demo-6-2",
|
|
103
|
-
type: "file",
|
|
104
|
-
url: "/placeholder.svg?height=200&width=200",
|
|
105
|
-
name: "instructions.docx",
|
|
106
|
-
size: 45000,
|
|
107
|
-
},
|
|
108
|
-
],
|
|
109
|
-
createdAt: new Date(Date.now() - 600000).toISOString(),
|
|
110
|
-
isMine: true,
|
|
111
|
-
},
|
|
112
|
-
// Promotional message (system message)
|
|
113
|
-
{
|
|
114
|
-
id: "demo-7",
|
|
115
|
-
senderId: "system",
|
|
116
|
-
type: "promo",
|
|
117
|
-
promoData: {
|
|
118
|
-
imageUrl: "/placeholder.svg?height=200&width=400",
|
|
119
|
-
title: "Giảm 30% đơn hàng hôm nay!",
|
|
120
|
-
description: "Khuyến mãi đặc biệt chỉ trong hôm nay. Đừng bỏ lỡ cơ hội tiết kiệm!",
|
|
121
|
-
buttonText: "Đặt ngay",
|
|
122
|
-
buttonUrl: "https://example.com/sale",
|
|
123
|
-
},
|
|
124
|
-
createdAt: new Date(Date.now() - 300000).toISOString(),
|
|
125
|
-
isMine: false,
|
|
126
|
-
},
|
|
127
|
-
// Recent text message from other user
|
|
128
|
-
{
|
|
129
|
-
id: "demo-8",
|
|
130
|
-
senderId: "user-2",
|
|
131
|
-
type: "text",
|
|
132
|
-
text: "Thanks for sharing! Those photos are amazing 🤩",
|
|
133
|
-
createdAt: new Date(Date.now() - 60000).toISOString(),
|
|
134
|
-
isMine: false,
|
|
135
|
-
},
|
|
136
|
-
];
|
|
137
|
-
const groupMessagesByDate = () => {
|
|
138
|
-
const groups = [];
|
|
139
|
-
let currentDate = "";
|
|
140
|
-
let currentGroup = [];
|
|
141
|
-
demoMessages.forEach((message) => {
|
|
142
|
-
const messageDate = new Date(message.createdAt).toDateString();
|
|
143
|
-
if (messageDate !== currentDate) {
|
|
144
|
-
if (currentGroup.length > 0) {
|
|
145
|
-
groups.push({ date: currentDate, messages: currentGroup });
|
|
146
|
-
}
|
|
147
|
-
currentDate = messageDate;
|
|
148
|
-
currentGroup = [message];
|
|
149
|
-
}
|
|
150
|
-
else {
|
|
151
|
-
currentGroup.push(message);
|
|
152
|
-
}
|
|
153
|
-
});
|
|
154
|
-
if (currentGroup.length > 0) {
|
|
155
|
-
groups.push({ date: currentDate, messages: currentGroup });
|
|
156
|
-
}
|
|
157
|
-
return groups;
|
|
158
|
-
};
|
|
159
|
-
const messageGroups = groupMessagesByDate();
|
|
160
|
-
return (_jsxs("div", { className: "max-w-2xl mx-auto bg-white rounded-lg shadow-lg overflow-hidden", children: [_jsxs("div", { className: "bg-gray-50 p-4 border-b", children: [_jsx("h2", { className: "text-lg font-semibold text-gray-900", children: "MessageItem Demo" }), _jsx("p", { className: "text-sm text-gray-600", children: "Showcasing all message types: text, media, and promotional" })] }), _jsx("div", { className: "h-96 overflow-y-auto p-4 space-y-4", children: messageGroups.map((group, groupIndex) => (_jsxs("div", { children: [_jsx(DateDivider, { date: new Date(group.date) }), _jsx("div", { className: "space-y-2", children: group.messages.map((message, messageIndex) => {
|
|
161
|
-
const prevMessage = messageIndex > 0 ? group.messages[messageIndex - 1] : null;
|
|
162
|
-
const isGrouped = (prevMessage === null || prevMessage === void 0 ? void 0 : prevMessage.senderId) === message.senderId &&
|
|
163
|
-
new Date(message.createdAt).getTime() - new Date(prevMessage.createdAt).getTime() < 300000; // 5 minutes
|
|
164
|
-
return _jsx(MessageItem, { message: message, isGrouped: isGrouped }, message.id);
|
|
165
|
-
}) })] }, group.date))) })] }));
|
|
166
|
-
}
|
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { MessageItem } from "./MessageItem";
|
|
3
|
-
import { DateDivider } from "./DateDivider";
|
|
4
|
-
export function MessageItemDemo() {
|
|
5
|
-
// Demo messages showcasing all message types
|
|
6
|
-
const demoMessages = [
|
|
7
|
-
// Text message from other user
|
|
8
|
-
{
|
|
9
|
-
id: "demo-1",
|
|
10
|
-
senderId: "user-2",
|
|
11
|
-
type: "text",
|
|
12
|
-
text: "Hey! How are you doing today? 😊",
|
|
13
|
-
createdAt: new Date(Date.now() - 3600000).toISOString(),
|
|
14
|
-
isMine: false,
|
|
15
|
-
},
|
|
16
|
-
// Text message from current user
|
|
17
|
-
{
|
|
18
|
-
id: "demo-2",
|
|
19
|
-
senderId: "current-user",
|
|
20
|
-
type: "text",
|
|
21
|
-
text: "I'm doing great! Thanks for asking. Check out this link: https://example.com",
|
|
22
|
-
createdAt: new Date(Date.now() - 3000000).toISOString(),
|
|
23
|
-
isMine: true,
|
|
24
|
-
},
|
|
25
|
-
// Media message with text and image from other user
|
|
26
|
-
{
|
|
27
|
-
id: "demo-3",
|
|
28
|
-
senderId: "user-2",
|
|
29
|
-
type: "media",
|
|
30
|
-
text: "Look at this beautiful sunset I captured! 📸",
|
|
31
|
-
attachments: [
|
|
32
|
-
{
|
|
33
|
-
id: "demo-3-1",
|
|
34
|
-
type: "image",
|
|
35
|
-
url: "/placeholder.svg?height=300&width=400",
|
|
36
|
-
name: "sunset.jpg",
|
|
37
|
-
size: 245760,
|
|
38
|
-
},
|
|
39
|
-
],
|
|
40
|
-
createdAt: new Date(Date.now() - 2400000).toISOString(),
|
|
41
|
-
isMine: false,
|
|
42
|
-
},
|
|
43
|
-
// Media message with multiple images from current user
|
|
44
|
-
{
|
|
45
|
-
id: "demo-4",
|
|
46
|
-
senderId: "current-user",
|
|
47
|
-
type: "media",
|
|
48
|
-
text: "My vacation photos! 🏖️",
|
|
49
|
-
attachments: [
|
|
50
|
-
{
|
|
51
|
-
id: "demo-4-1",
|
|
52
|
-
type: "image",
|
|
53
|
-
url: "/placeholder.svg?height=200&width=300",
|
|
54
|
-
name: "beach1.jpg",
|
|
55
|
-
size: 180000,
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
id: "demo-4-2",
|
|
59
|
-
type: "image",
|
|
60
|
-
url: "/placeholder.svg?height=200&width=300",
|
|
61
|
-
name: "beach2.jpg",
|
|
62
|
-
size: 195000,
|
|
63
|
-
},
|
|
64
|
-
],
|
|
65
|
-
createdAt: new Date(Date.now() - 1800000).toISOString(),
|
|
66
|
-
isMine: true,
|
|
67
|
-
},
|
|
68
|
-
// Media message with file from other user
|
|
69
|
-
{
|
|
70
|
-
id: "demo-5",
|
|
71
|
-
senderId: "user-2",
|
|
72
|
-
type: "media",
|
|
73
|
-
text: "Here's the document you requested",
|
|
74
|
-
attachments: [
|
|
75
|
-
{
|
|
76
|
-
id: "demo-5-1",
|
|
77
|
-
type: "file",
|
|
78
|
-
url: "/placeholder.svg?height=200&width=200",
|
|
79
|
-
name: "project-proposal.pdf",
|
|
80
|
-
size: 1024000,
|
|
81
|
-
},
|
|
82
|
-
],
|
|
83
|
-
createdAt: new Date(Date.now() - 1200000).toISOString(),
|
|
84
|
-
isMine: false,
|
|
85
|
-
},
|
|
86
|
-
// Media message with mixed attachments from current user
|
|
87
|
-
{
|
|
88
|
-
id: "demo-6",
|
|
89
|
-
senderId: "current-user",
|
|
90
|
-
type: "media",
|
|
91
|
-
text: "Screenshot and the related document",
|
|
92
|
-
attachments: [
|
|
93
|
-
{
|
|
94
|
-
id: "demo-6-1",
|
|
95
|
-
type: "image",
|
|
96
|
-
url: "/placeholder.svg?height=400&width=300",
|
|
97
|
-
name: "screenshot.png",
|
|
98
|
-
size: 156000,
|
|
99
|
-
},
|
|
100
|
-
{
|
|
101
|
-
id: "demo-6-2",
|
|
102
|
-
type: "file",
|
|
103
|
-
url: "/placeholder.svg?height=200&width=200",
|
|
104
|
-
name: "instructions.docx",
|
|
105
|
-
size: 45000,
|
|
106
|
-
},
|
|
107
|
-
],
|
|
108
|
-
createdAt: new Date(Date.now() - 600000).toISOString(),
|
|
109
|
-
isMine: true,
|
|
110
|
-
},
|
|
111
|
-
// Promotional message (system message)
|
|
112
|
-
{
|
|
113
|
-
id: "demo-7",
|
|
114
|
-
senderId: "system",
|
|
115
|
-
type: "promo",
|
|
116
|
-
promoData: {
|
|
117
|
-
imageUrl: "/placeholder.svg?height=200&width=400",
|
|
118
|
-
title: "Giảm 30% đơn hàng hôm nay!",
|
|
119
|
-
description: "Khuyến mãi đặc biệt chỉ trong hôm nay. Đừng bỏ lỡ cơ hội tiết kiệm!",
|
|
120
|
-
buttonText: "Đặt ngay",
|
|
121
|
-
buttonUrl: "https://example.com/sale",
|
|
122
|
-
},
|
|
123
|
-
createdAt: new Date(Date.now() - 300000).toISOString(),
|
|
124
|
-
isMine: false,
|
|
125
|
-
},
|
|
126
|
-
// Recent text message from other user
|
|
127
|
-
{
|
|
128
|
-
id: "demo-8",
|
|
129
|
-
senderId: "user-2",
|
|
130
|
-
type: "text",
|
|
131
|
-
text: "Thanks for sharing! Those photos are amazing 🤩",
|
|
132
|
-
createdAt: new Date(Date.now() - 60000).toISOString(),
|
|
133
|
-
isMine: false,
|
|
134
|
-
},
|
|
135
|
-
];
|
|
136
|
-
const groupMessagesByDate = () => {
|
|
137
|
-
const groups = [];
|
|
138
|
-
let currentDate = "";
|
|
139
|
-
let currentGroup = [];
|
|
140
|
-
demoMessages.forEach((message) => {
|
|
141
|
-
const messageDate = new Date(message.createdAt).toDateString();
|
|
142
|
-
if (messageDate !== currentDate) {
|
|
143
|
-
if (currentGroup.length > 0) {
|
|
144
|
-
groups.push({ date: currentDate, messages: currentGroup });
|
|
145
|
-
}
|
|
146
|
-
currentDate = messageDate;
|
|
147
|
-
currentGroup = [message];
|
|
148
|
-
}
|
|
149
|
-
else {
|
|
150
|
-
currentGroup.push(message);
|
|
151
|
-
}
|
|
152
|
-
});
|
|
153
|
-
if (currentGroup.length > 0) {
|
|
154
|
-
groups.push({ date: currentDate, messages: currentGroup });
|
|
155
|
-
}
|
|
156
|
-
return groups;
|
|
157
|
-
};
|
|
158
|
-
const messageGroups = groupMessagesByDate();
|
|
159
|
-
return (<div className="max-w-2xl mx-auto bg-white rounded-lg shadow-lg overflow-hidden">
|
|
160
|
-
<div className="bg-gray-50 p-4 border-b">
|
|
161
|
-
<h2 className="text-lg font-semibold text-gray-900">MessageItem Demo</h2>
|
|
162
|
-
<p className="text-sm text-gray-600">Showcasing all message types: text, media, and promotional</p>
|
|
163
|
-
</div>
|
|
164
|
-
|
|
165
|
-
<div className="h-96 overflow-y-auto p-4 space-y-4">
|
|
166
|
-
{messageGroups.map((group, groupIndex) => (<div key={group.date}>
|
|
167
|
-
<DateDivider date={new Date(group.date)}/>
|
|
168
|
-
<div className="space-y-2">
|
|
169
|
-
{group.messages.map((message, messageIndex) => {
|
|
170
|
-
const prevMessage = messageIndex > 0 ? group.messages[messageIndex - 1] : null;
|
|
171
|
-
const isGrouped = (prevMessage === null || prevMessage === void 0 ? void 0 : prevMessage.senderId) === message.senderId &&
|
|
172
|
-
new Date(message.createdAt).getTime() - new Date(prevMessage.createdAt).getTime() < 300000; // 5 minutes
|
|
173
|
-
return <MessageItem key={message.id} message={message} isGrouped={isGrouped}/>;
|
|
174
|
-
})}
|
|
175
|
-
</div>
|
|
176
|
-
</div>))}
|
|
177
|
-
</div>
|
|
178
|
-
</div>);
|
|
179
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { Message } from "../types";
|
|
2
|
-
interface MessageListProps {
|
|
3
|
-
messages: Message[];
|
|
4
|
-
isLoadingMore?: boolean;
|
|
5
|
-
onLoadMore?: () => void;
|
|
6
|
-
hasMore?: boolean;
|
|
7
|
-
currentUserId: string;
|
|
8
|
-
conversationId?: string;
|
|
9
|
-
className?: string;
|
|
10
|
-
onSwipeBack?: () => void;
|
|
11
|
-
}
|
|
12
|
-
export declare function MessageList({ messages, // Add default empty array
|
|
13
|
-
isLoadingMore, onLoadMore, hasMore, currentUserId, conversationId, className, onSwipeBack, }: MessageListProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
-
export {};
|
|
15
|
-
//# sourceMappingURL=MessageList.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../src/components/MessageList.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAkB,OAAO,EAAE,MAAM,UAAU,CAAA;AAGvD,UAAU,gBAAgB;IACxB,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAA;IACvB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,aAAa,EAAE,MAAM,CAAA;IACrB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAA;CACzB;AAED,wBAAgB,WAAW,CAAC,EAC1B,QAAa,EAAE,0BAA0B;AACzC,aAAqB,EACrB,UAAU,EACV,OAAe,EACf,aAAa,EACb,cAAc,EACd,SAAc,EACd,WAAW,GACZ,EAAE,gBAAgB,2CA8WlB"}
|