Update ChatDetail.tsx

This commit is contained in:
NotII
2025-03-17 20:10:53 +01:00
parent 2deb3b2429
commit a6079469f6

View File

@@ -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) ||
{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>
</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>
);
}