Dateien
Hetzner-Backup/v2_adminpanel/leads/templates/leads/all_contacts.html
2025-06-19 17:59:50 +02:00

239 Zeilen
9.6 KiB
HTML

{% extends "base.html" %}
{% block title %}Alle Kontakte{% endblock %}
{% block content %}
<div class="container-fluid">
<div class="row mb-4">
<div class="col-md-8">
<h1 class="h2 mb-0">
<i class="bi bi-people"></i> Alle Kontakte
</h1>
<p class="text-muted mb-0">Übersicht aller Kontakte aus allen Institutionen</p>
</div>
<div class="col-md-4 text-end">
<a href="{{ url_for('leads.institutions') }}" class="btn btn-secondary">
<i class="bi bi-building"></i> Zu Institutionen
</a>
</div>
</div>
<!-- Search and Filter Bar -->
<div class="row mb-4">
<div class="col-md-6">
<div class="input-group">
<span class="input-group-text"><i class="bi bi-search"></i></span>
<input type="text" class="form-control" id="searchInput"
placeholder="Nach Name, Institution oder Position suchen..."
onkeyup="filterContacts()">
</div>
</div>
<div class="col-md-3">
<select class="form-select" id="institutionFilter" onchange="filterContacts()">
<option value="">Alle Institutionen</option>
{% set institutions = contacts | map(attribute='institution_name') | unique | sort %}
{% for institution in institutions %}
<option value="{{ institution }}">{{ institution }}</option>
{% endfor %}
</select>
</div>
<div class="col-md-3">
<div class="btn-group" role="group">
<button type="button" class="btn btn-outline-secondary" onclick="sortContacts('name')">
<i class="bi bi-sort-alpha-down"></i> Name
</button>
<button type="button" class="btn btn-outline-secondary" onclick="sortContacts('institution')">
<i class="bi bi-building"></i> Institution
</button>
<button type="button" class="btn btn-outline-secondary" onclick="sortContacts('updated')">
<i class="bi bi-clock"></i> Aktualisiert
</button>
</div>
</div>
</div>
<!-- Contacts Table -->
<div class="card">
<div class="card-body">
<div class="table-responsive">
<table class="table table-hover" id="contactsTable">
<thead>
<tr>
<th>Name</th>
<th>Institution</th>
<th>Position</th>
<th>Kontaktdaten</th>
<th>Notizen</th>
<th>Zuletzt aktualisiert</th>
<th>Aktionen</th>
</tr>
</thead>
<tbody>
{% for contact in contacts %}
<tr data-name="{{ contact.last_name }} {{ contact.first_name }}"
data-institution="{{ contact.institution_name }}"
data-updated="{{ contact.updated_at or contact.created_at }}">
<td>
<a href="{{ url_for('leads.contact_detail', contact_id=contact.id) }}"
class="text-decoration-none">
<strong>{{ contact.last_name }}, {{ contact.first_name }}</strong>
</a>
</td>
<td>
<a href="{{ url_for('leads.institution_detail', institution_id=contact.institution_id) }}"
class="text-decoration-none text-muted">
{{ contact.institution_name }}
</a>
</td>
<td>{{ contact.position or '-' }}</td>
<td>
{% if contact.phone_count > 0 %}
<span class="badge bg-info me-1" title="Telefonnummern">
<i class="bi bi-telephone"></i> {{ contact.phone_count }}
</span>
{% endif %}
{% if contact.email_count > 0 %}
<span class="badge bg-primary" title="E-Mail-Adressen">
<i class="bi bi-envelope"></i> {{ contact.email_count }}
</span>
{% endif %}
{% if contact.phone_count == 0 and contact.email_count == 0 %}
<span class="text-muted">-</span>
{% endif %}
</td>
<td>
{% if contact.note_count > 0 %}
<span class="badge bg-secondary">
<i class="bi bi-sticky"></i> {{ contact.note_count }}
</span>
{% else %}
<span class="text-muted">-</span>
{% endif %}
</td>
<td>
{{ (contact.updated_at or contact.created_at).strftime('%d.%m.%Y %H:%M') }}
</td>
<td>
<a href="{{ url_for('leads.contact_detail', contact_id=contact.id) }}"
class="btn btn-sm btn-outline-primary">
<i class="bi bi-eye"></i> Details
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% if not contacts %}
<div class="text-center py-4">
<p class="text-muted">Noch keine Kontakte vorhanden.</p>
<a href="{{ url_for('leads.institutions') }}" class="btn btn-primary">
<i class="bi bi-building"></i> Zu Institutionen
</a>
</div>
{% endif %}
</div>
</div>
</div>
<!-- Contact Count -->
{% if contacts %}
<div class="row mt-3">
<div class="col-12">
<p class="text-muted">
<span id="visibleCount">{{ contacts|length }}</span> von {{ contacts|length }} Kontakten angezeigt
</p>
</div>
</div>
{% endif %}
</div>
<script>
// Current sort order
let currentSort = { field: 'name', ascending: true };
// Filter contacts
function filterContacts() {
const searchTerm = document.getElementById('searchInput').value.toLowerCase();
const institutionFilter = document.getElementById('institutionFilter').value.toLowerCase();
const rows = document.querySelectorAll('#contactsTable tbody tr');
let visibleCount = 0;
rows.forEach(row => {
const text = row.textContent.toLowerCase();
const institution = row.getAttribute('data-institution').toLowerCase();
const matchesSearch = searchTerm === '' || text.includes(searchTerm);
const matchesInstitution = institutionFilter === '' || institution === institutionFilter;
if (matchesSearch && matchesInstitution) {
row.style.display = '';
visibleCount++;
} else {
row.style.display = 'none';
}
});
// Update visible count
const countElement = document.getElementById('visibleCount');
if (countElement) {
countElement.textContent = visibleCount;
}
}
// Sort contacts
function sortContacts(field) {
const tbody = document.querySelector('#contactsTable tbody');
const rows = Array.from(tbody.querySelectorAll('tr'));
// Toggle sort order if same field
if (currentSort.field === field) {
currentSort.ascending = !currentSort.ascending;
} else {
currentSort.field = field;
currentSort.ascending = true;
}
// Sort rows
rows.sort((a, b) => {
let aValue, bValue;
switch(field) {
case 'name':
aValue = a.getAttribute('data-name');
bValue = b.getAttribute('data-name');
break;
case 'institution':
aValue = a.getAttribute('data-institution');
bValue = b.getAttribute('data-institution');
break;
case 'updated':
aValue = new Date(a.getAttribute('data-updated'));
bValue = new Date(b.getAttribute('data-updated'));
break;
}
if (field === 'updated') {
return currentSort.ascending ? aValue - bValue : bValue - aValue;
} else {
const comparison = aValue.localeCompare(bValue);
return currentSort.ascending ? comparison : -comparison;
}
});
// Re-append sorted rows
rows.forEach(row => tbody.appendChild(row));
// Update button states
document.querySelectorAll('.btn-group button').forEach(btn => {
btn.classList.remove('active');
});
event.target.classList.add('active');
}
// Initialize
document.addEventListener('DOMContentLoaded', function() {
// Set initial sort
sortContacts('name');
});
</script>
{% endblock %}