'use client' import { useState, useEffect, useRef, useMemo } from 'react' import { useRouter } from 'next/navigation' import { Sidebar } from '@/components/Sidebar' import { useLanguage } from '@/lib/LanguageContext' import { useTheme } from '@/lib/ThemeContext' import { useMessages, formatMessageTime, formatMessageDate, getContactInitials, getRoleLabel, getRoleColor, emojiCategories, type Conversation, type Message, type Contact } from '@/lib/MessagesContext' // ============================================ // EMOJI PICKER COMPONENT // ============================================ function EmojiPicker({ onSelect, onClose, isDark }: { onSelect: (emoji: string) => void onClose: () => void isDark: boolean }) { const [activeCategory, setActiveCategory] = useState('Hรคufig') return (
{/* Header */}
Emoji
{/* Category Tabs */}
{Object.keys(emojiCategories).map(cat => ( ))}
{/* Emoji Grid */}
{emojiCategories[activeCategory as keyof typeof emojiCategories].map((emoji, i) => ( ))}
) } // ============================================ // MESSAGE TEMPLATES DROPDOWN // ============================================ function TemplatesDropdown({ templates, onSelect, isDark }: { templates: { id: string; name: string; content: string }[] onSelect: (content: string) => void isDark: boolean }) { return (
Vorlagen
{templates.map(tpl => ( ))}
) } // ============================================ // CONTACT INFO PANEL // ============================================ function ContactInfoPanel({ contact, conversation, onClose, isDark }: { contact: Contact | undefined conversation: Conversation onClose: () => void isDark: boolean }) { return (
{/* Header */}
Info
{/* Content */}
{/* Avatar & Name */}
{conversation.title ? getContactInitials(conversation.title) : '?'}

{conversation.title}

{contact && ( {getRoleLabel(contact.role)} )}
{/* Contact Details */} {contact && (
{contact.email && (
E-Mail {contact.email}
)} {contact.phone && (
Telefon {contact.phone}
)} {contact.student_name && (
Schueler/in {contact.student_name} ({contact.class_name})
)} {contact.tags.length > 0 && (
Tags
{contact.tags.map(tag => ( {tag} ))}
)}
)} {/* Group Members */} {conversation.is_group && (
{conversation.participant_ids.length} Mitglieder
)}
) } // ============================================ // MAIN PAGE // ============================================ export default function MessagesPage() { const { t } = useLanguage() const { isDark } = useTheme() const router = useRouter() const { contacts, conversations, messages, templates, unreadCount, recentConversations, sendMessage, markAsRead, createConversation, addReaction, deleteMessage, pinConversation, muteConversation, currentConversationId, setCurrentConversationId } = useMessages() const [messageInput, setMessageInput] = useState('') const [sendWithEmail, setSendWithEmail] = useState(false) const [isSending, setIsSending] = useState(false) const [showNewConversation, setShowNewConversation] = useState(false) const [showEmojiPicker, setShowEmojiPicker] = useState(false) const [showTemplates, setShowTemplates] = useState(false) const [showContactInfo, setShowContactInfo] = useState(false) const [searchQuery, setSearchQuery] = useState('') const [contextMenu, setContextMenu] = useState<{ x: number; y: number; messageId: string } | null>(null) const messagesEndRef = useRef(null) const inputRef = useRef(null) // Current conversation data const currentConversation = conversations.find(c => c.id === currentConversationId) const currentMessages = currentConversationId ? (messages[currentConversationId] || []) : [] // Find contact for conversation const getConversationContact = (conv: Conversation): Contact | undefined => { if (conv.is_group) return undefined return contacts.find(c => conv.participant_ids.includes(c.id)) } // Get sender name for group messages const getSenderName = (senderId: string): string => { if (senderId === 'self') return 'Du' const contact = contacts.find(c => c.id === senderId) return contact?.name?.split(' ')[0] || 'Unbekannt' } // Filter conversations by search const filteredConversations = useMemo(() => { if (!searchQuery) return recentConversations const q = searchQuery.toLowerCase() return recentConversations.filter(c => c.title?.toLowerCase().includes(q) || c.last_message?.toLowerCase().includes(q) ) }, [recentConversations, searchQuery]) // Group messages by date const groupedMessages = useMemo(() => { const groups: { date: string; messages: Message[] }[] = [] let currentDate = '' for (const msg of currentMessages) { const msgDate = formatMessageDate(msg.timestamp) if (msgDate !== currentDate) { currentDate = msgDate groups.push({ date: msgDate, messages: [] }) } groups[groups.length - 1].messages.push(msg) } return groups }, [currentMessages]) // Select conversation const selectConversation = async (conv: Conversation) => { setCurrentConversationId(conv.id) if (conv.unread_count > 0) { await markAsRead(conv.id) } setShowContactInfo(false) } // Send message const handleSendMessage = async () => { if (!messageInput.trim() || !currentConversationId) return setIsSending(true) await sendMessage(currentConversationId, messageInput.trim(), sendWithEmail) setMessageInput('') setIsSending(false) setShowEmojiPicker(false) setShowTemplates(false) inputRef.current?.focus() } // Insert emoji const handleEmojiSelect = (emoji: string) => { setMessageInput(prev => prev + emoji) inputRef.current?.focus() } // Start new conversation const handleStartConversation = async (contact: Contact) => { const conv = await createConversation(contact.id) if (conv) { setCurrentConversationId(conv.id) setShowNewConversation(false) } } // Handle context menu const handleContextMenu = (e: React.MouseEvent, messageId: string) => { e.preventDefault() setContextMenu({ x: e.clientX, y: e.clientY, messageId }) } // Scroll to bottom useEffect(() => { messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }) }, [currentMessages]) // Close context menu on click outside useEffect(() => { const handleClick = () => setContextMenu(null) if (contextMenu) { document.addEventListener('click', handleClick) return () => document.removeEventListener('click', handleClick) } }, [contextMenu]) // Handle Enter key const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault() handleSendMessage() } } const currentContact = currentConversation ? getConversationContact(currentConversation) : undefined return (
{/* Animated Background Blobs */}
{/* Sidebar */} {/* Main Content */}
{/* Conversations List */}
{/* Header */}

Nachrichten

{unreadCount > 0 && ( {unreadCount} ungelesen )}
{/* Search */}
setSearchQuery(e.target.value)} placeholder="Suchen..." className={`w-full px-4 py-3 pl-10 rounded-2xl border transition-all ${ isDark ? 'bg-white/5 border-white/10 text-white placeholder:text-white/40 focus:border-green-500/50' : 'bg-white border-slate-200 text-slate-900 placeholder:text-slate-400 focus:border-green-500' } focus:outline-none focus:ring-2 focus:ring-green-500/20`} />
{/* Conversation List */}
{filteredConversations.length === 0 ? (
๐Ÿ’ฌ

Keine Konversationen

Starten Sie eine neue Unterhaltung!

) : (
{filteredConversations.map((conv) => { const contact = getConversationContact(conv) const isActive = currentConversationId === conv.id return ( ) })}
)}
{/* Chat Area */}
{currentConversation ? ( <> {/* Chat Header */}
{/* Avatar */}
{currentConversation.title ? getContactInitials(currentConversation.title) : '?'}
{!currentConversation.is_group && currentContact?.online && ( )}

{currentConversation.title || 'Unbenannt'}

{currentConversation.typing ? ( schreibt... ) : currentContact ? ( <> {getRoleLabel(currentContact.role)} {currentContact.student_name && ( โ€ข {currentContact.student_name} )} {currentContact.online && ( โ€ข Online )} ) : currentConversation.is_group && ( {currentConversation.participant_ids.length} Mitglieder )}
{/* Actions */}
{/* Messages */}
{groupedMessages.length === 0 ? (
๐Ÿ‘‹

Noch keine Nachrichten

Starten Sie die Konversation!

) : ( groupedMessages.map((group, groupIndex) => (
{/* Date Separator */}
{group.date}
{/* Messages */}
{group.messages.map((msg) => { const isSelf = msg.sender_id === 'self' const isGroupMsg = currentConversation.is_group && !isSelf return (
handleContextMenu(e, msg.id)} >
{/* Sender name for groups */} {isGroupMsg && ( {getSenderName(msg.sender_id)} )}

{msg.content}

{/* Reactions */} {msg.reactions && msg.reactions.length > 0 && (
{msg.reactions.map((r, i) => ( {r.emoji} ))}
)} {/* Time & Status */}
{new Date(msg.timestamp).toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit' })} {isSelf && ( <> {msg.delivered && ( )} {msg.email_sent && ( โœ‰๏ธ )} )}
) })}
)) )}
{/* Message Input */}
{/* Options Row */}
{/* Input Row */}
{/* Emoji Button */}
{showEmojiPicker && ( setShowEmojiPicker(false)} isDark={isDark} /> )}
{/* Templates Button */}
{showTemplates && ( { setMessageInput(content) setShowTemplates(false) inputRef.current?.focus() }} isDark={isDark} /> )}
{/* Text Input */}