agdar/templates/partial/header.html
Marwan Alwali f31362093e update
2025-11-02 16:38:29 +03:00

260 lines
12 KiB
HTML

{% load static %}
<div id="header" class="app-header" data-bs-theme="{% if appHeaderInverse %}dark{% endif %}">
<!-- BEGIN navbar-header -->
<div class="navbar-header">
{% if appSidebarTwo %}
<button type="button" class="navbar-mobile-toggler" data-toggle="app-sidebar-end-mobile">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
{% endif %}
<a href="/" class="navbar-brand"><img src="{% static 'img/logo/Agdar-Logo.png' %}" alt="" class="me-2" style="height: 64px; "></a>
{% if appHeaderMegaMenu %}
<button type="button" class="navbar-mobile-toggler collapsed" data-bs-toggle="collapse" data-bs-target="#top-navbar" aria-expanded="false">
<span class="fa-stack fa-lg">
<i class="far fa-square fa-stack-2x"></i>
<i class="fa fa-cog fa-stack-1x"></i>
</span>
</button>
{% endif %}
<button type="button" class="navbar-mobile-toggler" data-toggle="app-sidebar-mobile">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<!-- END navbar-header -->
<div class="navbar-nav">
<!-- Language Switcher - Always visible -->
<div class="navbar-item dropdown">
<a href="#" class="navbar-link dropdown-toggle" data-bs-toggle="dropdown">
<span class="d-none d-sm-inline"><i class="fa fa-globe"></i></span> <b class="caret"></b>
</a>
<div class="dropdown-menu dropdown-menu-end">
<a href="{% url 'switch_language' %}?language=en" class="dropdown-item">English</a>
<a href="{% url 'switch_language' %}?language=ar" class="dropdown-item">عربي</a>
</div>
</div>
<!-- Notifications - Only visible when authenticated -->
{% if request.user.is_authenticated %}
<div class="navbar-item dropdown">
<a href="#" class="navbar-link dropdown-toggle position-relative" data-bs-toggle="dropdown" id="notificationDropdown">
<i class="fa fa-bell"></i>
<span class="badge bg-danger rounded-pill position-absolute" id="notificationBadge" >0</span>
</a>
<div class="dropdown-menu dropdown-menu-end" style="width: 350px; max-height: 500px; overflow-y: auto;">
<div class="dropdown-header d-flex justify-content-between align-items-center">
<span class="fw-bold">{{ _("Notifications") }}</span>
<a href="#" class="text-decoration-none small" id="markAllRead">{{ _("Mark all as read")}}</a>
</div>
<div class="dropdown-divider"></div>
<div id="notificationList">
<div class="text-center py-3 text-muted">
<i class="fa fa-spinner fa-spin"></i> {{ _("Loading") }}...
</div>
</div>
<div class="dropdown-divider"></div>
<a href="{% url 'notifications:notification_list' %}" class="dropdown-item text-center small">
{{ _("View All Notifications")}}
</a>
</div>
</div>
<!-- User Menu - Only visible when authenticated -->
<div class="navbar-item navbar-user dropdown">
<a href="#" class="navbar-link dropdown-toggle d-flex align-items-center" data-bs-toggle="dropdown">
{% if request.user.profile_picture %}
<img src="{{ request.user.profile_picture.url}}" alt="" />
{% else %}
<img src="{% static 'img/user/user-12.jpg' %}" alt="" />
{% endif %}
<span>
<span class="d-none d-md-inline fw-bold">{{ request.user.get_full_name }}</span>
<b class="caret"></b>
</span>
</a>
<div class="dropdown-menu dropdown-menu-end me-1">
<a href="{% url 'core:user_profile' %}" class="dropdown-item">{{ _("User Profile")}}</a>
<a href="#" class="dropdown-item">{{ _("Calendar") }}</a>
<a href="{% url 'core:tenant_settings' %}" class="dropdown-item">{{ _("Settings") }}</a>
<div class="dropdown-divider"></div>
<form method="post" action="{% url 'logout' %}" class="d-inline">
{% csrf_token %}
<button type="submit" class="dropdown-item" style="border: none; background: none; cursor: pointer; text-align: left; width: 100%;">
{{ _("Log Out")}}
</button>
</form>
</div>
</div>
{% else %}
<!-- Login button for non-authenticated users -->
<div class="navbar-item">
<a href="{% url 'login' %}" class="navbar-link">
<i class="fa fa-sign-in-alt me-1"></i>
<span class="d-none d-sm-inline">{{ _("Login") }}</span>
</a>
</div>
{% endif %}
</div>
<!-- END header-nav -->
</div>
<!-- Notification Center JavaScript -->
{% if request.user.is_authenticated %}
<script>
document.addEventListener('DOMContentLoaded', function() {
// Load notifications on dropdown open
const notificationDropdown = document.getElementById('notificationDropdown');
const notificationList = document.getElementById('notificationList');
const notificationBadge = document.getElementById('notificationBadge');
const markAllReadBtn = document.getElementById('markAllRead');
// Function to update unread count
function updateUnreadCount() {
fetch('{% url "notifications:notification_unread_count" %}')
.then(response => response.json())
.then(data => {
const count = data.unread_count;
if (count > 0) {
notificationBadge.textContent = count > 99 ? '99+' : count;
notificationBadge.style.display = 'block';
} else {
notificationBadge.style.display = 'none';
}
})
.catch(error => console.error('Error fetching unread count:', error));
}
// Function to load notifications
function loadNotifications() {
fetch('{% url "notifications:notification_dropdown" %}')
.then(response => response.json())
.then(data => {
if (data.notifications.length === 0) {
notificationList.innerHTML = '<div class="text-center py-3 text-muted">{{_("No notifications")}}</div>';
} else {
notificationList.innerHTML = data.notifications.map(notif => {
const typeColors = {
'INFO': 'primary',
'SUCCESS': 'success',
'WARNING': 'warning',
'ERROR': 'danger'
};
const color = typeColors[notif.type] || 'secondary';
const readClass = notif.is_read ? 'bg-light' : '';
const readIcon = notif.is_read ? '<i class="fa fa-check-circle text-success ms-1" title="Read"></i>' : '';
const date = new Date(notif.created_at);
const timeAgo = getTimeAgo(date);
return `
<a href="${notif.action_url}" class="dropdown-item ${readClass}" data-notification-id="${notif.id}">
<div class="d-flex">
<div class="flex-shrink-0">
<span class="badge bg-${color} rounded-circle" style="width: 10px; height: 10px; padding: 0;"></span>
</div>
<div class="flex-grow-1 ms-2">
<div class="fw-bold small d-flex align-items-center">
${notif.title}
${readIcon}
</div>
<div class="text-muted small text-wrap">${notif.message}</div>
<div class="text-muted" style="font-size: 0.75rem;">${timeAgo}</div>
</div>
</div>
</a>
`;
}).join('');
// Add click handlers to mark as read
document.querySelectorAll('[data-notification-id]').forEach(item => {
item.addEventListener('click', function(e) {
const notifId = this.dataset.notificationId;
markAsRead(notifId);
});
});
}
})
.catch(error => {
console.error('Error loading notifications:', error);
notificationList.innerHTML = '<div class="text-center py-3 text-danger">{{_("Error loading notifications")}}</div>';
});
}
// Function to mark notification as read
function markAsRead(notificationId) {
const markReadUrl = '{% url "notifications:notification_mark_read" "00000000-0000-0000-0000-000000000000" %}'.replace('00000000-0000-0000-0000-000000000000', notificationId);
fetch(markReadUrl, {
method: 'POST',
headers: {
'X-CSRFToken': '{{ csrf_token }}',
'X-Requested-With': 'XMLHttpRequest'
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
updateUnreadCount();
}
})
.catch(error => console.error('Error marking as read:', error));
}
// Function to mark all as read
markAllReadBtn.addEventListener('click', function(e) {
e.preventDefault();
fetch('{% url "notifications:notification_mark_all_read" %}', {
method: 'POST',
headers: {
'X-CSRFToken': '{{ csrf_token }}',
'X-Requested-With': 'XMLHttpRequest'
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
updateUnreadCount();
loadNotifications();
}
})
.catch(error => console.error('Error marking all as read:', error));
});
// Helper function to get time ago
function getTimeAgo(date) {
const seconds = Math.floor((new Date() - date) / 1000);
let interval = seconds / 31536000;
if (interval > 1) return Math.floor(interval) + ' years ago';
interval = seconds / 2592000;
if (interval > 1) return Math.floor(interval) + ' months ago';
interval = seconds / 86400;
if (interval > 1) return Math.floor(interval) + ' days ago';
interval = seconds / 3600;
if (interval > 1) return Math.floor(interval) + ' hours ago';
interval = seconds / 60;
if (interval > 1) return Math.floor(interval) + ' minutes ago';
return 'Just now';
}
// Load notifications when dropdown is opened
notificationDropdown.addEventListener('click', function() {
loadNotifications();
});
// Initial load of unread count
updateUnreadCount();
// Poll for new notifications every 30 seconds
setInterval(updateUnreadCount, 30000);
});
</script>
{% endif %}