251 lines
14 KiB
HTML
251 lines
14 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}Edit Classroom - {{ classroom.code_display }}{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="container-fluid px-0">
|
|
<!-- Header -->
|
|
<div class="row mb-3 align-items-center">
|
|
<div class="col-md-7">
|
|
<nav aria-label="breadcrumb">
|
|
<ol class="breadcrumb mb-1 small">
|
|
<li class="breadcrumb-item"><a href="/classrooms/list_classrooms">Classrooms</a></li>
|
|
<li class="breadcrumb-item"><a href="/classrooms/view_classroom">{{ classroom.code_display }}</a></li>
|
|
<li class="breadcrumb-item active">Edit</li>
|
|
</ol>
|
|
</nav>
|
|
<h1 class="h3 mb-1">
|
|
<i class="bi bi-pencil-square text-primary me-2"></i>Edit Classroom
|
|
</h1>
|
|
<p class="text-muted small mb-0">{{ classroom.location_display }}</p>
|
|
</div>
|
|
<div class="col-md-5 text-md-end mt-3 mt-md-0">
|
|
<a href="/classrooms/view_classroom" class="btn btn-outline-secondary me-2">
|
|
<i class="bi bi-eye me-1"></i>Ver Detalle
|
|
</a>
|
|
<a href="/classrooms/list_classrooms" class="btn btn-outline-secondary">
|
|
<i class="bi bi-arrow-left me-1"></i>Volver al Listado
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row justify-content-center">
|
|
<div class="col-lg-8">
|
|
<div class="card border-0 shadow-sm">
|
|
<div class="card-header bg-body-tertiary border-0 py-3 d-flex justify-content-between align-items-center">
|
|
<h5 class="mb-0 h6 fw-bold">
|
|
<i class="bi bi-door-open text-primary me-2"></i>Classroom Information
|
|
</h5>
|
|
<span class="badge bg-secondary-subtle text-secondary font-monospace border">ID #{{ classroom.id }}</span>
|
|
</div>
|
|
<div class="card-body p-4">
|
|
<form method="POST" id="classroom-form" novalidate>
|
|
|
|
<div class="row g-3 mb-3">
|
|
<!-- Edificio -->
|
|
<div class="col-md-6">
|
|
<label for="building_id" class="form-label fw-semibold">
|
|
<i class="bi bi-buildings text-primary me-1"></i>Edificio / Sede <span class="text-danger">*</span>
|
|
</label>
|
|
{{ form.building_id(class="form-select", id="building_id") }}
|
|
{% if form.building_id.errors %}
|
|
<div class="text-danger small mt-1">{{ form.building_id.errors[0] }}</div>
|
|
{% endif %}
|
|
|
|
<div id="newBuildingContainer" class="mt-2 p-2 rounded bg-body-tertiary border border-success-subtle" style="display: none;">
|
|
<label for="new_building_name" class="form-label small fw-bold text-success mb-1">
|
|
<i class="bi bi-plus-circle me-1"></i>Nombre del Nuevo Edificio:
|
|
</label>
|
|
{{ form.new_building_name(class="form-control form-control-sm", id="new_building_name", placeholder="ej. Pabellón III") }}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Piso -->
|
|
<div class="col-md-3">
|
|
<label for="floor" class="form-label fw-semibold">
|
|
<i class="bi bi-layers text-secondary me-1"></i>Piso / Nivel <span class="text-danger">*</span>
|
|
</label>
|
|
{{ form.floor(class="form-control", id="floor", list="floorSuggestions", placeholder="ej. PB, 1, 2, 4°P") }}
|
|
<datalist id="floorSuggestions">
|
|
<!-- sugerencias dinámicas -->
|
|
</datalist>
|
|
<div class="form-text small text-muted">Sugerido o nuevo</div>
|
|
{% if form.floor.errors %}
|
|
<div class="text-danger small mt-1">{{ form.floor.errors[0] }}</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<!-- Aula -->
|
|
<div class="col-md-3">
|
|
<label for="room_number" class="form-label fw-semibold">
|
|
<i class="bi bi-door-open text-info me-1"></i>Aula / Sala <span class="text-danger">*</span>
|
|
</label>
|
|
{{ form.room_number(class="form-control", id="room_number", placeholder="ej. Aula 304, Lab 1") }}
|
|
{% if form.room_number.errors %}
|
|
<div class="text-danger small mt-1">{{ form.room_number.errors[0] }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row g-3 mb-3">
|
|
<div class="col-md-6">
|
|
<div class="d-flex justify-content-between align-items-center mb-1">
|
|
<label for="capacityInput" class="form-label fw-semibold mb-0">Capacidad de Alumnos <span class="text-danger">*</span></label>
|
|
<button type="button" class="btn btn-sm btn-outline-primary py-0 px-2" id="btnInfinity" style="font-size: 0.8rem;" title="Asignar capacidad ilimitada">
|
|
<i class="bi bi-infinity me-1"></i>Ilimitada (∞)
|
|
</button>
|
|
</div>
|
|
<div class="input-group">
|
|
{{ form.capacity(class="form-control" + (" is-invalid" if form.capacity.errors else ""), id="capacityInput", placeholder="ej. 35 o ∞") }}
|
|
<span class="input-group-text bg-body-tertiary text-muted font-monospace"><i class="bi bi-people"></i></span>
|
|
</div>
|
|
<div class="form-text small text-muted mt-1">
|
|
<i class="bi bi-info-circle text-info me-1"></i>Para aulas virtuales o eventos sin aforo restringido, ingrese <strong>∞</strong> o <strong>0</strong>.
|
|
</div>
|
|
{% if form.capacity.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.capacity.errors[0] }}</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<div class="col-md-6 d-flex align-items-center pt-md-3">
|
|
<div class="form-check form-switch pt-2">
|
|
{{ form.is_active(class="form-check-input", id="is_active") }}
|
|
<label class="form-check-label fw-semibold" for="is_active">
|
|
Aula Habilitada para Reservas
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-4">
|
|
{{ form.description.label(class="form-label fw-semibold") }}
|
|
{{ form.description(class="form-control" + (" is-invalid" if form.description.errors else ""), rows="3", placeholder="Opcional: Detalles adicionales del equipamiento...") }}
|
|
{% if form.description.errors %}
|
|
<div class="invalid-feedback">{{ form.description.errors[0] }}</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<!-- Preview Card -->
|
|
<div class="card bg-body-tertiary border-0 shadow-xs mb-4">
|
|
<div class="card-body py-3 px-4">
|
|
<h6 class="card-subtitle mb-2 text-muted small fw-bold">
|
|
<i class="bi bi-eye me-1"></i>Vista Previa de Ubicación
|
|
</h6>
|
|
<div class="row g-2">
|
|
<div class="col-md-4">
|
|
<small class="text-muted d-block">🏢 Edificio</small>
|
|
<strong id="preview-building" class="text-primary">{{ classroom.building_name }}</strong>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<small class="text-muted d-block">🪜 Piso</small>
|
|
<strong id="preview-floor" class="text-secondary">{{ classroom.floor_display }}</strong>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<small class="text-muted d-block">🚪 Aula / Código</small>
|
|
<strong id="preview-room" class="text-success">{{ classroom.code }}</strong>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="d-flex justify-content-between">
|
|
<a href="/classrooms/view_classroom" class="btn btn-outline-secondary">
|
|
Cancelar
|
|
</a>
|
|
<button type="submit" class="btn btn-primary px-4">
|
|
<i class="bi bi-check-circle me-1"></i>Guardar Cambios
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block extra_js %}
|
|
<script type="application/json" id="buildingFloorsData">
|
|
{{ building_floors|tojson|safe }}
|
|
</script>
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
var buildingFloorsDataEl = document.getElementById('buildingFloorsData');
|
|
var buildingFloors = buildingFloorsDataEl ? JSON.parse(buildingFloorsDataEl.textContent || '{}') : {};
|
|
|
|
var buildingSelect = document.getElementById('building_id');
|
|
var newBuildingContainer = document.getElementById('newBuildingContainer');
|
|
var newBuildingNameInput = document.getElementById('new_building_name');
|
|
var floorInput = document.getElementById('floor');
|
|
var floorDatalist = document.getElementById('floorSuggestions');
|
|
var roomInput = document.getElementById('room_number');
|
|
|
|
var previewBuilding = document.getElementById('preview-building');
|
|
var previewFloor = document.getElementById('preview-floor');
|
|
var previewRoom = document.getElementById('preview-room');
|
|
|
|
function updateFloorsDatalist(bId) {
|
|
if (!floorDatalist) return;
|
|
floorDatalist.innerHTML = '';
|
|
var floors = buildingFloors[bId] || [];
|
|
floors.forEach(function(f) {
|
|
var opt = document.createElement('option');
|
|
opt.value = f;
|
|
opt.textContent = (f === '0' || f === 'PB') ? 'Planta Baja' : 'Piso ' + f;
|
|
floorDatalist.appendChild(opt);
|
|
});
|
|
}
|
|
|
|
function updatePreview() {
|
|
var bText = '-';
|
|
if (buildingSelect) {
|
|
if (buildingSelect.value === '__new__') {
|
|
bText = newBuildingNameInput.value.trim() || '{{ _("Nuevo Edificio") }}';
|
|
} else if (buildingSelect.selectedIndex >= 0) {
|
|
bText = buildingSelect.options[buildingSelect.selectedIndex].text;
|
|
}
|
|
}
|
|
var fText = floorInput ? (floorInput.value.trim() || '-') : '-';
|
|
var rText = roomInput ? (roomInput.value.trim() || '-') : '-';
|
|
|
|
if (previewBuilding) previewBuilding.textContent = bText;
|
|
if (previewFloor) previewFloor.textContent = (fText === '0' || fText.toUpperCase() === 'PB') ? 'Planta Baja' : fText;
|
|
if (previewRoom) previewRoom.textContent = rText;
|
|
}
|
|
|
|
if (buildingSelect) {
|
|
buildingSelect.addEventListener('change', function() {
|
|
if (this.value === '__new__') {
|
|
newBuildingContainer.style.display = 'block';
|
|
if (newBuildingNameInput) newBuildingNameInput.focus();
|
|
} else {
|
|
newBuildingContainer.style.display = 'none';
|
|
updateFloorsDatalist(this.value);
|
|
}
|
|
updatePreview();
|
|
});
|
|
if (buildingSelect.value === '__new__') {
|
|
newBuildingContainer.style.display = 'block';
|
|
} else if (buildingSelect.value) {
|
|
updateFloorsDatalist(buildingSelect.value);
|
|
}
|
|
}
|
|
|
|
if (newBuildingNameInput) newBuildingNameInput.addEventListener('input', updatePreview);
|
|
if (floorInput) floorInput.addEventListener('input', updatePreview);
|
|
if (roomInput) roomInput.addEventListener('input', updatePreview);
|
|
|
|
updatePreview();
|
|
|
|
var btnInf = document.getElementById('btnInfinity');
|
|
var capInput = document.getElementById('capacityInput');
|
|
if (btnInf && capInput) {
|
|
btnInf.addEventListener('click', function() {
|
|
capInput.value = '∞';
|
|
capInput.focus();
|
|
});
|
|
}
|
|
});
|
|
</script>
|
|
{% endblock %}
|