- Implemented alert notes JavaScript module for loading and displaying alerts for customers and contacts. - Created HTML template for alert boxes to display alerts inline on detail pages. - Developed modal for creating and editing alert notes with form validation and user restrictions. - Added modal for displaying alerts with acknowledgment functionality. - Enhanced user experience with toast notifications for successful operations.
199 lines
6.7 KiB
HTML
199 lines
6.7 KiB
HTML
<!-- Alert Notes Modal Component - For popup display -->
|
|
<div class="modal fade" id="alertNoteModal" tabindex="-1" aria-labelledby="alertNoteModalLabel" aria-hidden="true">
|
|
<div class="modal-dialog modal-dialog-centered">
|
|
<div class="modal-content">
|
|
<div class="modal-header" id="alertModalHeader">
|
|
<h5 class="modal-title" id="alertNoteModalLabel">
|
|
<i class="bi bi-exclamation-triangle-fill"></i> Vigtig information
|
|
</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Luk"></button>
|
|
</div>
|
|
<div class="modal-body" id="alertModalBody">
|
|
<!-- Alert content will be inserted here -->
|
|
</div>
|
|
<div class="modal-footer" id="alertModalFooter">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Luk</button>
|
|
<button type="button" class="btn btn-primary" id="alertModalAcknowledgeBtn" style="display: none;">
|
|
<i class="bi bi-check-circle"></i> Forstået
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
#alertNoteModal .modal-header.severity-info {
|
|
background: linear-gradient(135deg, #0dcaf0 0%, #00b4d8 100%);
|
|
color: white;
|
|
}
|
|
|
|
#alertNoteModal .modal-header.severity-warning {
|
|
background: linear-gradient(135deg, #ffc107 0%, #ffb703 100%);
|
|
color: #000;
|
|
}
|
|
|
|
#alertNoteModal .modal-header.severity-critical {
|
|
background: linear-gradient(135deg, #dc3545 0%, #bb2d3b 100%);
|
|
color: white;
|
|
}
|
|
|
|
.alert-modal-content {
|
|
padding: 15px 0;
|
|
}
|
|
|
|
.alert-modal-title {
|
|
font-weight: 600;
|
|
font-size: 1.2rem;
|
|
margin-bottom: 15px;
|
|
padding-bottom: 10px;
|
|
border-bottom: 2px solid #dee2e6;
|
|
}
|
|
|
|
.alert-modal-message {
|
|
line-height: 1.6;
|
|
margin-bottom: 15px;
|
|
white-space: pre-wrap;
|
|
}
|
|
|
|
.alert-modal-restrictions {
|
|
background: #f8f9fa;
|
|
padding: 15px;
|
|
border-radius: 8px;
|
|
border-left: 4px solid #0f4c75;
|
|
margin-top: 15px;
|
|
}
|
|
|
|
[data-bs-theme="dark"] .alert-modal-restrictions {
|
|
background: #2c3034;
|
|
}
|
|
|
|
.alert-modal-restrictions strong {
|
|
display: block;
|
|
margin-bottom: 8px;
|
|
color: var(--accent);
|
|
}
|
|
|
|
.alert-modal-restrictions ul {
|
|
margin-bottom: 0;
|
|
padding-left: 20px;
|
|
}
|
|
|
|
.alert-modal-meta {
|
|
font-size: 0.85rem;
|
|
color: var(--text-secondary);
|
|
margin-top: 15px;
|
|
padding-top: 15px;
|
|
border-top: 1px solid #dee2e6;
|
|
}
|
|
</style>
|
|
|
|
<script>
|
|
let currentAlertModal = null;
|
|
let currentAlerts = [];
|
|
|
|
function showAlertModal(alerts) {
|
|
if (!alerts || alerts.length === 0) return;
|
|
|
|
currentAlerts = alerts;
|
|
const modal = document.getElementById('alertNoteModal');
|
|
const modalHeader = document.getElementById('alertModalHeader');
|
|
const modalBody = document.getElementById('alertModalBody');
|
|
const modalAckBtn = document.getElementById('alertModalAcknowledgeBtn');
|
|
|
|
// Set severity styling (use highest severity)
|
|
const highestSeverity = alerts.find(a => a.severity === 'critical') ? 'critical' :
|
|
alerts.find(a => a.severity === 'warning') ? 'warning' : 'info';
|
|
|
|
modalHeader.className = `modal-header severity-${highestSeverity}`;
|
|
|
|
// Build content
|
|
let contentHtml = '';
|
|
|
|
alerts.forEach((alert, index) => {
|
|
const severityText = alert.severity === 'info' ? 'INFO' :
|
|
alert.severity === 'warning' ? 'ADVARSEL' : 'KRITISK';
|
|
|
|
let restrictionsHtml = '';
|
|
if (alert.restrictions && alert.restrictions.length > 0) {
|
|
const restrictionsList = alert.restrictions
|
|
.map(r => `<li>${r.restriction_name}</li>`)
|
|
.join('');
|
|
restrictionsHtml = `
|
|
<div class="alert-modal-restrictions">
|
|
<strong><i class="bi bi-shield-lock"></i> Kun følgende må håndtere denne ${alert.entity_type === 'customer' ? 'kunde' : 'kontakt'}:</strong>
|
|
<ul>${restrictionsList}</ul>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
const createdBy = alert.created_by_user_name ? ` • Oprettet af ${alert.created_by_user_name}` : '';
|
|
|
|
contentHtml += `
|
|
<div class="alert-modal-content" data-alert-id="${alert.id}">
|
|
${index > 0 ? '<hr>' : ''}
|
|
<div class="alert-modal-title">
|
|
<span class="badge bg-${alert.severity === 'critical' ? 'danger' : alert.severity === 'warning' ? 'warning' : 'info'}">
|
|
${severityText}
|
|
</span>
|
|
${alert.title}
|
|
</div>
|
|
<div class="alert-modal-message">${alert.message}</div>
|
|
${restrictionsHtml}
|
|
<div class="alert-modal-meta">
|
|
<i class="bi bi-calendar"></i> ${new Date(alert.created_at).toLocaleDateString('da-DK', {
|
|
year: 'numeric',
|
|
month: 'long',
|
|
day: 'numeric'
|
|
})}${createdBy}
|
|
</div>
|
|
</div>
|
|
`;
|
|
});
|
|
|
|
modalBody.innerHTML = contentHtml;
|
|
|
|
// Show acknowledge button if any alert requires it and user hasn't acknowledged
|
|
const requiresAck = alerts.some(a => a.requires_acknowledgement && !a.user_has_acknowledged);
|
|
if (requiresAck) {
|
|
modalAckBtn.style.display = 'inline-block';
|
|
modalAckBtn.onclick = function() {
|
|
acknowledgeAllAlerts();
|
|
};
|
|
} else {
|
|
modalAckBtn.style.display = 'none';
|
|
}
|
|
|
|
// Show modal
|
|
currentAlertModal = new bootstrap.Modal(modal);
|
|
currentAlertModal.show();
|
|
}
|
|
|
|
function acknowledgeAllAlerts() {
|
|
const promises = currentAlerts
|
|
.filter(a => a.requires_acknowledgement && !a.user_has_acknowledged)
|
|
.map(alert => {
|
|
return fetch(`/api/v1/alert-notes/${alert.id}/acknowledge`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
}
|
|
});
|
|
});
|
|
|
|
Promise.all(promises)
|
|
.then(() => {
|
|
if (currentAlertModal) {
|
|
currentAlertModal.hide();
|
|
}
|
|
// Reload alerts on the page if in inline view
|
|
if (typeof loadAlerts === 'function') {
|
|
loadAlerts();
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error acknowledging alerts:', error);
|
|
alert('Kunne ikke markere som læst. Prøv igen.');
|
|
});
|
|
}
|
|
</script>
|