diff --git a/src/app/[locale]/dashboard/messages/[id]/page.tsx b/src/app/[locale]/dashboard/messages/[id]/page.tsx new file mode 100644 index 0000000..da199a2 --- /dev/null +++ b/src/app/[locale]/dashboard/messages/[id]/page.tsx @@ -0,0 +1,242 @@ + +'use client'; + +import { useState, useEffect, useRef } from 'react'; +import { useRouter } from 'next/navigation'; +import Link from 'next/link'; +import Image from 'next/image'; +import { Button } from '@/components/ui/button'; +import { Card, CardContent, CardHeader, CardTitle, CardFooter } from '@/components/ui/card'; +import { Textarea } from '@/components/ui/textarea'; +import { ScrollArea } from '@/components/ui/scroll-area'; +import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; +import { mockRentalRequests, mockToys } from '@/lib/mockData'; // Assuming mockToys has owner avatars +import type { RentalRequest, MessageEntry, Toy } from '@/types'; +import { useI18n, useCurrentLocale } from '@/locales/client'; +import { ArrowLeft, Send, Loader2, AlertTriangle, ToyBrick } from 'lucide-react'; +import { useToast } from '@/hooks/use-toast'; +import { format } from 'date-fns'; + +// Assume current user is 'user1' for mock purposes +const currentUserId = 'user1'; +const currentUserProfiles: Record = { + 'user1': { name: 'Alice Wonderland', avatarInitial: 'AW', avatarUrl: 'https://placehold.co/40x40.png?text=AW' }, // Logged in user + 'user2': { name: 'Bob The Builder', avatarInitial: 'BT', avatarUrl: 'https://placehold.co/40x40.png?text=BT' }, + 'user3': { name: 'Carol Danvers', avatarInitial: 'CD', avatarUrl: 'https://placehold.co/40x40.png?text=CD' }, + 'user4': { name: 'Charlie Brown', avatarInitial: 'CB', avatarUrl: 'https://placehold.co/40x40.png?text=CB' }, + 'user5': { name: 'Diana Prince', avatarInitial: 'DP', avatarUrl: 'https://placehold.co/40x40.png?text=DP' }, + 'user6': { name: 'Edward Nigma', avatarInitial: 'EN', avatarUrl: 'https://placehold.co/40x40.png?text=EN' }, +}; + + +// Helper function to get the other participant in a conversation +const getOtherParticipant = (request: RentalRequest, currentUserId: string) => { + if (request.toy.ownerId === currentUserId) { + return { id: request.requesterId, name: request.requesterName }; + } + return { id: request.toy.ownerId, name: request.toy.ownerName }; +}; + +export default function MessageDetailPage({ params }: { params: { id: string } }) { + const router = useRouter(); + const locale = useCurrentLocale(); + const t = useI18n(); + const { toast } = useToast(); + + const [request, setRequest] = useState(undefined); // undefined for loading state + const [newMessage, setNewMessage] = useState(''); + const [isSending, setIsSending] = useState(false); + const messagesEndRef = useRef(null); + + useEffect(() => { + const foundRequest = mockRentalRequests.find(r => r.id === params.id); + setRequest(foundRequest || null); + }, [params.id]); + + useEffect(() => { + messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); + }, [request?.messages]); + + + const handleSendMessage = async () => { + if (!newMessage.trim()) { + toast({ title: t('message_detail.empty_message_toast'), variant: 'destructive' }); + return; + } + if (!request) return; + + setIsSending(true); + + // Mock sending message + await new Promise(resolve => setTimeout(resolve, 700)); + + const currentSenderProfile = currentUserProfiles[currentUserId]; + const newMsgEntry: MessageEntry = { + id: `msg-${Date.now()}`, + senderId: currentUserId, + senderName: currentSenderProfile?.name || 'Current User', + text: newMessage.trim(), + timestamp: new Date().toISOString(), + }; + + setRequest(prevRequest => { + if (!prevRequest) return null; + // This is a mock update. In a real app, this would re-fetch or update via state management. + const updatedMessages = [...(prevRequest.messages || []), newMsgEntry]; + // Find the request in global mock data and update it (for mock persistence across navigation) + const globalRequestIndex = mockRentalRequests.findIndex(r => r.id === prevRequest.id); + if (globalRequestIndex > -1) { + mockRentalRequests[globalRequestIndex].messages = updatedMessages; + } + return { ...prevRequest, messages: updatedMessages }; + }); + + setNewMessage(''); + setIsSending(false); + toast({ title: t('message_detail.message_sent_toast') }); + }; + + if (request === undefined) { + return ( +
+ +

{t('dashboard.layout.loading')}

+
+ ); + } + + if (!request) { + return ( +
+ +

{t('message_detail.no_conversation_found')}

+

{t('message_detail.no_conversation_description')}

+ + + +
+ ); + } + + const otherParticipant = getOtherParticipant(request, currentUserId); + const otherParticipantProfile = currentUserProfiles[otherParticipant.id] || { name: otherParticipant.name, avatarInitial: otherParticipant.name.charAt(0).toUpperCase() }; + const currentSenderProfile = currentUserProfiles[currentUserId] || { name: "You", avatarInitial: "U" }; + + + return ( +
{/* Adjust height as needed */} + + +
+ + + {t('message_detail.back_to_messages')} + +
+
+ + {request.toy.name} +
+ + {t('message_detail.title', { toyName: request.toy.name })} + +

+ {t('dashboard.messages.conversation_with', { name: otherParticipant.name })} +

+
+ +
+
+ + + {request.messages && request.messages.length > 0 ? ( + request.messages.map(msg => { + const isCurrentUser = msg.senderId === currentUserId; + const senderProfile = isCurrentUser ? currentSenderProfile : (currentUserProfiles[msg.senderId] || {name: msg.senderName, avatarInitial: msg.senderName.charAt(0).toUpperCase()}); + + return ( +
+ {!isCurrentUser && ( + + + {senderProfile.avatarInitial} + + )} +
+

{msg.text}

+

+ {format(new Date(msg.timestamp), 'MMM d, HH:mm')} +

+
+ {isCurrentUser && ( + + + {senderProfile.avatarInitial} + + )} +
+ ); + }) + ) : ( +
+ +

{t('dashboard.messages.no_messages_description')}

+
+ )} +
+ + + +
{ + e.preventDefault(); + handleSendMessage(); + }} + className="flex w-full items-start gap-2" + > +