/** * TASKMATE - Contacts Manager * =========================== * Kontaktverwaltung mit Kartenansicht */ import api from './api.js'; import { $, $$, formatDate, debounce } from './utils.js'; import store from './store.js'; class ContactsManager { constructor() { this.contacts = []; this.filteredContacts = []; this.allTags = new Set(); this.searchQuery = ''; this.filterTag = ''; this.sortBy = 'created_at'; this.sortOrder = 'desc'; this.initialized = false; } async init() { console.log('[Contacts] init() called, initialized:', this.initialized); if (this.initialized) { await this.loadContacts(); return; } // DOM Elements this.contactsView = $('#view-contacts'); this.contactsGrid = $('#contacts-grid'); this.contactsEmpty = $('#contacts-empty'); this.tagFilter = $('#contacts-tag-filter'); this.sortSelect = $('#contacts-sort'); this.newContactBtn = $('#btn-new-contact'); console.log('[Contacts] DOM Elements check:'); console.log(' contactsView:', this.contactsView); console.log(' newContactBtn:', this.newContactBtn); console.log(' contactsGrid:', this.contactsGrid); // Modal Elements this.contactModal = $('#contact-modal'); this.modalTitle = $('#contact-modal-title'); this.contactForm = $('#contact-form'); console.log('[Contacts] Modal Elements check:'); console.log(' contactModal:', this.contactModal); console.log(' contactForm:', this.contactForm); this.contactIdInput = $('#contact-id'); this.firstNameInput = $('#contact-first-name'); this.lastNameInput = $('#contact-last-name'); this.companyInput = $('#contact-company'); this.positionInput = $('#contact-position'); this.emailInput = $('#contact-email'); this.phoneInput = $('#contact-phone'); this.mobileInput = $('#contact-mobile'); this.addressInput = $('#contact-address'); this.postalCodeInput = $('#contact-postal-code'); this.cityInput = $('#contact-city'); this.countryInput = $('#contact-country'); this.websiteInput = $('#contact-website'); this.notesInput = $('#contact-notes'); this.tagsInput = $('#contact-tags'); this.deleteContactBtn = $('#btn-delete-contact'); this.bindEvents(); this.initialized = true; console.log('[Contacts] Initialization complete'); await this.loadContacts(); // Store subscriptions store.subscribe('contacts', this.handleContactsUpdate.bind(this)); // Window events window.addEventListener('app:refresh', () => this.loadContacts()); window.addEventListener('modal:close', () => this.loadContacts()); } bindEvents() { console.log('[Contacts] bindEvents() called'); // Tag Filter if (this.tagFilter) { this.tagFilter.addEventListener('change', (e) => { this.filterTag = e.target.value; this.filterContacts(); }); } // Sort if (this.sortSelect) { this.sortSelect.addEventListener('change', (e) => { const [sortBy, sortOrder] = e.target.value.split('-'); this.sortBy = sortBy; this.sortOrder = sortOrder; this.sortContacts(); this.renderContacts(); }); } // New Contact Button console.log('[Contacts] newContactBtn element:', this.newContactBtn); if (this.newContactBtn) { console.log('[Contacts] Binding click event to newContactBtn'); this.newContactBtn.addEventListener('click', () => { console.log('[Contacts] New contact button clicked!'); this.showContactModal(); }); } else { console.warn('[Contacts] newContactBtn not found!'); } // Modal Form if (this.contactForm) { this.contactForm.addEventListener('submit', (e) => { e.preventDefault(); this.saveContact(); }); } // Delete Button if (this.deleteContactBtn) { this.deleteContactBtn.addEventListener('click', () => this.deleteContact()); } // Modal Close const modalCloseBtn = this.contactModal?.querySelector('.modal-close'); if (modalCloseBtn) { modalCloseBtn.addEventListener('click', () => this.hideContactModal()); } const modalCancelBtn = this.contactModal?.querySelector('.modal-cancel'); if (modalCancelBtn) { modalCancelBtn.addEventListener('click', () => this.hideContactModal()); } // Socket Events const socket = window.socket; if (socket) { socket.on('contact:created', (data) => { console.log('[Contacts] Socket: contact created', data); this.contacts.unshift(data.contact); this.updateTagsList(); this.filterContacts(); }); socket.on('contact:updated', (data) => { console.log('[Contacts] Socket: contact updated', data); const index = this.contacts.findIndex(c => c.id === data.contact.id); if (index !== -1) { this.contacts[index] = data.contact; this.updateTagsList(); this.filterContacts(); } }); socket.on('contact:deleted', (data) => { console.log('[Contacts] Socket: contact deleted', data); this.contacts = this.contacts.filter(c => c.id !== data.contactId); this.updateTagsList(); this.filterContacts(); }); } } async loadContacts() { try { console.log('[Contacts] Loading contacts...'); const response = await api.getContacts(); this.contacts = response.data || response || []; this.updateTagsList(); this.filterContacts(); console.log(`[Contacts] Loaded ${this.contacts.length} contacts`); } catch (error) { console.error('[Contacts] Error loading contacts:', error); window.dispatchEvent(new CustomEvent('toast:show', { detail: { message: 'Fehler beim Laden der Kontakte', type: 'error' } })); } } filterContacts() { this.filteredContacts = this.contacts.filter(contact => { // Search filter if (this.searchQuery) { const query = this.searchQuery.toLowerCase(); const searchFields = [ contact.firstName, contact.lastName, contact.company, contact.email, contact.position, contact.phone, contact.mobile ].filter(Boolean).join(' ').toLowerCase(); if (!searchFields.includes(query)) { return false; } } // Tag filter if (this.filterTag && contact.tags) { if (!contact.tags.includes(this.filterTag)) { return false; } } return true; }); this.sortContacts(); this.renderContacts(); } sortContacts() { this.filteredContacts.sort((a, b) => { let aVal = a[this.sortBy] || ''; let bVal = b[this.sortBy] || ''; // Handle name sorting if (this.sortBy === 'name') { aVal = `${a.lastName || ''} ${a.firstName || ''}`.trim(); bVal = `${b.lastName || ''} ${b.firstName || ''}`.trim(); } if (typeof aVal === 'string') { aVal = aVal.toLowerCase(); bVal = bVal.toLowerCase(); } if (this.sortOrder === 'asc') { return aVal < bVal ? -1 : aVal > bVal ? 1 : 0; } else { return aVal > bVal ? -1 : aVal < bVal ? 1 : 0; } }); } renderContacts() { if (!this.contactsGrid) return; if (this.filteredContacts.length === 0) { this.contactsGrid.classList.add('hidden'); this.contactsEmpty.classList.remove('hidden'); return; } this.contactsGrid.classList.remove('hidden'); this.contactsEmpty.classList.add('hidden'); const html = this.filteredContacts.map(contact => this.createContactCard(contact)).join(''); this.contactsGrid.innerHTML = html; // Bind card events this.bindCardEvents(); } createContactCard(contact) { const displayName = this.getContactDisplayName(contact); const initials = this.getContactInitials(contact); const tags = contact.tags || []; return `