unread notifs
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,9 +1,18 @@
|
|||||||
from flask import render_template, request, flash, redirect, url_for
|
from flask import render_template, request, flash, redirect, url_for, Blueprint, jsonify
|
||||||
from flask_login import login_user, logout_user, login_required, current_user
|
from flask_login import login_user, logout_user, login_required, current_user
|
||||||
from models import db, User
|
from models import db, User, Notif
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from utils import log_event, create_notification
|
from utils import log_event, create_notification, get_unread_count
|
||||||
|
|
||||||
|
auth_bp = Blueprint('auth', __name__)
|
||||||
|
|
||||||
|
@auth_bp.context_processor
|
||||||
|
def inject_unread_notifications():
|
||||||
|
if current_user.is_authenticated:
|
||||||
|
unread_count = get_unread_count(current_user.id)
|
||||||
|
return {'unread_notifications': unread_count}
|
||||||
|
return {'unread_notifications': 0}
|
||||||
|
|
||||||
def require_password_change(f):
|
def require_password_change(f):
|
||||||
@wraps(f)
|
@wraps(f)
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
from flask import Blueprint, render_template, redirect, url_for, flash, request
|
from flask import Blueprint, render_template, redirect, url_for, flash, request, jsonify
|
||||||
from flask_login import login_required, current_user
|
from flask_login import login_required, current_user
|
||||||
from models import db, User
|
from models import db, User, Notif
|
||||||
from forms import UserForm
|
from forms import UserForm
|
||||||
from flask import abort
|
from flask import abort
|
||||||
from sqlalchemy import or_
|
from sqlalchemy import or_
|
||||||
from routes.auth import require_password_change
|
from routes.auth import require_password_change
|
||||||
from utils import log_event, create_notification
|
from utils import log_event, create_notification, get_unread_count
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
from werkzeug.utils import secure_filename
|
from werkzeug.utils import secure_filename
|
||||||
@@ -17,6 +17,13 @@ UPLOAD_FOLDER = os.path.join(os.getcwd(), 'uploads', 'profile_pics')
|
|||||||
if not os.path.exists(UPLOAD_FOLDER):
|
if not os.path.exists(UPLOAD_FOLDER):
|
||||||
os.makedirs(UPLOAD_FOLDER)
|
os.makedirs(UPLOAD_FOLDER)
|
||||||
|
|
||||||
|
@contacts_bp.context_processor
|
||||||
|
def inject_unread_notifications():
|
||||||
|
if current_user.is_authenticated:
|
||||||
|
unread_count = get_unread_count(current_user.id)
|
||||||
|
return {'unread_notifications': unread_count}
|
||||||
|
return {'unread_notifications': 0}
|
||||||
|
|
||||||
def admin_required():
|
def admin_required():
|
||||||
if not current_user.is_authenticated:
|
if not current_user.is_authenticated:
|
||||||
return redirect(url_for('auth.login'))
|
return redirect(url_for('auth.login'))
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ from flask_login import login_required, current_user
|
|||||||
from models import db, Conversation, User, Message, MessageAttachment
|
from models import db, Conversation, User, Message, MessageAttachment
|
||||||
from forms import ConversationForm
|
from forms import ConversationForm
|
||||||
from routes.auth import require_password_change
|
from routes.auth import require_password_change
|
||||||
from utils import log_event, create_notification
|
from utils import log_event, create_notification, get_unread_count
|
||||||
import os
|
import os
|
||||||
from werkzeug.utils import secure_filename
|
from werkzeug.utils import secure_filename
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
@@ -54,7 +54,8 @@ def conversations():
|
|||||||
if search:
|
if search:
|
||||||
query = query.filter(Conversation.name.ilike(f'%{search}%'))
|
query = query.filter(Conversation.name.ilike(f'%{search}%'))
|
||||||
conversations = query.order_by(Conversation.created_at.desc()).all()
|
conversations = query.order_by(Conversation.created_at.desc()).all()
|
||||||
return render_template('conversations/conversations.html', conversations=conversations, search=search)
|
unread_count = get_unread_count(current_user.id)
|
||||||
|
return render_template('conversations/conversations.html', conversations=conversations, search=search, unread_notifications=unread_count)
|
||||||
|
|
||||||
@conversations_bp.route('/create', methods=['GET', 'POST'])
|
@conversations_bp.route('/create', methods=['GET', 'POST'])
|
||||||
@login_required
|
@login_required
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import logging
|
|||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
from forms import CompanySettingsForm
|
from forms import CompanySettingsForm
|
||||||
from utils import log_event, create_notification
|
from utils import log_event, create_notification, get_unread_count
|
||||||
|
|
||||||
# Set up logging to show in console
|
# Set up logging to show in console
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
@@ -28,6 +28,13 @@ def init_routes(main_bp):
|
|||||||
site_settings = SiteSettings.query.first()
|
site_settings = SiteSettings.query.first()
|
||||||
return dict(site_settings=site_settings)
|
return dict(site_settings=site_settings)
|
||||||
|
|
||||||
|
@main_bp.context_processor
|
||||||
|
def inject_unread_notifications():
|
||||||
|
if current_user.is_authenticated:
|
||||||
|
unread_count = get_unread_count(current_user.id)
|
||||||
|
return {'unread_notifications': unread_count}
|
||||||
|
return {'unread_notifications': 0}
|
||||||
|
|
||||||
@main_bp.route('/')
|
@main_bp.route('/')
|
||||||
@login_required
|
@login_required
|
||||||
@require_password_change
|
@require_password_change
|
||||||
|
|||||||
@@ -22,14 +22,14 @@ to maintain file metadata and content.
|
|||||||
from flask import Blueprint, jsonify, request, abort, send_from_directory, send_file
|
from flask import Blueprint, jsonify, request, abort, send_from_directory, send_file
|
||||||
from flask_login import login_required, current_user
|
from flask_login import login_required, current_user
|
||||||
import os
|
import os
|
||||||
from models import Room, RoomMemberPermission, RoomFile, TrashedFile, db
|
from models import Room, RoomMemberPermission, RoomFile, TrashedFile, db, User, Notif
|
||||||
from werkzeug.utils import secure_filename, safe_join
|
from werkzeug.utils import secure_filename, safe_join
|
||||||
import time
|
import time
|
||||||
import shutil
|
import shutil
|
||||||
import io
|
import io
|
||||||
import zipfile
|
import zipfile
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from utils import log_event
|
from utils import log_event, create_notification, get_unread_count
|
||||||
|
|
||||||
# Blueprint for room file operations
|
# Blueprint for room file operations
|
||||||
room_files_bp = Blueprint('room_files', __name__, url_prefix='/api/rooms')
|
room_files_bp = Blueprint('room_files', __name__, url_prefix='/api/rooms')
|
||||||
@@ -61,6 +61,13 @@ ALLOWED_EXTENSIONS = {
|
|||||||
'eml', 'msg', 'vcf', 'ics'
|
'eml', 'msg', 'vcf', 'ics'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@room_files_bp.context_processor
|
||||||
|
def inject_unread_notifications():
|
||||||
|
if current_user.is_authenticated:
|
||||||
|
unread_count = get_unread_count(current_user.id)
|
||||||
|
return {'unread_notifications': unread_count}
|
||||||
|
return {'unread_notifications': 0}
|
||||||
|
|
||||||
def get_room_dir(room_id):
|
def get_room_dir(room_id):
|
||||||
"""
|
"""
|
||||||
Get the absolute path to a room's directory.
|
Get the absolute path to a room's directory.
|
||||||
|
|||||||
@@ -1,10 +1,18 @@
|
|||||||
from flask import Blueprint, jsonify, request, abort
|
from flask import Blueprint, jsonify, request, abort, render_template, redirect, url_for, flash
|
||||||
from flask_login import login_required, current_user
|
from flask_login import login_required, current_user
|
||||||
from models import db, Room, User, RoomMemberPermission
|
from models import db, Room, User, RoomMemberPermission, Notif
|
||||||
from utils import user_has_permission, log_event, create_notification
|
from utils import user_has_permission, log_event, create_notification, get_unread_count
|
||||||
|
from routes.auth import require_password_change
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
room_members_bp = Blueprint('room_members', __name__)
|
room_members_bp = Blueprint('room_members', __name__, url_prefix='/api/rooms')
|
||||||
|
|
||||||
|
@room_members_bp.context_processor
|
||||||
|
def inject_unread_notifications():
|
||||||
|
if current_user.is_authenticated:
|
||||||
|
unread_count = get_unread_count(current_user.id)
|
||||||
|
return {'unread_notifications': unread_count}
|
||||||
|
return {'unread_notifications': 0}
|
||||||
|
|
||||||
@room_members_bp.route('/<int:room_id>/members', methods=['GET'])
|
@room_members_bp.route('/<int:room_id>/members', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
|
|||||||
@@ -1,16 +1,23 @@
|
|||||||
from flask import Blueprint, render_template, redirect, url_for, flash, request
|
from flask import Blueprint, render_template, redirect, url_for, flash, request, jsonify
|
||||||
from flask_login import login_required, current_user
|
from flask_login import login_required, current_user
|
||||||
from models import db, Room, User, RoomMemberPermission, RoomFile
|
from models import db, Room, User, RoomMemberPermission, RoomFile, Notif
|
||||||
from forms import RoomForm
|
from forms import RoomForm
|
||||||
from routes.room_files import user_has_permission
|
from routes.room_files import user_has_permission
|
||||||
from routes.auth import require_password_change
|
from routes.auth import require_password_change
|
||||||
from utils import log_event, create_notification
|
from utils import log_event, create_notification, get_unread_count
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
rooms_bp = Blueprint('rooms', __name__, url_prefix='/rooms')
|
rooms_bp = Blueprint('rooms', __name__, url_prefix='/rooms')
|
||||||
|
|
||||||
|
@rooms_bp.context_processor
|
||||||
|
def inject_unread_notifications():
|
||||||
|
if current_user.is_authenticated:
|
||||||
|
unread_count = get_unread_count(current_user.id)
|
||||||
|
return {'unread_notifications': unread_count}
|
||||||
|
return {'unread_notifications': 0}
|
||||||
|
|
||||||
@rooms_bp.route('/')
|
@rooms_bp.route('/')
|
||||||
@login_required
|
@login_required
|
||||||
@require_password_change
|
@require_password_change
|
||||||
|
|||||||
@@ -1,11 +1,19 @@
|
|||||||
from flask import Blueprint, jsonify, request, abort
|
from flask import Blueprint, jsonify, request, abort, render_template, redirect, url_for, flash
|
||||||
from flask_login import login_required, current_user
|
from flask_login import login_required, current_user
|
||||||
from models import db, Room, RoomFile, TrashedFile, UserStarredFile
|
from models import db, Room, RoomFile, TrashedFile, UserStarredFile, Notif
|
||||||
from utils import user_has_permission, clean_path, log_event
|
from routes.auth import require_password_change
|
||||||
|
from utils import user_has_permission, clean_path, log_event, create_notification, get_unread_count
|
||||||
import os
|
import os
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
trash_bp = Blueprint('trash', __name__)
|
trash_bp = Blueprint('trash', __name__, url_prefix='/trash')
|
||||||
|
|
||||||
|
@trash_bp.context_processor
|
||||||
|
def inject_unread_notifications():
|
||||||
|
if current_user.is_authenticated:
|
||||||
|
unread_count = get_unread_count(current_user.id)
|
||||||
|
return {'unread_notifications': unread_count}
|
||||||
|
return {'unread_notifications': 0}
|
||||||
|
|
||||||
@trash_bp.route('/<int:room_id>/trash', methods=['GET'])
|
@trash_bp.route('/<int:room_id>/trash', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
// Initialize tooltips
|
||||||
|
const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
|
||||||
|
tooltipTriggerList.map(function (tooltipTriggerEl) {
|
||||||
|
return new bootstrap.Tooltip(tooltipTriggerEl);
|
||||||
|
});
|
||||||
|
|
||||||
// Initialize variables
|
// Initialize variables
|
||||||
let currentPage = 1;
|
let currentPage = 1;
|
||||||
let totalPages = parseInt(document.getElementById('totalPages').textContent) || 1;
|
let totalPages = parseInt(document.getElementById('totalPages').textContent) || 1;
|
||||||
@@ -62,6 +68,12 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
updateNotificationsTable(data.notifications);
|
updateNotificationsTable(data.notifications);
|
||||||
updatePagination(data.total_pages, data.current_page);
|
updatePagination(data.total_pages, data.current_page);
|
||||||
|
|
||||||
|
// Reinitialize tooltips after updating the table
|
||||||
|
const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
|
||||||
|
tooltipTriggerList.map(function (tooltipTriggerEl) {
|
||||||
|
return new bootstrap.Tooltip(tooltipTriggerEl);
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching notifications:', error);
|
console.error('Error fetching notifications:', error);
|
||||||
notifsTableBody.innerHTML = '<tr><td colspan="6" class="text-center">Error loading notifications</td></tr>';
|
notifsTableBody.innerHTML = '<tr><td colspan="6" class="text-center">Error loading notifications</td></tr>';
|
||||||
@@ -104,6 +116,11 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Function to update notification counter
|
||||||
|
function updateNotificationCounter() {
|
||||||
|
counter.textContent = document.querySelector('.nav-link[href*="notifications"] .badge');
|
||||||
|
}
|
||||||
|
|
||||||
// Function to mark notification as read
|
// Function to mark notification as read
|
||||||
async function markAsRead(notifId) {
|
async function markAsRead(notifId) {
|
||||||
try {
|
try {
|
||||||
@@ -138,6 +155,8 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Update the notification counter
|
||||||
|
updateNotificationCounter();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error marking notification as read:', error);
|
console.error('Error marking notification as read:', error);
|
||||||
@@ -165,6 +184,10 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
// Remove the notification row from the table
|
// Remove the notification row from the table
|
||||||
const notifRow = document.querySelector(`tr[data-notif-id="${notifId}"]`);
|
const notifRow = document.querySelector(`tr[data-notif-id="${notifId}"]`);
|
||||||
if (notifRow) {
|
if (notifRow) {
|
||||||
|
// Only update counter if the notification was unread
|
||||||
|
if (notifRow.classList.contains('table-warning')) {
|
||||||
|
updateNotificationCounter();
|
||||||
|
}
|
||||||
notifRow.remove();
|
notifRow.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -206,6 +229,11 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// Remove the notification counter
|
||||||
|
const counter = document.querySelector('.nav-link[href*="notifications"] .badge');
|
||||||
|
if (counter) {
|
||||||
|
counter.remove();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error marking all notifications as read:', error);
|
console.error('Error marking all notifications as read:', error);
|
||||||
@@ -260,28 +288,30 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add event listeners for filters with debounce
|
// Initialize event listeners
|
||||||
let filterTimeout;
|
attachEventListeners();
|
||||||
function debouncedFetch() {
|
|
||||||
clearTimeout(filterTimeout);
|
// Add event listeners for filters
|
||||||
filterTimeout = setTimeout(() => {
|
notifTypeFilter.addEventListener('change', () => {
|
||||||
currentPage = 1; // Reset to first page when filters change
|
currentPage = 1;
|
||||||
fetchNotifications();
|
fetchNotifications();
|
||||||
}, 300);
|
updateURL();
|
||||||
}
|
});
|
||||||
|
|
||||||
notifTypeFilter.addEventListener('change', debouncedFetch);
|
dateRangeFilter.addEventListener('change', () => {
|
||||||
dateRangeFilter.addEventListener('change', debouncedFetch);
|
currentPage = 1;
|
||||||
|
fetchNotifications();
|
||||||
|
updateURL();
|
||||||
|
});
|
||||||
|
|
||||||
// Add event listener for clear filters
|
|
||||||
clearFiltersBtn.addEventListener('click', () => {
|
clearFiltersBtn.addEventListener('click', () => {
|
||||||
notifTypeFilter.value = '';
|
notifTypeFilter.value = '';
|
||||||
dateRangeFilter.value = '7d';
|
dateRangeFilter.value = '7d';
|
||||||
currentPage = 1;
|
currentPage = 1;
|
||||||
fetchNotifications();
|
fetchNotifications();
|
||||||
|
updateURL();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add event listener for mark all as read
|
|
||||||
markAllReadBtn.addEventListener('click', markAllAsRead);
|
markAllReadBtn.addEventListener('click', markAllAsRead);
|
||||||
|
|
||||||
// Add event listeners for pagination
|
// Add event listeners for pagination
|
||||||
@@ -289,6 +319,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
if (currentPage > 1) {
|
if (currentPage > 1) {
|
||||||
currentPage--;
|
currentPage--;
|
||||||
fetchNotifications();
|
fetchNotifications();
|
||||||
|
updateURL();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -296,20 +327,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
if (currentPage < totalPages) {
|
if (currentPage < totalPages) {
|
||||||
currentPage++;
|
currentPage++;
|
||||||
fetchNotifications();
|
fetchNotifications();
|
||||||
|
updateURL();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Initialize filters from URL parameters
|
|
||||||
const params = new URLSearchParams(window.location.search);
|
|
||||||
notifTypeFilter.value = params.get('notif_type') || '';
|
|
||||||
dateRangeFilter.value = params.get('date_range') || '7d';
|
|
||||||
currentPage = parseInt(params.get('page')) || 1;
|
|
||||||
|
|
||||||
// Initial fetch if filters are set
|
|
||||||
if (notifTypeFilter.value || dateRangeFilter.value !== '7d') {
|
|
||||||
fetchNotifications();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attach initial event listeners
|
|
||||||
attachEventListeners();
|
|
||||||
});
|
});
|
||||||
@@ -32,8 +32,13 @@
|
|||||||
</a>
|
</a>
|
||||||
<div class="d-flex align-items-center">
|
<div class="d-flex align-items-center">
|
||||||
<div class="d-none d-lg-flex align-items-center me-3">
|
<div class="d-none d-lg-flex align-items-center me-3">
|
||||||
<a class="nav-link text-white" href="{{ url_for('main.notifications') }}">
|
<a class="nav-link text-white position-relative" href="{{ url_for('main.notifications') }}">
|
||||||
<i class="fas fa-bell text-xl" style="width: 2rem; height: 2rem; display: flex; align-items: center; justify-content: center;"></i>
|
<i class="fas fa-bell text-xl" style="width: 2rem; height: 2rem; display: flex; align-items: center; justify-content: center;"></i>
|
||||||
|
{% if unread_notifications > 0 %}
|
||||||
|
<span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger" style="font-size: 0.6rem;">
|
||||||
|
{{ unread_notifications }}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="dropdown">
|
<div class="dropdown">
|
||||||
|
|||||||
@@ -50,7 +50,6 @@
|
|||||||
<th>Timestamp</th>
|
<th>Timestamp</th>
|
||||||
<th>Type</th>
|
<th>Type</th>
|
||||||
<th>From</th>
|
<th>From</th>
|
||||||
<th>Details</th>
|
|
||||||
<th>Status</th>
|
<th>Status</th>
|
||||||
<th>Actions</th>
|
<th>Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -84,14 +83,6 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td>{{ notif.sender.username + ' ' + notif.sender.last_name if notif.sender else 'System' }}</td>
|
<td>{{ notif.sender.username + ' ' + notif.sender.last_name if notif.sender else 'System' }}</td>
|
||||||
<td>
|
|
||||||
<button class="btn btn-sm btn-secondary"
|
|
||||||
data-bs-toggle="modal"
|
|
||||||
data-bs-target="#notifDetailsModal"
|
|
||||||
data-notif-id="{{ notif.id }}">
|
|
||||||
<i class="fas fa-info-circle"></i> View Details
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
<td>
|
<td>
|
||||||
{% if notif.read %}
|
{% if notif.read %}
|
||||||
<span class="badge bg-success">Read</span>
|
<span class="badge bg-success">Read</span>
|
||||||
@@ -103,21 +94,39 @@
|
|||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
{% if notif.notif_type in ['room_invite', 'room_invite_removed'] and notif.details and notif.details.room_id %}
|
{% if notif.notif_type in ['room_invite', 'room_invite_removed'] and notif.details and notif.details.room_id %}
|
||||||
<a href="{{ url_for('rooms.room', room_id=notif.details.room_id) }}"
|
<a href="{{ url_for('rooms.room', room_id=notif.details.room_id) }}"
|
||||||
class="btn btn-sm btn-primary">
|
class="btn btn-sm btn-primary"
|
||||||
<i class="fas fa-door-open"></i> View Room
|
data-bs-toggle="tooltip"
|
||||||
|
title="View Room">
|
||||||
|
<i class="fas fa-door-open"></i>
|
||||||
</a>
|
</a>
|
||||||
{% elif notif.notif_type in ['conversation_invite', 'conversation_invite_removed', 'conversation_message'] and notif.details and notif.details.conversation_id %}
|
{% elif notif.notif_type in ['conversation_invite', 'conversation_invite_removed', 'conversation_message'] and notif.details and notif.details.conversation_id %}
|
||||||
<a href="{{ url_for('conversations.conversation', conversation_id=notif.details.conversation_id) }}"
|
<a href="{{ url_for('conversations.conversation', conversation_id=notif.details.conversation_id) }}"
|
||||||
class="btn btn-sm btn-primary">
|
class="btn btn-sm btn-primary"
|
||||||
<i class="fas fa-comments"></i> View Conversation
|
data-bs-toggle="tooltip"
|
||||||
|
title="View Conversation">
|
||||||
|
<i class="fas fa-comments"></i>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<button class="btn btn-sm btn-secondary"
|
||||||
|
data-bs-toggle="modal"
|
||||||
|
data-bs-target="#notifDetailsModal"
|
||||||
|
data-notif-id="{{ notif.id }}"
|
||||||
|
data-bs-toggle="tooltip"
|
||||||
|
title="View Details">
|
||||||
|
<i class="fas fa-info-circle"></i>
|
||||||
|
</button>
|
||||||
{% if not notif.read %}
|
{% if not notif.read %}
|
||||||
<button class="btn btn-sm btn-success mark-read" data-notif-id="{{ notif.id }}">
|
<button class="btn btn-sm btn-success mark-read"
|
||||||
<i class="fas fa-check"></i> Mark as Read
|
data-notif-id="{{ notif.id }}"
|
||||||
|
data-bs-toggle="tooltip"
|
||||||
|
title="Mark as Read">
|
||||||
|
<i class="fas fa-check"></i>
|
||||||
</button>
|
</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<button class="btn btn-sm btn-danger delete-notif" data-notif-id="{{ notif.id }}">
|
<button class="btn btn-sm btn-danger delete-notif"
|
||||||
|
data-notif-id="{{ notif.id }}"
|
||||||
|
data-bs-toggle="tooltip"
|
||||||
|
title="Delete">
|
||||||
<i class="fas fa-trash"></i>
|
<i class="fas fa-trash"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -126,7 +135,7 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="6" class="text-center">No notifications found</td>
|
<td colspan="5" class="text-center">No notifications found</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
Reference in New Issue
Block a user