Files
breakpilot-lehrer/studio-v2/lib/MessagesContext.tsx
Benjamin Admin b6983ab1dc [split-required] Split 500-1000 LOC files across all services
backend-lehrer (5 files):
- alerts_agent/db/repository.py (992 → 5), abitur_docs_api.py (956 → 3)
- teacher_dashboard_api.py (951 → 3), services/pdf_service.py (916 → 3)
- mail/mail_db.py (987 → 6)

klausur-service (5 files):
- legal_templates_ingestion.py (942 → 3), ocr_pipeline_postprocess.py (929 → 4)
- ocr_pipeline_words.py (876 → 3), ocr_pipeline_ocr_merge.py (616 → 2)
- KorrekturPage.tsx (956 → 6)

website (5 pages):
- mail (985 → 9), edu-search (958 → 8), mac-mini (950 → 7)
- ocr-labeling (946 → 7), audit-workspace (871 → 4)

studio-v2 (5 files + 1 deleted):
- page.tsx (946 → 5), MessagesContext.tsx (925 → 4)
- korrektur (914 → 6), worksheet-cleanup (899 → 6)
- useVocabWorksheet.ts (888 → 3)
- Deleted dead page-original.tsx (934 LOC)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-24 23:35:37 +02:00

137 lines
6.5 KiB
TypeScript

'use client'
import { createContext, useContext, useState, useEffect, useCallback, ReactNode } from 'react'
import type { Contact, Conversation, Message, MessageTemplate, MessagesStats, MessagesContextType } from './messages/types'
import { mockContacts, mockConversations, mockMessages, mockTemplates } from './messages/mock-data'
// Re-export types and helpers for backward compatibility
export type { Contact, Conversation, Message, MessageTemplate, MessagesStats } from './messages/types'
export { formatMessageTime, formatMessageDate, getContactInitials, getRoleLabel, getRoleColor, emojiCategories } from './messages/helpers'
const MessagesContext = createContext<MessagesContextType | null>(null)
export function MessagesProvider({ children }: { children: ReactNode }) {
const [contacts, setContacts] = useState<Contact[]>(mockContacts)
const [conversations, setConversations] = useState<Conversation[]>(mockConversations)
const [messages, setMessages] = useState<Record<string, Message[]>>(mockMessages)
const [templates] = useState<MessageTemplate[]>(mockTemplates)
const [stats] = useState<MessagesStats>({
total_contacts: mockContacts.length,
total_conversations: mockConversations.length,
total_messages: Object.values(mockMessages).flat().length,
unread_messages: mockConversations.reduce((sum, c) => sum + c.unread_count, 0)
})
const [isLoading] = useState(false)
const [error] = useState<string | null>(null)
const [currentConversationId, setCurrentConversationId] = useState<string | null>(null)
const [mounted, setMounted] = useState(false)
useEffect(() => { setMounted(true) }, [])
const unreadCount = conversations.reduce((sum, c) => sum + c.unread_count, 0)
const recentConversations = [...conversations].sort((a, b) => {
if (a.pinned && !b.pinned) return -1
if (!a.pinned && b.pinned) return 1
const aTime = a.last_message_time ? new Date(a.last_message_time).getTime() : 0
const bTime = b.last_message_time ? new Date(b.last_message_time).getTime() : 0
return bTime - aTime
})
const fetchContacts = useCallback(async () => { setContacts(mockContacts) }, [])
const fetchConversations = useCallback(async () => { setConversations(mockConversations) }, [])
const fetchMessages = useCallback(async (conversationId: string): Promise<Message[]> => {
return messages[conversationId] || []
}, [messages])
const sendMessage = useCallback(async (
conversationId: string, content: string, sendEmail = false, replyTo?: string
): Promise<Message | null> => {
const newMsg: Message = {
id: `msg_${Date.now()}`, conversation_id: conversationId, sender_id: 'self',
content, content_type: 'text', timestamp: new Date().toISOString(),
read: true, delivered: true, send_email: sendEmail, email_sent: sendEmail, reply_to: replyTo
}
setMessages(prev => ({ ...prev, [conversationId]: [...(prev[conversationId] || []), newMsg] }))
setConversations(prev => prev.map(c =>
c.id === conversationId
? { ...c, last_message: content.length > 50 ? content.slice(0, 50) + '...' : content,
last_message_time: newMsg.timestamp, updated_at: newMsg.timestamp }
: c
))
return newMsg
}, [])
const markAsRead = useCallback(async (conversationId: string) => {
setMessages(prev => ({ ...prev, [conversationId]: (prev[conversationId] || []).map(m => ({ ...m, read: true })) }))
setConversations(prev => prev.map(c => c.id === conversationId ? { ...c, unread_count: 0 } : c))
}, [])
const createConversation = useCallback(async (contactId: string): Promise<Conversation | null> => {
const existing = conversations.find(c => !c.is_group && c.participant_ids.includes(contactId))
if (existing) return existing
const contact = contacts.find(c => c.id === contactId)
const newConv: Conversation = {
id: `conv_${Date.now()}`, participant_ids: [contactId],
created_at: new Date().toISOString(), updated_at: new Date().toISOString(),
unread_count: 0, is_group: false, title: contact?.name || 'Neue Konversation'
}
setConversations(prev => [newConv, ...prev])
setMessages(prev => ({ ...prev, [newConv.id]: [] }))
return newConv
}, [conversations, contacts])
const addReaction = useCallback((messageId: string, emoji: string) => {
setMessages(prev => {
const newMessages = { ...prev }
for (const convId of Object.keys(newMessages)) {
newMessages[convId] = newMessages[convId].map(msg => {
if (msg.id !== messageId) return msg
const reactions = [...(msg.reactions || [])]
const existingIndex = reactions.findIndex(r => r.user_id === 'self')
if (existingIndex >= 0) {
if (reactions[existingIndex].emoji === emoji) { reactions.splice(existingIndex, 1) }
else { reactions[existingIndex] = { ...reactions[existingIndex], emoji } }
} else { reactions.push({ emoji, user_id: 'self' }) }
return { ...msg, reactions }
})
}
return newMessages
})
}, [])
const deleteMessage = useCallback((conversationId: string, messageId: string) => {
setMessages(prev => ({ ...prev, [conversationId]: (prev[conversationId] || []).filter(m => m.id !== messageId) }))
}, [])
const pinConversation = useCallback((conversationId: string) => {
setConversations(prev => prev.map(c => c.id === conversationId ? { ...c, pinned: !c.pinned } : c))
}, [])
const muteConversation = useCallback((conversationId: string) => {
setConversations(prev => prev.map(c => c.id === conversationId ? { ...c, muted: !c.muted } : c))
}, [])
const value: MessagesContextType = {
contacts: mounted ? contacts : [], conversations: mounted ? conversations : [],
messages: mounted ? messages : {}, templates: mounted ? templates : [],
stats: mounted ? stats : { total_contacts: 0, total_conversations: 0, total_messages: 0, unread_messages: 0 },
unreadCount: mounted ? unreadCount : 0,
recentConversations: mounted ? recentConversations : [],
fetchContacts, fetchConversations, fetchMessages, sendMessage, markAsRead,
createConversation, addReaction, deleteMessage, pinConversation, muteConversation,
isLoading, error, currentConversationId,
setCurrentConversationId: mounted ? setCurrentConversationId : () => {}
}
return <MessagesContext.Provider value={value}>{children}</MessagesContext.Provider>
}
export function useMessages() {
const context = useContext(MessagesContext)
if (!context) {
throw new Error('useMessages must be used within a MessagesProvider')
}
return context
}