""" BreakPilot Studio - Messenger Modul Funktionen: - Matrix Chat Integration (DSGVO-konform) - Direktnachrichten an Eltern - Gruppenchats (Klassen, Fachschaften) - Vorlagen fuer haeufige Nachrichten - Dateiaustausch - Lesebestaetigungen """ class MessengerModule: """Modul fuer sichere Kommunikation mit Matrix-Integration.""" @staticmethod def get_css() -> str: """CSS fuer das Messenger-Modul.""" return """ /* ============================================= MESSENGER MODULE - Matrix Chat Integration ============================================= */ /* Panel Layout */ .panel-messenger { display: none; flex-direction: column; height: 100%; background: var(--bp-bg); overflow: hidden; } .panel-messenger.active { display: flex; } /* Messenger Container */ .messenger-container { display: flex; flex: 1; overflow: hidden; } /* Left Sidebar - Conversations */ .messenger-sidebar { width: 320px; border-right: 1px solid var(--bp-border); display: flex; flex-direction: column; background: var(--bp-surface); } .messenger-sidebar-header { padding: 20px; border-bottom: 1px solid var(--bp-border); } .messenger-sidebar-title { font-size: 18px; font-weight: 600; color: var(--bp-text); margin-bottom: 16px; } /* Search Box */ .messenger-search { position: relative; } .messenger-search input { width: 100%; padding: 12px 16px 12px 40px; border: 1px solid var(--bp-border); border-radius: 10px; background: var(--bp-bg); color: var(--bp-text); font-size: 14px; } .messenger-search input:focus { outline: none; border-color: var(--bp-primary); } .messenger-search-icon { position: absolute; left: 14px; top: 50%; transform: translateY(-50%); color: var(--bp-text-muted); font-size: 16px; } /* Tab Navigation */ .messenger-tabs { display: flex; padding: 12px 20px; gap: 8px; border-bottom: 1px solid var(--bp-border); } .messenger-tab { flex: 1; padding: 10px 16px; border: none; border-radius: 8px; background: transparent; color: var(--bp-text-muted); font-size: 13px; font-weight: 500; cursor: pointer; transition: all 0.2s; } .messenger-tab:hover { background: var(--bp-surface-elevated); } .messenger-tab.active { background: var(--bp-primary); color: white; } .messenger-tab-badge { display: inline-flex; align-items: center; justify-content: center; min-width: 18px; height: 18px; padding: 0 6px; margin-left: 6px; border-radius: 9px; background: #ef4444; color: white; font-size: 11px; font-weight: 600; } /* Conversation List */ .messenger-conversations { flex: 1; overflow-y: auto; } .messenger-conversation { display: flex; align-items: center; gap: 12px; padding: 16px 20px; cursor: pointer; transition: background 0.2s; border-bottom: 1px solid var(--bp-border-subtle); } .messenger-conversation:hover { background: var(--bp-surface-elevated); } .messenger-conversation.active { background: var(--bp-primary-soft); border-left: 3px solid var(--bp-primary); } .messenger-conversation.unread { background: rgba(59, 130, 246, 0.05); } .messenger-avatar { width: 48px; height: 48px; border-radius: 50%; background: var(--bp-surface-elevated); display: flex; align-items: center; justify-content: center; font-size: 20px; flex-shrink: 0; position: relative; } .messenger-avatar.online::after { content: ''; position: absolute; bottom: 2px; right: 2px; width: 12px; height: 12px; border-radius: 50%; background: #10b981; border: 2px solid var(--bp-surface); } .messenger-avatar.group { border-radius: 12px; background: var(--bp-primary-soft); } .messenger-conversation-content { flex: 1; min-width: 0; } .messenger-conversation-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px; } .messenger-conversation-name { font-size: 14px; font-weight: 600; color: var(--bp-text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .messenger-conversation-time { font-size: 11px; color: var(--bp-text-muted); flex-shrink: 0; } .messenger-conversation-preview { font-size: 13px; color: var(--bp-text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .messenger-conversation.unread .messenger-conversation-preview { color: var(--bp-text); font-weight: 500; } .messenger-unread-badge { width: 20px; height: 20px; border-radius: 50%; background: var(--bp-primary); color: white; font-size: 11px; font-weight: 600; display: flex; align-items: center; justify-content: center; flex-shrink: 0; } /* New Conversation Button */ .messenger-new-btn { margin: 16px 20px; padding: 14px; border: none; border-radius: 12px; background: var(--bp-primary); color: white; font-size: 14px; font-weight: 600; cursor: pointer; display: flex; align-items: center; justify-content: center; gap: 8px; transition: all 0.2s; } .messenger-new-btn:hover { background: var(--bp-primary-hover); transform: translateY(-1px); } /* Chat Area */ .messenger-chat { flex: 1; display: flex; flex-direction: column; background: var(--bp-bg); } .messenger-chat-header { display: flex; align-items: center; justify-content: space-between; padding: 16px 24px; border-bottom: 1px solid var(--bp-border); background: var(--bp-surface); } .messenger-chat-info { display: flex; align-items: center; gap: 12px; } .messenger-chat-name { font-size: 16px; font-weight: 600; color: var(--bp-text); } .messenger-chat-status { font-size: 12px; color: var(--bp-text-muted); } .messenger-chat-status.online { color: #10b981; } .messenger-chat-actions { display: flex; gap: 8px; } .messenger-action-btn { width: 40px; height: 40px; border: none; border-radius: 10px; background: var(--bp-surface-elevated); color: var(--bp-text-muted); cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 18px; transition: all 0.2s; } .messenger-action-btn:hover { background: var(--bp-primary-soft); color: var(--bp-primary); } /* Messages Area */ .messenger-messages { flex: 1; overflow-y: auto; padding: 24px; display: flex; flex-direction: column; gap: 16px; } .messenger-message { display: flex; gap: 12px; max-width: 70%; } .messenger-message.sent { align-self: flex-end; flex-direction: row-reverse; } .messenger-message-avatar { width: 36px; height: 36px; border-radius: 50%; background: var(--bp-surface-elevated); display: flex; align-items: center; justify-content: center; font-size: 16px; flex-shrink: 0; } .messenger-message-content { display: flex; flex-direction: column; gap: 4px; } .messenger-message-bubble { padding: 12px 16px; border-radius: 18px; background: var(--bp-surface); color: var(--bp-text); font-size: 14px; line-height: 1.5; border: 1px solid var(--bp-border); } .messenger-message.sent .messenger-message-bubble { background: var(--bp-primary); color: white; border-color: var(--bp-primary); border-bottom-right-radius: 4px; } .messenger-message:not(.sent) .messenger-message-bubble { border-bottom-left-radius: 4px; } .messenger-message-meta { display: flex; gap: 8px; font-size: 11px; color: var(--bp-text-muted); padding: 0 8px; } .messenger-message.sent .messenger-message-meta { justify-content: flex-end; } .messenger-message-status { color: #10b981; } /* Message Input */ .messenger-input-area { padding: 16px 24px; border-top: 1px solid var(--bp-border); background: var(--bp-surface); } .messenger-input-wrapper { display: flex; gap: 12px; align-items: flex-end; } .messenger-input-actions { display: flex; gap: 4px; } .messenger-input-btn { width: 40px; height: 40px; border: none; border-radius: 10px; background: transparent; color: var(--bp-text-muted); cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 20px; transition: all 0.2s; } .messenger-input-btn:hover { background: var(--bp-surface-elevated); color: var(--bp-primary); } .messenger-input { flex: 1; padding: 12px 16px; border: 1px solid var(--bp-border); border-radius: 20px; background: var(--bp-bg); color: var(--bp-text); font-size: 14px; resize: none; min-height: 44px; max-height: 120px; line-height: 1.4; } .messenger-input:focus { outline: none; border-color: var(--bp-primary); } .messenger-send-btn { width: 44px; height: 44px; border: none; border-radius: 50%; background: var(--bp-primary); color: white; cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 20px; transition: all 0.2s; } .messenger-send-btn:hover { background: var(--bp-primary-hover); transform: scale(1.05); } .messenger-send-btn:disabled { background: var(--bp-surface-elevated); color: var(--bp-text-muted); cursor: not-allowed; transform: none; } /* Empty State */ .messenger-empty { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 48px; text-align: center; color: var(--bp-text-muted); } .messenger-empty-icon { font-size: 64px; margin-bottom: 24px; opacity: 0.5; } .messenger-empty h2 { font-size: 20px; font-weight: 600; color: var(--bp-text); margin-bottom: 8px; } .messenger-empty p { font-size: 14px; max-width: 400px; margin-bottom: 24px; } /* Templates Panel */ .messenger-templates { position: absolute; bottom: 80px; left: 24px; right: 24px; background: var(--bp-surface); border: 1px solid var(--bp-border); border-radius: 16px; padding: 16px; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15); display: none; } .messenger-templates.active { display: block; } .messenger-templates-title { font-size: 14px; font-weight: 600; color: var(--bp-text); margin-bottom: 12px; } .messenger-template-list { display: flex; flex-direction: column; gap: 8px; max-height: 200px; overflow-y: auto; } .messenger-template-item { padding: 12px; border-radius: 10px; background: var(--bp-bg); cursor: pointer; transition: all 0.2s; } .messenger-template-item:hover { background: var(--bp-primary-soft); } .messenger-template-name { font-size: 13px; font-weight: 500; color: var(--bp-text); margin-bottom: 4px; } .messenger-template-preview { font-size: 12px; color: var(--bp-text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* Connection Status */ .messenger-connection { display: flex; align-items: center; gap: 8px; padding: 12px 20px; background: var(--bp-surface-elevated); border-bottom: 1px solid var(--bp-border); font-size: 12px; color: var(--bp-text-muted); } .messenger-connection-dot { width: 8px; height: 8px; border-radius: 50%; background: #10b981; } .messenger-connection-dot.connecting { background: #f59e0b; animation: pulse 1s infinite; } .messenger-connection-dot.offline { background: #ef4444; } @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } } /* Date Separator */ .messenger-date-separator { display: flex; align-items: center; gap: 16px; margin: 16px 0; } .messenger-date-separator::before, .messenger-date-separator::after { content: ''; flex: 1; height: 1px; background: var(--bp-border); } .messenger-date-separator span { font-size: 12px; color: var(--bp-text-muted); padding: 4px 12px; background: var(--bp-surface-elevated); border-radius: 12px; } /* Typing Indicator */ .messenger-typing { display: flex; align-items: center; gap: 8px; padding: 8px 16px; font-size: 12px; color: var(--bp-text-muted); } .messenger-typing-dots { display: flex; gap: 4px; } .messenger-typing-dots span { width: 6px; height: 6px; border-radius: 50%; background: var(--bp-text-muted); animation: typingDot 1.4s infinite; } .messenger-typing-dots span:nth-child(2) { animation-delay: 0.2s; } .messenger-typing-dots span:nth-child(3) { animation-delay: 0.4s; } @keyframes typingDot { 0%, 60%, 100% { transform: translateY(0); } 30% { transform: translateY(-4px); } } /* Modal Styles */ .messenger-modal-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.5); display: flex; align-items: center; justify-content: center; z-index: 10000; } .messenger-modal { background: var(--bp-surface); border-radius: 16px; width: 90%; max-width: 480px; max-height: 80vh; display: flex; flex-direction: column; box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); } .messenger-modal-header { display: flex; justify-content: space-between; align-items: center; padding: 20px; border-bottom: 1px solid var(--bp-border); } .messenger-modal-header h3 { margin: 0; font-size: 18px; font-weight: 600; color: var(--bp-text); } .messenger-modal-close { width: 32px; height: 32px; border: none; background: var(--bp-surface-elevated); border-radius: 8px; font-size: 20px; color: var(--bp-text-muted); cursor: pointer; display: flex; align-items: center; justify-content: center; } .messenger-modal-close:hover { background: var(--bp-primary-soft); color: var(--bp-primary); } .messenger-modal-search { padding: 16px 20px; border-bottom: 1px solid var(--bp-border); } .messenger-modal-search input { width: 100%; padding: 12px 16px; border: 1px solid var(--bp-border); border-radius: 10px; background: var(--bp-bg); color: var(--bp-text); font-size: 14px; } .messenger-modal-search input:focus { outline: none; border-color: var(--bp-primary); } .messenger-modal-content { flex: 1; overflow-y: auto; padding: 8px 0; } .messenger-contact-item { display: flex; align-items: center; gap: 12px; padding: 12px 20px; cursor: pointer; transition: background 0.2s; } .messenger-contact-item:hover { background: var(--bp-surface-elevated); } .messenger-contact-info { flex: 1; } .messenger-contact-name { font-size: 14px; font-weight: 500; color: var(--bp-text); } .messenger-contact-role { font-size: 12px; color: var(--bp-text-muted); } /* Admin Tab Styles */ .messenger-admin-tab { padding: 8px 16px; background: var(--bp-surface-elevated); color: var(--bp-text-muted); border: none; border-radius: 8px; font-size: 12px; cursor: pointer; margin: 8px 20px; } .messenger-admin-tab:hover { background: var(--bp-primary-soft); color: var(--bp-primary); } """ @staticmethod def get_html() -> str: """HTML fuer das Messenger-Modul.""" return """
""" @staticmethod def get_js() -> str: """JavaScript fuer das Messenger-Modul.""" return """ // ============================================= // MESSENGER MODULE - Matrix Chat Integration // ============================================= let messengerInitialized = false; let currentConversationId = null; let messengerSocket = null; let messengerContacts = []; let messengerConversations = []; let messengerMessages = {}; let messengerTemplates = []; let messengerGroups = []; // API Base URL const MESSENGER_API = '/api/messenger'; // Fallback Templates (wenn API nicht erreichbar) const defaultTemplates = [ { id: 'default-1', name: 'Terminbestaetigung', content: 'Vielen Dank fuer Ihre Terminanfrage. Ich bestaetige den Termin am [DATUM] um [UHRZEIT]. Bitte geben Sie mir Bescheid, falls sich etwas aendern sollte.', category: 'termin' }, { id: 'default-2', name: 'Hausaufgaben-Info', content: 'Zur Information: Die Hausaufgaben fuer diese Woche umfassen [THEMA]. Abgabetermin ist [DATUM]. Bei Fragen stehe ich gerne zur Verfuegung.', category: 'hausaufgaben' }, { id: 'default-3', name: 'Entschuldigung bestaetigen', content: 'Ich bestaetige den Erhalt der Entschuldigung fuer [NAME] am [DATUM]. Die Fehlzeiten wurden entsprechend vermerkt.', category: 'entschuldigung' }, { id: 'default-4', name: 'Gespraechsanfrage', content: 'Ich wuerde gerne einen Termin fuer ein Gespraech mit Ihnen vereinbaren, um [THEMA] zu besprechen. Waeren Sie am [DATUM] um [UHRZEIT] verfuegbar?', category: 'gespraech' } ]; async function loadMessengerModule() { if (messengerInitialized) { console.log('Messenger module already initialized'); return; } console.log('Loading Messenger Module...'); // Initialize search const searchInput = document.getElementById('messenger-search-input'); if (searchInput) { searchInput.addEventListener('input', (e) => { filterConversations(e.target.value); }); } // Initialize message input const messageInput = document.getElementById('messenger-input'); if (messageInput) { messageInput.addEventListener('input', () => { const sendBtn = document.getElementById('messenger-send-btn'); if (sendBtn) { sendBtn.disabled = !messageInput.value.trim(); } }); } // Load data from API await loadMessengerData(); // Connect to Matrix (mock) connectToMatrix(); messengerInitialized = true; console.log('Messenger Module loaded successfully'); } // Load all messenger data from API async function loadMessengerData() { try { // Load contacts, conversations, templates, groups in parallel const [contactsRes, convsRes, templatesRes, groupsRes] = await Promise.all([ fetch(`${MESSENGER_API}/contacts`), fetch(`${MESSENGER_API}/conversations`), fetch(`${MESSENGER_API}/templates`), fetch(`${MESSENGER_API}/groups`) ]); if (contactsRes.ok) { messengerContacts = await contactsRes.json(); console.log(`Loaded ${messengerContacts.length} contacts`); } if (convsRes.ok) { messengerConversations = await convsRes.json(); console.log(`Loaded ${messengerConversations.length} conversations`); renderConversationList(); } if (templatesRes.ok) { messengerTemplates = await templatesRes.json(); console.log(`Loaded ${messengerTemplates.length} templates`); } else { messengerTemplates = defaultTemplates; } renderTemplateList(); if (groupsRes.ok) { messengerGroups = await groupsRes.json(); console.log(`Loaded ${messengerGroups.length} groups`); } } catch (error) { console.error('Error loading messenger data:', error); messengerTemplates = defaultTemplates; renderTemplateList(); } } // Render conversation list from API data function renderConversationList() { const container = document.getElementById('messenger-conversations'); if (!container || messengerConversations.length === 0) return; // Keep demo conversations if no API data if (messengerConversations.length === 0) return; container.innerHTML = messengerConversations.map(conv => { const isGroup = conv.type === 'group'; const unreadCount = conv.unread_count || 0; const isUnread = unreadCount > 0; const avatar = isGroup ? '👥' : '👱'; const lastTime = conv.last_message_time ? formatMessageTime(conv.last_message_time) : ''; return `Keine Kontakte vorhanden.
Fuegen Sie Kontakte hinzu oder importieren Sie eine CSV-Datei.