Initial commit: Queensway Europe Telco Portal (Flask + SQLite, Docker deploy)

This commit is contained in:
Martin Belan
2026-09-11 07:23:40 +00:00
commit 919df2220e
42 changed files with 2206 additions and 0 deletions
+148
View File
@@ -0,0 +1,148 @@
{% extends "base.html" %}
{% block title %}Internet Connectivity - Queensway Europe Telco Portal{% endblock %}
{% block content %}
<div class="d-flex justify-content-between align-items-center mb-3">
<h2 class="mb-0 d-flex align-items-center gap-2">{% include "icons/wifi.svg" %} Internet Connectivity</h2>
{% if session.role == 'admin' %}
<button type="button" class="btn btn-success" onclick="openConnModal(null)">+ Add Connection</button>
{% endif %}
</div>
<div class="table-responsive">
<table class="table table-striped table-hover align-middle bg-white">
<thead class="table-dark">
<tr>
<th>Venue</th>
<th>ISP Provider</th>
<th>Plan</th>
<th>Contract Expiration</th>
<th>Notes</th>
{% if session.role == 'admin' %}<th class="text-end">Actions</th>{% endif %}
</tr>
</thead>
<tbody>
{% for c in connections %}
<tr>
<td>{{ c.venue }}</td>
<td>{{ c.isp_provider or "" }}</td>
<td>{{ c.plan or "" }}</td>
<td>{{ c.contract_expiration.strftime("%d-%m-%Y") if c.contract_expiration else "" }}</td>
<td>{{ c.notes or "" }}</td>
{% if session.role == 'admin' %}
<td class="text-end">
<button type="button" class="btn btn-sm btn-outline-primary"
onclick='openConnModal({{ c.to_dict() | tojson }})'>Edit</button>
<button type="button" class="btn btn-sm btn-outline-danger"
onclick="deleteConn({{ c.id }}, {{ c.venue | tojson }})">Delete</button>
</td>
{% endif %}
</tr>
{% else %}
<tr><td colspan="{{ 6 if session.role == 'admin' else 5 }}" class="text-center text-muted py-4">No internet connections recorded yet.</td></tr>
{% endfor %}
</tbody>
</table>
</div>
<!-- Edit / Add modal -->
<div class="modal fade" id="connModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<form id="connForm">
<div class="modal-header">
<h5 class="modal-title" id="connModalTitle">Edit Connection</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<input type="hidden" id="connId">
<div class="mb-3">
<label class="form-label">Venue</label>
<input type="text" class="form-control" id="connVenue" required>
</div>
<div class="mb-3">
<label class="form-label">ISP Provider</label>
<input type="text" class="form-control" id="connProvider">
</div>
<div class="mb-3">
<label class="form-label">Plan</label>
<input type="text" class="form-control" id="connPlan">
</div>
<div class="mb-3">
<label class="form-label">Contract Expiration</label>
<input type="date" class="form-control" id="connContractExpiration">
</div>
<div class="mb-3">
<label class="form-label">Notes</label>
<textarea class="form-control" id="connNotes" rows="3"></textarea>
</div>
<div id="connError" class="text-danger small"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-primary">Save</button>
</div>
</form>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
const connModalEl = document.getElementById('connModal');
const connModal = new bootstrap.Modal(connModalEl);
function openConnModal(conn) {
document.getElementById('connForm').reset();
document.getElementById('connError').textContent = '';
if (conn) {
document.getElementById('connModalTitle').textContent = 'Edit Connection';
document.getElementById('connId').value = conn.id;
document.getElementById('connVenue').value = conn.venue || '';
document.getElementById('connProvider').value = conn.isp_provider || '';
document.getElementById('connPlan').value = conn.plan || '';
document.getElementById('connContractExpiration').value = conn.contract_expiration || '';
document.getElementById('connNotes').value = conn.notes || '';
} else {
document.getElementById('connModalTitle').textContent = 'Add Connection';
document.getElementById('connId').value = '';
}
connModal.show();
}
document.getElementById('connForm').addEventListener('submit', async function (e) {
e.preventDefault();
const id = document.getElementById('connId').value;
const payload = {
venue: document.getElementById('connVenue').value,
isp_provider: document.getElementById('connProvider').value,
plan: document.getElementById('connPlan').value,
contract_expiration: document.getElementById('connContractExpiration').value,
notes: document.getElementById('connNotes').value,
};
const url = id ? `/api/internet/${id}` : '/api/internet';
const method = id ? 'PUT' : 'POST';
const resp = await fetch(url, {
method,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
});
if (resp.ok) {
window.location.reload();
} else {
const data = await resp.json().catch(() => ({}));
document.getElementById('connError').textContent = data.error || 'Failed to save. Please check the fields.';
}
});
async function deleteConn(id, venue) {
if (!confirm(`Delete internet connection for "${venue}"? This cannot be undone.`)) return;
const resp = await fetch(`/api/internet/${id}`, { method: 'DELETE' });
if (resp.ok) {
window.location.reload();
} else {
alert('Failed to delete.');
}
}
</script>
{% endblock %}