Dateien
Hetzner-Backup/v2_adminpanel/leads/templates/leads/contact_detail.html
2025-06-19 16:04:26 +02:00

502 Zeilen
20 KiB
HTML

{% extends "base.html" %}
{% block title %}{{ contact.first_name }} {{ contact.last_name }} - Kontakt-Details{% 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-person"></i> {{ contact.first_name }} {{ contact.last_name }}
</h1>
<p class="mb-0">
<span class="text-muted">{{ contact.position or 'Keine Position' }}</span>
<span class="mx-2"></span>
<a href="{{ url_for('leads.institution_detail', institution_id=contact.institution_id) }}"
class="text-decoration-none">
{{ contact.institution_name }}
</a>
</p>
</div>
<div class="col-md-4 text-end">
<button class="btn btn-outline-primary" onclick="editContact()">
<i class="bi bi-pencil"></i> Bearbeiten
</button>
<a href="{{ url_for('leads.institution_detail', institution_id=contact.institution_id) }}"
class="btn btn-secondary">
<i class="bi bi-arrow-left"></i> Zurück
</a>
</div>
</div>
<div class="row">
<!-- Contact Details -->
<div class="col-md-6">
<!-- Phone Numbers -->
<div class="card mb-3">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0"><i class="bi bi-telephone"></i> Telefonnummern</h5>
<button class="btn btn-sm btn-primary" onclick="showAddPhoneModal()">
<i class="bi bi-plus"></i>
</button>
</div>
<div class="card-body">
{% if contact.phones %}
<ul class="list-group list-group-flush">
{% for phone in contact.phones %}
<li class="list-group-item d-flex justify-content-between align-items-center">
<div>
<strong>{{ phone.detail_value }}</strong>
{% if phone.detail_label %}
<span class="badge bg-secondary">{{ phone.detail_label }}</span>
{% endif %}
</div>
<button class="btn btn-sm btn-outline-danger"
onclick="deleteDetail('{{ phone.id }}')">
<i class="bi bi-trash"></i>
</button>
</li>
{% endfor %}
</ul>
{% else %}
<p class="text-muted mb-0">Keine Telefonnummern hinterlegt.</p>
{% endif %}
</div>
</div>
<!-- Email Addresses -->
<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0"><i class="bi bi-envelope"></i> E-Mail-Adressen</h5>
<button class="btn btn-sm btn-primary" onclick="showAddEmailModal()">
<i class="bi bi-plus"></i>
</button>
</div>
<div class="card-body">
{% if contact.emails %}
<ul class="list-group list-group-flush">
{% for email in contact.emails %}
<li class="list-group-item d-flex justify-content-between align-items-center">
<div>
<a href="mailto:{{ email.detail_value }}">{{ email.detail_value }}</a>
{% if email.detail_label %}
<span class="badge bg-secondary">{{ email.detail_label }}</span>
{% endif %}
</div>
<button class="btn btn-sm btn-outline-danger"
onclick="deleteDetail('{{ email.id }}')">
<i class="bi bi-trash"></i>
</button>
</li>
{% endfor %}
</ul>
{% else %}
<p class="text-muted mb-0">Keine E-Mail-Adressen hinterlegt.</p>
{% endif %}
</div>
</div>
</div>
<!-- Notes -->
<div class="col-md-6">
<div class="card">
<div class="card-header">
<h5 class="mb-0"><i class="bi bi-journal-text"></i> Notizen</h5>
</div>
<div class="card-body">
<!-- New Note Form -->
<div class="mb-3">
<textarea class="form-control" id="newNoteText" rows="3"
placeholder="Neue Notiz hinzufügen..."></textarea>
<button class="btn btn-primary btn-sm mt-2" onclick="addNote()">
<i class="bi bi-plus"></i> Notiz speichern
</button>
</div>
<!-- Notes List -->
<div id="notesList">
{% for note in contact.notes %}
<div class="card mb-2" id="note-{{ note.id }}">
<div class="card-body">
<div class="d-flex justify-content-between align-items-start mb-2">
<small class="text-muted">
<i class="bi bi-clock"></i>
{{ note.created_at.strftime('%d.%m.%Y %H:%M') }}
{% if note.created_by %} • {{ note.created_by }}{% endif %}
{% if note.version > 1 %}
<span class="badge bg-info">v{{ note.version }}</span>
{% endif %}
</small>
<div>
<button class="btn btn-sm btn-link p-0 mx-1"
onclick="editNote('{{ note.id }}')">
<i class="bi bi-pencil"></i>
</button>
<button class="btn btn-sm btn-link text-danger p-0 mx-1"
onclick="deleteNote('{{ note.id }}')">
<i class="bi bi-trash"></i>
</button>
</div>
</div>
<div class="note-content" id="note-content-{{ note.id }}">
{{ note.note_text|nl2br|safe }}
</div>
<div class="note-edit d-none" id="note-edit-{{ note.id }}">
<textarea class="form-control mb-2" id="note-edit-text-{{ note.id }}">{{ note.note_text }}</textarea>
<button class="btn btn-sm btn-primary" onclick="saveNote('{{ note.id }}')">
Speichern
</button>
<button class="btn btn-sm btn-secondary" onclick="cancelEdit('{{ note.id }}')">
Abbrechen
</button>
</div>
</div>
</div>
{% endfor %}
</div>
{% if not contact.notes %}
<p class="text-muted">Noch keine Notizen vorhanden.</p>
{% endif %}
</div>
</div>
</div>
</div>
</div>
<!-- Modals -->
<!-- Edit Contact Modal -->
<div class="modal fade" id="editContactModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Kontakt bearbeiten</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<form id="editContactForm">
<div class="row">
<div class="col-md-6 mb-3">
<label for="editFirstName" class="form-label">Vorname</label>
<input type="text" class="form-control" id="editFirstName"
value="{{ contact.first_name }}" required>
</div>
<div class="col-md-6 mb-3">
<label for="editLastName" class="form-label">Nachname</label>
<input type="text" class="form-control" id="editLastName"
value="{{ contact.last_name }}" required>
</div>
</div>
<div class="mb-3">
<label for="editPosition" class="form-label">Position</label>
<input type="text" class="form-control" id="editPosition"
value="{{ contact.position or '' }}">
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Abbrechen</button>
<button type="button" class="btn btn-primary" onclick="updateContact()">Speichern</button>
</div>
</div>
</div>
</div>
<!-- Add Phone Modal -->
<div class="modal fade" id="addPhoneModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Telefonnummer hinzufügen</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<form id="addPhoneForm">
<div class="mb-3">
<label for="phoneNumber" class="form-label">Telefonnummer</label>
<input type="tel" class="form-control" id="phoneNumber" required>
</div>
<div class="mb-3">
<label for="phoneType" class="form-label">Typ</label>
<select class="form-select" id="phoneType">
<option value="">Bitte wählen...</option>
<option value="Mobil">Mobil</option>
<option value="Geschäftlich">Geschäftlich</option>
<option value="Privat">Privat</option>
<option value="Fax">Fax</option>
</select>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Abbrechen</button>
<button type="button" class="btn btn-primary" onclick="savePhone()">Speichern</button>
</div>
</div>
</div>
</div>
<!-- Add Email Modal -->
<div class="modal fade" id="addEmailModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">E-Mail-Adresse hinzufügen</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<form id="addEmailForm">
<div class="mb-3">
<label for="emailAddress" class="form-label">E-Mail-Adresse</label>
<input type="email" class="form-control" id="emailAddress" required>
</div>
<div class="mb-3">
<label for="emailType" class="form-label">Typ</label>
<select class="form-select" id="emailType">
<option value="">Bitte wählen...</option>
<option value="Geschäftlich">Geschäftlich</option>
<option value="Privat">Privat</option>
</select>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Abbrechen</button>
<button type="button" class="btn btn-primary" onclick="saveEmail()">Speichern</button>
</div>
</div>
</div>
</div>
<script>
const contactId = '{{ contact.id }}';
// Contact functions
function editContact() {
new bootstrap.Modal(document.getElementById('editContactModal')).show();
}
async function updateContact() {
const firstName = document.getElementById('editFirstName').value.trim();
const lastName = document.getElementById('editLastName').value.trim();
const position = document.getElementById('editPosition').value.trim();
if (!firstName || !lastName) {
alert('Bitte geben Sie Vor- und Nachname ein.');
return;
}
try {
const response = await fetch(`/leads/api/contacts/${contactId}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
first_name: firstName,
last_name: lastName,
position: position
})
});
const data = await response.json();
if (data.success) {
location.reload();
} else {
alert('Fehler: ' + (data.error || 'Unbekannter Fehler'));
}
} catch (error) {
alert('Fehler beim Speichern: ' + error.message);
}
}
// Phone functions
function showAddPhoneModal() {
document.getElementById('addPhoneForm').reset();
new bootstrap.Modal(document.getElementById('addPhoneModal')).show();
}
async function savePhone() {
const phoneNumber = document.getElementById('phoneNumber').value.trim();
const phoneType = document.getElementById('phoneType').value;
if (!phoneNumber) {
alert('Bitte geben Sie eine Telefonnummer ein.');
return;
}
try {
const response = await fetch(`/leads/api/contacts/${contactId}/phones`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
phone_number: phoneNumber,
phone_type: phoneType
})
});
const data = await response.json();
if (data.success) {
location.reload();
} else {
alert('Fehler: ' + (data.error || 'Unbekannter Fehler'));
}
} catch (error) {
alert('Fehler beim Speichern: ' + error.message);
}
}
// Email functions
function showAddEmailModal() {
document.getElementById('addEmailForm').reset();
new bootstrap.Modal(document.getElementById('addEmailModal')).show();
}
async function saveEmail() {
const email = document.getElementById('emailAddress').value.trim();
const emailType = document.getElementById('emailType').value;
if (!email) {
alert('Bitte geben Sie eine E-Mail-Adresse ein.');
return;
}
try {
const response = await fetch(`/leads/api/contacts/${contactId}/emails`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email: email,
email_type: emailType
})
});
const data = await response.json();
if (data.success) {
location.reload();
} else {
alert('Fehler: ' + (data.error || 'Unbekannter Fehler'));
}
} catch (error) {
alert('Fehler beim Speichern: ' + error.message);
}
}
// Delete detail
async function deleteDetail(detailId) {
if (!confirm('Möchten Sie diesen Eintrag wirklich löschen?')) {
return;
}
try {
const response = await fetch(`/leads/api/details/${detailId}`, {
method: 'DELETE'
});
const data = await response.json();
if (data.success) {
location.reload();
} else {
alert('Fehler beim Löschen');
}
} catch (error) {
alert('Fehler: ' + error.message);
}
}
// Note functions
async function addNote() {
const noteText = document.getElementById('newNoteText').value.trim();
if (!noteText) {
alert('Bitte geben Sie eine Notiz ein.');
return;
}
try {
const response = await fetch(`/leads/api/contacts/${contactId}/notes`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ note_text: noteText })
});
const data = await response.json();
if (data.success) {
location.reload();
} else {
alert('Fehler: ' + (data.error || 'Unbekannter Fehler'));
}
} catch (error) {
alert('Fehler beim Speichern: ' + error.message);
}
}
function editNote(noteId) {
// Text aus dem angezeigten Content holen
const contentDiv = document.getElementById(`note-content-${noteId}`);
const textarea = document.getElementById(`note-edit-text-${noteId}`);
// Der Text ist bereits im Textarea durch das Template
document.getElementById(`note-content-${noteId}`).classList.add('d-none');
document.getElementById(`note-edit-${noteId}`).classList.remove('d-none');
// Fokus auf Textarea setzen
textarea.focus();
}
function cancelEdit(noteId) {
document.getElementById(`note-content-${noteId}`).classList.remove('d-none');
document.getElementById(`note-edit-${noteId}`).classList.add('d-none');
}
async function saveNote(noteId) {
const noteText = document.getElementById(`note-edit-text-${noteId}`).value.trim();
if (!noteText) {
alert('Notiz darf nicht leer sein.');
return;
}
try {
const response = await fetch(`/leads/api/notes/${noteId}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ note_text: noteText })
});
const data = await response.json();
if (data.success) {
location.reload();
} else {
alert('Fehler: ' + (data.error || 'Unbekannter Fehler'));
}
} catch (error) {
alert('Fehler beim Speichern: ' + error.message);
}
}
async function deleteNote(noteId) {
if (!confirm('Möchten Sie diese Notiz wirklich löschen?')) {
return;
}
try {
const response = await fetch(`/leads/api/notes/${noteId}`, {
method: 'DELETE'
});
const data = await response.json();
if (data.success) {
location.reload();
} else {
alert('Fehler beim Löschen');
}
} catch (error) {
alert('Fehler: ' + error.message);
}
}
</script>
<style>
.note-content {
white-space: pre-wrap;
}
</style>
{% endblock %}