mirror of
https://github.com/idrainformatica/RoadmapMaker.git
synced 2026-04-18 10:53:48 +02:00
578 lines
20 KiB
HTML
578 lines
20 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="it">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Admin - Roadmap Manager</title>
|
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
|
|
<style>
|
|
* {
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
body {
|
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
background: #f8f9fa;
|
|
color: #2c3e50;
|
|
}
|
|
|
|
.sidebar {
|
|
position: fixed;
|
|
left: 0;
|
|
top: 0;
|
|
width: 250px;
|
|
height: 100vh;
|
|
background: linear-gradient(135deg, #2c3e50, #3498db);
|
|
color: white;
|
|
padding: 20px;
|
|
z-index: 1000;
|
|
}
|
|
|
|
.sidebar h2 {
|
|
margin-bottom: 30px;
|
|
text-align: center;
|
|
padding-bottom: 20px;
|
|
border-bottom: 1px solid rgba(255,255,255,0.2);
|
|
}
|
|
|
|
.nav-item {
|
|
padding: 15px 20px;
|
|
margin: 5px 0;
|
|
border-radius: 8px;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
}
|
|
|
|
.nav-item:hover, .nav-item.active {
|
|
background: rgba(255,255,255,0.1);
|
|
transform: translateX(5px);
|
|
}
|
|
|
|
.main-content {
|
|
margin-left: 250px;
|
|
padding: 30px;
|
|
}
|
|
|
|
.header {
|
|
background: white;
|
|
padding: 20px 30px;
|
|
border-radius: 15px;
|
|
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
|
margin-bottom: 30px;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
|
|
.btn {
|
|
padding: 12px 24px;
|
|
border: none;
|
|
border-radius: 8px;
|
|
cursor: pointer;
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
text-decoration: none;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.btn-primary {
|
|
background: #3498db;
|
|
color: white;
|
|
}
|
|
|
|
.btn-primary:hover {
|
|
background: #2980b9;
|
|
transform: translateY(-2px);
|
|
}
|
|
|
|
.btn-success {
|
|
background: #2ecc71;
|
|
color: white;
|
|
}
|
|
|
|
.btn-success:hover {
|
|
background: #27ae60;
|
|
}
|
|
|
|
.btn-danger {
|
|
background: #e74c3c;
|
|
color: white;
|
|
}
|
|
|
|
.btn-danger:hover {
|
|
background: #c0392b;
|
|
}
|
|
|
|
.btn-warning {
|
|
background: #f39c12;
|
|
color: white;
|
|
}
|
|
|
|
.card {
|
|
background: white;
|
|
border-radius: 15px;
|
|
padding: 25px;
|
|
box-shadow: 0 5px 20px rgba(0,0,0,0.1);
|
|
margin-bottom: 25px;
|
|
}
|
|
|
|
.card h3 {
|
|
margin-bottom: 20px;
|
|
color: #2c3e50;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
}
|
|
|
|
.form-group {
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.form-group label {
|
|
display: block;
|
|
margin-bottom: 8px;
|
|
font-weight: 500;
|
|
color: #2c3e50;
|
|
}
|
|
|
|
.form-control {
|
|
width: 100%;
|
|
padding: 12px 16px;
|
|
border: 2px solid #e9ecef;
|
|
border-radius: 8px;
|
|
font-size: 14px;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.form-control:focus {
|
|
outline: none;
|
|
border-color: #3498db;
|
|
box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1);
|
|
}
|
|
|
|
.milestone-item {
|
|
background: #f8f9fa;
|
|
border: 2px solid #e9ecef;
|
|
border-radius: 12px;
|
|
padding: 20px;
|
|
margin-bottom: 15px;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.milestone-item:hover {
|
|
border-color: #3498db;
|
|
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
|
|
}
|
|
|
|
.milestone-header {
|
|
display: flex;
|
|
justify-content: between;
|
|
align-items: center;
|
|
margin-bottom: 15px;
|
|
}
|
|
|
|
.milestone-title {
|
|
font-weight: 600;
|
|
color: #2c3e50;
|
|
flex-grow: 1;
|
|
}
|
|
|
|
.milestone-actions {
|
|
display: flex;
|
|
gap: 10px;
|
|
}
|
|
|
|
.status-badge {
|
|
padding: 6px 12px;
|
|
border-radius: 20px;
|
|
font-size: 12px;
|
|
font-weight: 500;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
.badge-completed {
|
|
background: #d5f4e6;
|
|
color: #27ae60;
|
|
}
|
|
|
|
.badge-in_progress {
|
|
background: #fdeaa7;
|
|
color: #f39c12;
|
|
}
|
|
|
|
.badge-pending {
|
|
background: #ecf0f1;
|
|
color: #95a5a6;
|
|
}
|
|
|
|
.modal {
|
|
display: none;
|
|
position: fixed;
|
|
z-index: 2000;
|
|
left: 0;
|
|
top: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background-color: rgba(0,0,0,0.5);
|
|
backdrop-filter: blur(5px);
|
|
}
|
|
|
|
.modal-content {
|
|
background: white;
|
|
margin: 3% auto;
|
|
padding: 30px;
|
|
border-radius: 15px;
|
|
max-width: 600px;
|
|
max-height: 80vh;
|
|
overflow-y: auto;
|
|
position: relative;
|
|
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
|
|
animation: modalSlide 0.3s ease-out;
|
|
}
|
|
|
|
@keyframes modalSlide {
|
|
from { opacity: 0; transform: translateY(-50px); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
|
|
.close {
|
|
position: absolute;
|
|
right: 20px;
|
|
top: 20px;
|
|
font-size: 28px;
|
|
cursor: pointer;
|
|
color: #aaa;
|
|
}
|
|
|
|
.close:hover {
|
|
color: #e74c3c;
|
|
}
|
|
|
|
.section {
|
|
display: none;
|
|
}
|
|
|
|
.section.active {
|
|
display: block;
|
|
}
|
|
|
|
.back-to-site {
|
|
position: fixed;
|
|
top: 30px;
|
|
right: 30px;
|
|
z-index: 1100;
|
|
}
|
|
|
|
.grid {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: 20px;
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.sidebar {
|
|
width: 100%;
|
|
height: auto;
|
|
position: relative;
|
|
}
|
|
|
|
.main-content {
|
|
margin-left: 0;
|
|
}
|
|
|
|
.grid {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="sidebar">
|
|
<h2><i class="fas fa-cogs"></i> Admin Panel</h2>
|
|
<div class="nav-item active" data-section="milestones">
|
|
<i class="fas fa-list"></i>
|
|
Gestione Milestone
|
|
</div>
|
|
<div class="nav-item" data-section="settings">
|
|
<i class="fas fa-cog"></i>
|
|
Impostazioni Progetto
|
|
</div>
|
|
<div style="margin-top: auto; padding-top: 20px; border-top: 1px solid rgba(255,255,255,0.2);">
|
|
<a href="/admin/logout" class="nav-item" style="text-decoration: none; color: inherit;">
|
|
<i class="fas fa-sign-out-alt"></i>
|
|
Logout
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="main-content">
|
|
<div class="header">
|
|
<h1><i class="fas fa-tachometer-alt"></i> Dashboard Admin</h1>
|
|
<a href="/" class="btn btn-primary">
|
|
<i class="fas fa-eye"></i> Visualizza Roadmap
|
|
</a>
|
|
</div>
|
|
|
|
<!-- Sezione Milestone -->
|
|
<div id="milestones" class="section active">
|
|
<div class="card">
|
|
<h3><i class="fas fa-plus"></i> Aggiungi Nuova Milestone</h3>
|
|
<form id="milestoneForm">
|
|
<div class="grid">
|
|
<div class="form-group">
|
|
<label for="title">Titolo</label>
|
|
<input type="text" id="title" class="form-control" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="order">Ordine</label>
|
|
<input type="number" id="order" class="form-control" value="{{ milestones|length + 1 }}" required>
|
|
</div>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="description">Descrizione Breve</label>
|
|
<input type="text" id="description" class="form-control" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="detailed_description">Descrizione Dettagliata</label>
|
|
<textarea id="detailed_description" class="form-control" rows="4"></textarea>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="status">Stato</label>
|
|
<select id="status" class="form-control">
|
|
<option value="pending">In Attesa</option>
|
|
<option value="in_progress">In Corso</option>
|
|
<option value="completed">Completato</option>
|
|
</select>
|
|
</div>
|
|
<button type="submit" class="btn btn-success">
|
|
<i class="fas fa-save"></i> Salva Milestone
|
|
</button>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h3><i class="fas fa-tasks"></i> Milestone Esistenti</h3>
|
|
<div id="milestonesList">
|
|
{% for milestone in milestones %}
|
|
<div class="milestone-item" data-id="{{ milestone.id }}">
|
|
<div class="milestone-header">
|
|
<div class="milestone-title">{{ milestone.order }}. {{ milestone.title }}</div>
|
|
<div class="milestone-actions">
|
|
<span class="status-badge badge-{{ milestone.status }}">
|
|
{% if milestone.status == 'completed' %}Completato
|
|
{% elif milestone.status == 'in_progress' %}In Corso
|
|
{% else %}In Attesa{% endif %}
|
|
</span>
|
|
<button class="btn btn-warning btn-sm" onclick="editMilestone({{ milestone.id }})">
|
|
<i class="fas fa-edit"></i>
|
|
</button>
|
|
<button class="btn btn-danger btn-sm" onclick="deleteMilestone({{ milestone.id }})">
|
|
<i class="fas fa-trash"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<p><strong>Descrizione:</strong> {{ milestone.description }}</p>
|
|
{% if milestone.detailed_description %}
|
|
<p><strong>Dettagli:</strong> {{ milestone.detailed_description[:100] }}...</p>
|
|
{% endif %}
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sezione Impostazioni -->
|
|
<div id="settings" class="section">
|
|
<div class="card">
|
|
<h3><i class="fas fa-sliders-h"></i> Impostazioni Progetto</h3>
|
|
<form id="settingsForm">
|
|
<div class="form-group">
|
|
<label for="project_name">Nome Progetto</label>
|
|
<input type="text" id="project_name" class="form-control" value="{{ settings.project_name if settings else 'Il Mio Progetto' }}">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="current_milestone">Milestone Corrente</label>
|
|
<select id="current_milestone" class="form-control">
|
|
{% for milestone in milestones %}
|
|
<option value="{{ milestone.id }}" {% if settings and settings.current_milestone_id == milestone.id %}selected{% endif %}>
|
|
{{ milestone.order }}. {{ milestone.title }}
|
|
</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="fas fa-save"></i> Salva Impostazioni
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Modal per Modifica Milestone -->
|
|
<div id="editModal" class="modal">
|
|
<div class="modal-content">
|
|
<span class="close">×</span>
|
|
<h2><i class="fas fa-edit"></i> Modifica Milestone</h2>
|
|
<form id="editMilestoneForm">
|
|
<input type="hidden" id="editId">
|
|
<div class="grid">
|
|
<div class="form-group">
|
|
<label for="editTitle">Titolo</label>
|
|
<input type="text" id="editTitle" class="form-control" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="editOrder">Ordine</label>
|
|
<input type="number" id="editOrder" class="form-control" required>
|
|
</div>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="editDescription">Descrizione Breve</label>
|
|
<input type="text" id="editDescription" class="form-control" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="editDetailedDescription">Descrizione Dettagliata</label>
|
|
<textarea id="editDetailedDescription" class="form-control" rows="4"></textarea>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="editStatus">Stato</label>
|
|
<select id="editStatus" class="form-control">
|
|
<option value="pending">In Attesa</option>
|
|
<option value="in_progress">In Corso</option>
|
|
<option value="completed">Completato</option>
|
|
</select>
|
|
</div>
|
|
<div style="display: flex; gap: 10px; justify-content: flex-end;">
|
|
<button type="button" class="btn btn-danger" onclick="closeModal()">Annulla</button>
|
|
<button type="submit" class="btn btn-success">
|
|
<i class="fas fa-save"></i> Salva Modifiche
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// Navigation
|
|
document.querySelectorAll('.nav-item').forEach(item => {
|
|
item.addEventListener('click', function() {
|
|
// Remove active class from all nav items and sections
|
|
document.querySelectorAll('.nav-item').forEach(n => n.classList.remove('active'));
|
|
document.querySelectorAll('.section').forEach(s => s.classList.remove('active'));
|
|
|
|
// Add active class to clicked nav item and corresponding section
|
|
this.classList.add('active');
|
|
document.getElementById(this.dataset.section).classList.add('active');
|
|
});
|
|
});
|
|
|
|
// Modal functionality
|
|
const modal = document.getElementById('editModal');
|
|
const closeBtn = document.getElementsByClassName('close')[0];
|
|
|
|
function closeModal() {
|
|
modal.style.display = 'none';
|
|
}
|
|
|
|
closeBtn.onclick = closeModal;
|
|
window.onclick = function(event) {
|
|
if (event.target == modal) {
|
|
closeModal();
|
|
}
|
|
}
|
|
|
|
// Add milestone
|
|
document.getElementById('milestoneForm').addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
|
|
const formData = {
|
|
title: document.getElementById('title').value,
|
|
description: document.getElementById('description').value,
|
|
detailed_description: document.getElementById('detailed_description').value,
|
|
order: parseInt(document.getElementById('order').value),
|
|
status: document.getElementById('status').value
|
|
};
|
|
|
|
fetch('/api/milestone', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(formData)
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
location.reload();
|
|
} else {
|
|
alert('Errore nel salvare la milestone');
|
|
}
|
|
});
|
|
});
|
|
|
|
// Edit milestone
|
|
function editMilestone(id) {
|
|
fetch(`/api/milestone/${id}`)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
document.getElementById('editId').value = data.id;
|
|
document.getElementById('editTitle').value = data.title;
|
|
document.getElementById('editDescription').value = data.description;
|
|
document.getElementById('editDetailedDescription').value = data.detailed_description || '';
|
|
document.getElementById('editOrder').value = data.order;
|
|
document.getElementById('editStatus').value = data.status;
|
|
modal.style.display = 'block';
|
|
});
|
|
}
|
|
|
|
// Update milestone
|
|
document.getElementById('editMilestoneForm').addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
|
|
const id = document.getElementById('editId').value;
|
|
const formData = {
|
|
title: document.getElementById('editTitle').value,
|
|
description: document.getElementById('editDescription').value,
|
|
detailed_description: document.getElementById('editDetailedDescription').value,
|
|
order: parseInt(document.getElementById('editOrder').value),
|
|
status: document.getElementById('editStatus').value
|
|
};
|
|
|
|
fetch(`/api/milestone/${id}`, {
|
|
method: 'PUT',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(formData)
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
location.reload();
|
|
} else {
|
|
alert('Errore nel salvare le modifiche');
|
|
}
|
|
});
|
|
});
|
|
|
|
// Delete milestone
|
|
function deleteMilestone(id) {
|
|
if (confirm('Sei sicuro di voler eliminare questa milestone?')) {
|
|
fetch(`/api/milestone/${id}`, {
|
|
method: 'DELETE'
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
location.reload();
|
|
} else {
|
|
alert('Errore nell\'eliminare la milestone');
|
|
}
|
|
|