Adb wohneinheit/add contacts
This commit is contained in:
@@ -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"); ?>
|
||||
|
||||
@@ -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"); ?>
|
||||
|
||||
@@ -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.']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
34
db/migrations/20250916153000_adb_wohneinheit_add_contact.php
Normal file
34
db/migrations/20250916153000_adb_wohneinheit_add_contact.php
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
0
public/js/pages/AddressDB/.gitkeep
Normal file
0
public/js/pages/AddressDB/.gitkeep
Normal file
282
public/js/pages/AddressDB/ADBWohneinheitContactManager.js
Normal file
282
public/js/pages/AddressDB/ADBWohneinheitContactManager.js
Normal 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">×</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();
|
||||
});
|
||||
Reference in New Issue
Block a user