Adb wohneinheit/add contacts

This commit is contained in:
Luca Haid
2025-09-16 14:10:03 +00:00
parent fd39ba1db2
commit 0496103841
6 changed files with 371 additions and 2 deletions

View File

@@ -179,7 +179,10 @@
</tr>
<?php foreach($address->wohneinheiten as $unit): ?>
<tr>
<td><a href="<?=self::getUrl("ADBWohneinheit", "edit", ["id" => $unit->id])?>"><i class="fas fa-edit"></i></a></td>
<td>
<a href="#" data-home-id="<?=$unit->id?>" data-home-contact title="Kontakte bearbeiten"><i class="fas fa-users-cog text-primary"></i></a>
<a href="<?=self::getUrl("ADBWohneinheit", "edit", ["id" => $unit->id])?>"><i class="fas fa-edit"></i></a>
</td>
<td><?=$unit->id?></td>
<td class="text-pink">
<?php if($unit->oaid): ?>
@@ -391,4 +394,4 @@
'json');
}
</script>
<?php include(realpath(dirname(__FILE__)."/../../$mfLayoutPackage")."/footer.php"); ?>
<?php include(realpath(dirname(__FILE__)."/../../$mfLayoutPackage")."/footer.php"); ?>

View File

@@ -628,6 +628,7 @@ $pagination_entity_name = "Vorbestellungen";
<td style="text-align: left; letter-spacing: 4px; font-size: 1.1em;">
<div class="preorder-campaign-table-actions">
<?php if(!$me->is(["preorderfront"]) && !$me->is("preorderreadonly")): ?>
<a href="#" data-home-id="<?=$preorder->adb_wohneinheit_id?>" data-home-contact title="Kontakte bearbeiten"><i class="fas fa-users-cog text-primary"></i></a>
<a href="<?=self::getUrl("Preorder", "edit", ["id" => $preorder->id])?>"><i class="far fa-edit" title="Vorbestellung Bearbeiten"></i></a>
<a href="<?=self::getUrl("Preorder", "delete", ["id" => $preorder->id, "filter" => $filter])?>" class="text-danger" onclick="if(!confirm('Vorbestellung wirklich löschen?')) return false;" title="Vorbestellung Löschen"><i class="fas fa-trash"></i></a>
<?php endif; ?>
@@ -2011,4 +2012,7 @@ $pagination_entity_name = "Vorbestellungen";
updateRimoTypesLink();
});
</script>
<script src="<?= self::getResourcePath() ?>js/pages/AddressDB/ADBWohneinheitContactManager.js"></script>
<script src="<?= self::getResourcePath() ?>plugins/axios/axios.min.js"></script>
<script src="<?= self::getResourcePath() ?>plugins/axios/axios.inject.js"></script>
<?php include(realpath(dirname(__FILE__)."/../../$mfLayoutPackage")."/footer.php"); ?>

View File

@@ -237,4 +237,50 @@ class ADBWohneinheitController extends mfBaseController {
"IS_ADMIN" => $isAdmin,
]);
}
protected function getContactsAction() {
$post = json_decode(file_get_contents('php://input'), true);
if (empty($post['id'])) {
self::returnJson(['success' => false, 'message' => 'Wohneinheit ID fehlt.']);
return;
}
$unit = new ADBWohneinheit($post['id']);
if (!$unit->id) {
self::returnJson(['success' => false, 'message' => 'Wohneinheit nicht gefunden.']);
return;
}
$contact = $unit->contact;
$contacts = !empty($contact) ? json_decode($contact, true) : [];
self::returnJson(['success' => true, 'contacts' => $contacts, 'header' =>
($unit->hausnummer->strasse ? $unit->hausnummer->strasse->name : '') . ' ' .
($unit->hausnummer ? $unit->hausnummer->hausnummer : '') . ', ' .
($unit->hausnummer->plz ? $unit->hausnummer->plz->plz : '') . ' ' .
($unit->hausnummer->ortschaft ? $unit->hausnummer->ortschaft->name : '')
]);
}
protected function saveContactsAction() {
$post = json_decode(file_get_contents('php://input'), true);
if (empty($post['id']) || !isset($post['data'])) {
self::returnJson(['success' => false, 'message' => 'ID oder Daten fehlen.']);
return;
}
$unit = new ADBWohneinheit($post['id']);
if (!$unit->id) {
self::returnJson(['success' => false, 'message' => 'Wohneinheit nicht gefunden.']);
return;
}
$unit->contact = json_encode($post['data']);
if ($unit->save()) {
self::returnJson(['success' => true, 'message' => 'Kontakt erfolgreich gespeichert.']);
} else {
self::returnJson(['success' => false, 'message' => 'Fehler beim Speichern der Kontakt.']);
}
}
}

View File

@@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class AdbWohneinheitAddContact extends AbstractMigration
{
public function up(): void
{
if ($this->getEnvironment() == 'addressdb') {
$table = $this->table('Wohneinheit');
if (!$table->hasColumn('contact')) {
$table->addColumn('contact', 'text', [
'null' => true,
'default' => null,
'after' => 'note'
])
->save();
}
}
}
public function down(): void
{
if ($this->getEnvironment() == 'addressdb') {
$table = $this->table('Wohneinheit');
if ($table->hasColumn('contact')) {
$table->removeColumn('contact')
->save();
}
}
}
}

View File

View File

@@ -0,0 +1,282 @@
const ADBWohneinheitContactManager = {
modal: null,
homeId: null,
header: null,
contacts: [],
editingIndex: null,
init() {
document.body.addEventListener('click', this.handleBodyClick.bind(this));
},
handleBodyClick(e) {
const trigger = e.target.closest('[data-home-id][data-home-contact]');
if (trigger) {
e.preventDefault();
this.homeId = trigger.dataset.homeId;
this.openModal();
}
},
async openModal() {
this.editingIndex = null;
this.createModal();
this.showLoading();
try {
const response = await axios.post('/ADBWohneinheit/getContacts', { id: this.homeId });
if (response.data.success) {
this.contacts = response.data.contacts || [];
this.header = response.data.header || {};
this.render();
} else {
this.showError(response.data.message);
}
} catch (error) {
this.showError('Fehler beim Laden der Kontaktdaten.');
console.error(error);
}
},
createModal() {
if (this.modal) {
$(this.modal).modal('hide');
this.modal.remove();
}
const modalHtml = `
<div class="modal fade" id="contactManagerModal" tabindex="-1" role="dialog" aria-labelledby="contactManagerModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="contactManagerModalLabel">Kontakt verwalten (WE-ID: ${this.homeId})</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
</div>
</div>
</div>
</div>
`;
document.body.insertAdjacentHTML('beforeend', modalHtml);
this.modal = document.getElementById('contactManagerModal');
$(this.modal).modal('show');
this.modal.addEventListener('hidden.bs.modal', () => {
if (document.body.contains(this.modal)) {
this.modal.remove();
}
this.modal = null;
});
},
render() {
const body = this.modal.querySelector('.modal-body');
const contactListHtml = this.contacts.map((contact, index) => this.renderContact(contact, index)).join('');
this.modal.querySelector('.modal-title').innerText = `Kontakt verwalten (WE-ID: ${this.homeId}) [${this.header}]`;
body.innerHTML = `
<div class="mb-4">
<h6>Bestehende Kontakte</h6>
${this.contacts.length ? `<ul class="list-group">${contactListHtml}</ul>` : '<p class="text-muted">Keine Kontakte vorhanden.</p>'}
</div>
<hr>
<div>
<h6>${this.editingIndex !== null ? 'Kontakt bearbeiten' : 'Neuen Kontakt hinzufügen'}</h6>
${this.renderForm(this.editingIndex !== null ? this.contacts[this.editingIndex] : {})}
</div>
`;
this.attachFormListeners();
},
renderContact(contact, index) {
const isCompany = contact.firma && contact.firma.trim() !== '';
const displayName = isCompany ? contact.firma : `${contact.vorname || ''} ${contact.nachname || ''}`.trim();
const typeLabel = contact.type === 'renter' ? 'Mieter' : (contact.type === 'prospect' ? 'Interessent' : '');
const typeBadge = typeLabel ? `<span class="badge badge-info ml-2">${typeLabel}</span>` : '';
return `
<li class="list-group-item d-flex justify-content-between align-items-center">
<div>
<strong>${displayName}</strong>${typeBadge}
<br>
<small class="text-muted">${contact.telefon || 'Kein Telefon'} | ${contact.email || 'Keine E-Mail'}</small>
</div>
<div>
<button class="btn btn-sm btn-outline-primary mr-2" data-action="edit" data-index="${index}"><i class="fas fa-edit"></i> Bearbeiten</button>
<button class="btn btn-sm btn-outline-danger" data-action="delete" data-index="${index}"><i class="fas fa-trash"></i> Löschen</button>
</div>
</li>
`;
},
renderForm(contact = {}) {
return `
<form id="contactForm" class="p-3 bg-light border rounded">
<div class="form-group row">
<label class="col-sm-3 col-form-label">Typ</label>
<div class="col-sm-9">
<select class="form-control form-control-sm" name="type" required>
<option value="" disabled ${!contact.type ? 'selected' : ''}>Bitte wählen...</option>
<option value="renter" ${contact.type === 'renter' ? 'selected' : ''}>Mieter</option>
<option value="prospect" ${contact.type === 'prospect' ? 'selected' : ''}>Interessent</option>
</select>
</div>
</div>
<div class="form-group row">
<label class="col-sm-3 col-form-label">Firma</label>
<div class="col-sm-9">
<input type="text" class="form-control form-control-sm" name="firma" value="${contact.firma || ''}" placeholder="Firmenname">
</div>
</div>
<div class="form-group row">
<label class="col-sm-3 col-form-label">Vorname</label>
<div class="col-sm-9">
<input type="text" class="form-control form-control-sm" name="vorname" value="${contact.vorname || ''}" placeholder="Vorname">
</div>
</div>
<div class="form-group row">
<label class="col-sm-3 col-form-label">Nachname</label>
<div class="col-sm-9">
<input type="text" class="form-control form-control-sm" name="nachname" value="${contact.nachname || ''}" placeholder="Nachname">
</div>
</div>
<div class="form-group row">
<label class="col-sm-3 col-form-label">Telefon</label>
<div class="col-sm-9">
<input type="tel" class="form-control form-control-sm" name="telefon" value="${contact.telefon || ''}" placeholder="Telefonnummer">
</div>
</div>
<div class="form-group row mb-0">
<label class="col-sm-3 col-form-label">E-Mail</label>
<div class="col-sm-9">
<input type="email" class="form-control form-control-sm" name="email" value="${contact.email || ''}" placeholder="E-Mail Adresse">
</div>
</div>
<hr>
<div class="text-right">
${this.editingIndex !== null ? `<button class="btn btn-secondary mr-2" data-action="cancel-edit" type="button">Abbrechen</button>` : ''}
<button class="btn btn-primary" type="submit"><i class="fas fa-save mr-1"></i> ${this.editingIndex !== null ? 'Änderungen speichern' : 'Kontakt hinzufügen'}</button>
</div>
</form>
`;
},
attachFormListeners() {
const form = this.modal.querySelector('#contactForm');
if (!form) return;
const firmaInput = form.querySelector('[name="firma"]');
const vornameInput = form.querySelector('[name="vorname"]');
const nachnameInput = form.querySelector('[name="nachname"]');
const togglePersonFields = () => {
const isCompany = firmaInput.value.trim() !== '';
vornameInput.disabled = isCompany;
nachnameInput.disabled = isCompany;
if (isCompany) {
vornameInput.value = '';
nachnameInput.value = '';
}
};
const toggleCompanyField = () => {
const isPerson = vornameInput.value.trim() !== '' || nachnameInput.value.trim() !== '';
firmaInput.disabled = isPerson;
if (isPerson) {
firmaInput.value = '';
}
};
firmaInput.addEventListener('input', togglePersonFields);
vornameInput.addEventListener('input', toggleCompanyField);
nachnameInput.addEventListener('input', toggleCompanyField);
togglePersonFields();
toggleCompanyField();
form.addEventListener('submit', this.handleFormSubmit.bind(this));
this.modal.querySelector('.modal-body').addEventListener('click', (e) => {
const button = e.target.closest('button[data-action]');
if(!button) return;
e.preventDefault();
const action = button.dataset.action;
const index = button.dataset.index;
if (action === 'edit') this.handleEdit(index);
if (action === 'delete') this.handleDelete(index);
if (action === 'cancel-edit') this.handleCancelEdit();
});
},
handleFormSubmit(e) {
e.preventDefault();
const formData = new FormData(e.target);
const newContact = Object.fromEntries(formData.entries());
if (this.editingIndex !== null) {
this.contacts[this.editingIndex] = newContact;
} else {
this.contacts.push(newContact);
}
this.saveContacts();
},
handleEdit(index) {
this.editingIndex = parseInt(index, 10);
this.render();
},
handleCancelEdit() {
this.editingIndex = null;
this.render();
},
handleDelete(index) {
if (confirm('Sollen die Kontaktdaten wirklich gelöscht werden?')) {
this.contacts.splice(index, 1);
this.saveContacts();
}
},
async saveContacts() {
this.showLoading('Speichern...');
try {
const response = await axios.post('/ADBWohneinheit/saveContacts', {
id: this.homeId,
data: this.contacts
});
if (response.data.success) {
this.editingIndex = null;
const freshResponse = await axios.post('/ADBWohneinheit/getContacts', { id: this.homeId });
this.contacts = freshResponse.data.contacts || [];
this.render();
window.notify('success', response.data.message);
} else {
this.showError(response.data.message);
}
} catch(error) {
this.showError('Fehler beim Speichern der Kontaktdaten.');
console.error(error);
}
},
showLoading(message = 'Laden...') {
const body = this.modal.querySelector('.modal-body');
body.innerHTML = `<div class="text-center p-5"><div class="spinner-border text-primary" role="status"><span class="sr-only">Loading...</span></div><p class="mt-2">${message}</p></div>`;
},
showError(message) {
const body = this.modal.querySelector('.modal-body');
body.innerHTML = `<div class="alert alert-danger">${message}</div>`;
setTimeout(() => this.render(), 3000);
}
};
document.addEventListener('DOMContentLoaded', () => {
ADBWohneinheitContactManager.init();
});