Update ChatDetail.tsx
This commit is contained in:
@@ -12,6 +12,7 @@ import axios from "axios";
|
||||
import { toast } from "sonner";
|
||||
import { ArrowLeft, Send, RefreshCw, File, FileText, Image as ImageIcon, Download } from "lucide-react";
|
||||
import { getCookie } from "@/lib/client-utils";
|
||||
import { ImageViewerModal } from "@/components/modals/image-viewer-modal";
|
||||
|
||||
interface Message {
|
||||
_id: string;
|
||||
@@ -88,6 +89,9 @@ export default function ChatDetail({ chatId }: { chatId: string }) {
|
||||
const [previousMessageCount, setPreviousMessageCount] = useState<number>(0);
|
||||
const audioRef = useRef<HTMLAudioElement | null>(null);
|
||||
const markReadTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||
const [selectedImage, setSelectedImage] = useState<string | null>(null);
|
||||
const [selectedMessageIndex, setSelectedMessageIndex] = useState<number | null>(null);
|
||||
const [selectedAttachmentIndex, setSelectedAttachmentIndex] = useState<number | null>(null);
|
||||
|
||||
// Initialize audio element
|
||||
useEffect(() => {
|
||||
@@ -290,6 +294,58 @@ export default function ChatDetail({ chatId }: { chatId: string }) {
|
||||
router.push("/dashboard/chats");
|
||||
};
|
||||
|
||||
// Add function to handle image navigation
|
||||
const handleImageNavigation = (direction: 'prev' | 'next') => {
|
||||
if (!chat || selectedMessageIndex === null || selectedAttachmentIndex === null) return;
|
||||
|
||||
const currentMessage = chat.messages[selectedMessageIndex];
|
||||
const currentAttachments = currentMessage.attachments.filter(att =>
|
||||
/\.(jpg|jpeg|png|gif|webp|svg|bmp|tiff)($|\?)/i.test(att) ||
|
||||
att.includes('/photos/') ||
|
||||
att.includes('/photo/')
|
||||
);
|
||||
|
||||
let newAttachmentIndex = selectedAttachmentIndex;
|
||||
let newMessageIndex = selectedMessageIndex;
|
||||
|
||||
if (direction === 'next') {
|
||||
newAttachmentIndex++;
|
||||
if (newAttachmentIndex >= currentAttachments.length) {
|
||||
newAttachmentIndex = 0;
|
||||
newMessageIndex++;
|
||||
if (newMessageIndex >= chat.messages.length) {
|
||||
newMessageIndex = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
newAttachmentIndex--;
|
||||
if (newAttachmentIndex < 0) {
|
||||
newMessageIndex--;
|
||||
if (newMessageIndex < 0) {
|
||||
newMessageIndex = chat.messages.length - 1;
|
||||
}
|
||||
const prevMessage = chat.messages[newMessageIndex];
|
||||
const prevAttachments = prevMessage.attachments.filter(att =>
|
||||
/\.(jpg|jpeg|png|gif|webp|svg|bmp|tiff)($|\?)/i.test(att) ||
|
||||
att.includes('/photos/') ||
|
||||
att.includes('/photo/')
|
||||
);
|
||||
newAttachmentIndex = prevAttachments.length - 1;
|
||||
}
|
||||
}
|
||||
|
||||
setSelectedMessageIndex(newMessageIndex);
|
||||
setSelectedAttachmentIndex(newAttachmentIndex);
|
||||
setSelectedImage(currentAttachments[newAttachmentIndex]);
|
||||
};
|
||||
|
||||
// Update the image click handler
|
||||
const handleImageClick = (imageUrl: string, messageIndex: number, attachmentIndex: number) => {
|
||||
setSelectedImage(imageUrl);
|
||||
setSelectedMessageIndex(messageIndex);
|
||||
setSelectedAttachmentIndex(attachmentIndex);
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="flex flex-col h-screen w-full relative">
|
||||
@@ -340,9 +396,9 @@ export default function ChatDetail({ chatId }: { chatId: string }) {
|
||||
<p className="text-muted-foreground">No messages yet. Send one to start the conversation.</p>
|
||||
</div>
|
||||
) : (
|
||||
chat.messages.map((msg, index) => (
|
||||
chat.messages.map((msg, messageIndex) => (
|
||||
<div
|
||||
key={msg._id || index}
|
||||
key={msg._id || messageIndex}
|
||||
className={cn(
|
||||
"flex",
|
||||
msg.sender === "vendor" ? "justify-end" : "justify-start"
|
||||
@@ -372,17 +428,19 @@ export default function ChatDetail({ chatId }: { chatId: string }) {
|
||||
{/* Show attachments if any */}
|
||||
{msg.attachments && msg.attachments.length > 0 && (
|
||||
<div className="mt-2 space-y-2">
|
||||
{msg.attachments.map((attachment, idx) => {
|
||||
// Check if attachment is an image by looking at the URL extension or paths
|
||||
const isImage = /\.(jpg|jpeg|png|gif|webp)($|\?)/i.test(attachment) ||
|
||||
attachment.includes('/photos/') ||
|
||||
attachment.includes('/photo/');
|
||||
{msg.attachments.map((attachment, attachmentIndex) => {
|
||||
const isImage = /\.(jpg|jpeg|png|gif|webp|svg|bmp|tiff)($|\?)/i.test(attachment) ||
|
||||
attachment.includes('/photos/') ||
|
||||
attachment.includes('/photo/');
|
||||
|
||||
const fileName = getFileNameFromUrl(attachment);
|
||||
|
||||
return isImage ? (
|
||||
// Render image attachment
|
||||
<div key={`attachment-${idx}`} className="rounded-md overflow-hidden bg-background/20 p-1">
|
||||
<div
|
||||
key={`attachment-${attachmentIndex}`}
|
||||
className="rounded-md overflow-hidden bg-background/20 p-1"
|
||||
onClick={() => handleImageClick(attachment, messageIndex, attachmentIndex)}
|
||||
>
|
||||
<div className="flex justify-between items-center mb-1">
|
||||
<span className="text-xs opacity-70 flex items-center">
|
||||
<ImageIcon className="h-3 w-3 mr-1" />
|
||||
@@ -399,21 +457,18 @@ export default function ChatDetail({ chatId }: { chatId: string }) {
|
||||
<Download className="h-3 w-3" />
|
||||
</a>
|
||||
</div>
|
||||
<a href={attachment} target="_blank" rel="noopener noreferrer">
|
||||
<img
|
||||
src={attachment}
|
||||
alt={fileName}
|
||||
className="max-w-full max-h-60 object-contain cursor-pointer hover:opacity-90 transition-opacity rounded"
|
||||
onError={(e) => {
|
||||
// Fallback for broken images
|
||||
(e.target as HTMLImageElement).src = "/placeholder-image.svg";
|
||||
}}
|
||||
/>
|
||||
</a>
|
||||
<img
|
||||
src={attachment}
|
||||
alt={fileName}
|
||||
className="max-w-full max-h-60 object-contain cursor-pointer hover:opacity-90 transition-opacity rounded"
|
||||
onError={(e) => {
|
||||
(e.target as HTMLImageElement).src = "/placeholder-image.svg";
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
// Render file attachment
|
||||
<div key={`attachment-${idx}`} className="flex items-center bg-background/20 rounded-md p-2 hover:bg-background/30 transition-colors">
|
||||
<div key={`attachment-${attachmentIndex}`} className="flex items-center bg-background/20 rounded-md p-2 hover:bg-background/30 transition-colors">
|
||||
<div className="mr-2">
|
||||
{getFileIcon(attachment)}
|
||||
</div>
|
||||
@@ -457,6 +512,18 @@ export default function ChatDetail({ chatId }: { chatId: string }) {
|
||||
</Button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{/* Update the image viewer modal */}
|
||||
<ImageViewerModal
|
||||
isOpen={!!selectedImage}
|
||||
onClose={() => {
|
||||
setSelectedImage(null);
|
||||
setSelectedMessageIndex(null);
|
||||
setSelectedAttachmentIndex(null);
|
||||
}}
|
||||
imageUrl={selectedImage || ""}
|
||||
onNavigate={handleImageNavigation}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user