Files
TenerifeProp/public/js/admin/modals/ServiceModal.js
APAW Agent Sync 8c1b897b9d feat(admin): replace prompt() with Bootstrap modals for CRUD operations
Replace browser prompt()-based editing with proper Bootstrap 5 modal
dialogs for testimonials, services, FAQs, and leads. This provides
better UX with form validation, structured input fields, and i18n
support (ES/RU) instead of raw prompt dialogs.

- Add testimonialModal, serviceModal, faqModal, leadModal to admin.html
- Add show*/save* methods in admin.js for each entity type
- Wire leads.html 'Add lead' button to leadModal
- Add modal JS modules (FAQModal, LeadModal, ServiceModal)
- Add unit and e2e tests for modals and API client
2026-05-16 00:43:04 +01:00

103 lines
4.3 KiB
JavaScript

export class ServiceModal {
constructor(app) {
this.app = app
this.id = 'serviceModal'
this.element = null
this.bsModal = null
this._editId = null
}
open(service = null) {
if (!this.element) this._build()
this._editId = service ? service.id : null
const title = this.element.querySelector('.modal-title')
const inputs = this.element.querySelectorAll('input[name], textarea[name]')
if (service) {
title.innerHTML = '<i class="bi bi-pencil me-2"></i>Editar servicio'
inputs.forEach(i => {
const key = i.getAttribute('name')
if (service[key] !== undefined) i.value = service[key]
if (i.type === 'checkbox') i.checked = service[key] !== false
})
} else {
title.innerHTML = '<i class="bi bi-briefcase me-2"></i>Añadir servicio'
inputs.forEach(i => { i.value = ''; if (i.type === 'checkbox') i.checked = true })
}
this.bsModal = new bootstrap.Modal(this.element)
this.bsModal.show()
}
close() {
if (this.bsModal) this.bsModal.hide()
}
async save() {
const data = this._collect()
if (!data.title_es || !data.title_es.trim()) {
this.app.showNotification('Título es obligatorio', 'error')
return
}
const res = this._editId
? await API.updateService(this._editId, data)
: await API.createService(data)
if (res.success) {
this.close()
this.app.showNotification(this._editId ? 'Servicio actualizado' : 'Servicio creado', 'success')
this.app.refreshSection('services')
} else {
this.app.showNotification(res.error || 'Error al guardar', 'error')
}
}
_collect() {
const d = {}
this.element.querySelectorAll('input[name], textarea[name], select[name]').forEach(i => {
const k = i.getAttribute('name')
d[k] = i.type === 'checkbox' ? i.checked : i.value
})
d.order_num = parseInt(d.order_num) || 0
d.is_active = d.is_active !== undefined ? d.is_active : true
return d
}
_build() {
const el = document.createElement('div')
el.id = this.id
el.className = 'modal fade'
el.innerHTML = `
<div class="modal-dialog modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"><i class="bi bi-briefcase me-2"></i>Añadir servicio</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div class="mb-3"><label class="form-label">Icono (clase Bootstrap)</label>
<input type="text" class="form-control" name="icon" placeholder="bi bi-key"></div>
<div class="mb-3"><label class="form-label">Título (ES)</label>
<input type="text" class="form-control" name="title_es" placeholder="Asesoría Legal"></div>
<div class="mb-3"><label class="form-label">Título (RU)</label>
<input type="text" class="form-control" name="title_ru" placeholder="Юридическая консультация"></div>
<div class="mb-3"><label class="form-label">Descripción (ES)</label>
<textarea class="form-control" rows="3" name="description_es" placeholder="Descripción del servicio..."></textarea></div>
<div class="mb-3"><label class="form-label">Descripción (RU)</label>
<textarea class="form-control" rows="3" name="description_ru" placeholder="Описание услуги..."></textarea></div>
<div class="mb-3"><label class="form-label">Orden</label>
<input type="number" class="form-control" name="order_num" placeholder="0"></div>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="is_active" id="serviceActive" checked>
<label class="form-check-label" for="serviceActive">Activo</label>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Cancelar</button>
<button type="button" class="btn btn-primary" onclick="window.app.modals.service.save()">
<i class="bi bi-check-lg me-2"></i>Guardar servicio</button>
</div>
</div>
</div>`
document.body.appendChild(el)
this.element = el
}
}