290 lines
19 KiB
HTML
290 lines
19 KiB
HTML
{% extends "portal_base.html" %}
|
|
{% load static i18n %}
|
|
|
|
{% block title %}{% trans "Messages" %}{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="max-w-7xl mx-auto py-6 px-4 space-y-6">
|
|
|
|
<!-- Page Header -->
|
|
<div class="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4">
|
|
<div>
|
|
<h1 class="text-2xl sm:text-3xl font-bold flex items-center gap-3">
|
|
<div class="w-12 h-12 rounded-xl flex items-center justify-center" style="background-color: rgba(157, 34, 53, 0.1);">
|
|
<i data-lucide="message-square" class="w-6 h-6" style="color: #9d2235;"></i>
|
|
</div>
|
|
{% trans "Messages" %}
|
|
</h1>
|
|
</div>
|
|
<a href="{% url 'message_create' %}"
|
|
class="inline-flex items-center gap-2 px-6 py-3 rounded-xl font-semibold text-white transition-all duration-200"
|
|
style="background-color: #9d2235;"
|
|
onmouseover="this.style.backgroundColor='#7a1a29'"
|
|
onmouseout="this.style.backgroundColor='#9d2235'">
|
|
<i data-lucide="plus" class="w-4 h-4"></i>
|
|
{% trans "Compose Message" %}
|
|
</a>
|
|
</div>
|
|
|
|
<!-- Filters Card -->
|
|
<div class="bg-white rounded-xl shadow-sm border border-gray-200">
|
|
<div class="px-6 py-4 border-b border-gray-100" style="background-color: #f8f9fa;">
|
|
<h2 class="text-lg font-bold flex items-center gap-2">
|
|
<i data-lucide="filter" class="w-5 h-5" style="color: #9d2235;"></i>
|
|
{% trans "Filter Messages" %}
|
|
</h2>
|
|
</div>
|
|
<div class="p-6">
|
|
<form method="get" class="grid grid-cols-1 md:grid-cols-4 gap-4">
|
|
<div>
|
|
<label for="status" class="block text-sm font-semibold text-gray-700 mb-2">{% trans "Status" %}</label>
|
|
<select name="status" id="status" class="w-full px-4 py-3 border border-gray-200 rounded-xl text-sm focus:ring-2 focus:ring-temple-red/20 focus:border-temple-red outline-none transition">
|
|
<option value="">{% trans "All Status" %}</option>
|
|
<option value="read" {% if status_filter == 'read' %}selected{% endif %}>{% trans "Read" %}</option>
|
|
<option value="unread" {% if status_filter == 'unread' %}selected{% endif %}>{% trans "Unread" %}</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label for="type" class="block text-sm font-semibold text-gray-700 mb-2">{% trans "Type" %}</label>
|
|
<select name="type" id="type" class="w-full px-4 py-3 border border-gray-200 rounded-xl text-sm focus:ring-2 focus:ring-temple-red/20 focus:border-temple-red outline-none transition">
|
|
<option value="">{% trans "All Types" %}</option>
|
|
<option value="GENERAL" {% if type_filter == 'GENERAL' %}selected{% endif %}>{% trans "General" %}</option>
|
|
<option value="JOB_RELATED" {% if type_filter == 'JOB_RELATED' %}selected{% endif %}>{% trans "Job Related" %}</option>
|
|
<option value="INTERVIEW" {% if type_filter == 'INTERVIEW' %}selected{% endif %}>{% trans "Interview" %}</option>
|
|
<option value="OFFER" {% if type_filter == 'OFFER' %}selected{% endif %}>{% trans "Offer" %}</option>
|
|
</select>
|
|
</div>
|
|
<div class="md:col-span-2">
|
|
<label for="q" class="block text-sm font-semibold text-gray-700 mb-2">{% trans "Search" %}</label>
|
|
<div class="relative">
|
|
<i data-lucide="search" class="absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400"></i>
|
|
<input type="text" name="q" id="q" class="w-full pl-10 pr-4 py-3 border border-gray-200 rounded-xl text-sm focus:ring-2 focus:ring-temple-red/20 focus:border-temple-red outline-none transition"
|
|
value="{{ search_query }}" placeholder="{% trans 'Search messages...' %}">
|
|
</div>
|
|
</div>
|
|
<div class="md:col-span-4 flex gap-3">
|
|
<button type="submit"
|
|
class="inline-flex items-center gap-2 px-6 py-3 rounded-xl font-medium text-white transition-all duration-200"
|
|
style="background-color: #9d2235;"
|
|
onmouseover="this.style.backgroundColor='#7a1a29'"
|
|
onmouseout="this.style.backgroundColor='#9d2235'">
|
|
<i data-lucide="filter" class="w-4 h-4"></i>
|
|
{% trans "Filter" %}
|
|
</button>
|
|
{% if search_query or status_filter or type_filter %}
|
|
<a href="{% url 'message_list' %}"
|
|
class="inline-flex items-center gap-2 px-6 py-3 rounded-xl font-medium border-2 border-gray-200 text-gray-700 hover:bg-gray-50 transition-all duration-200">
|
|
<i data-lucide="x" class="w-4 h-4"></i>
|
|
{% trans "Clear" %}
|
|
</a>
|
|
{% endif %}
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Stats Cards -->
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-6">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<p class="text-sm text-gray-500 font-semibold">{% trans "Total Messages" %}</p>
|
|
<p class="text-3xl font-bold mt-1" style="color: #9d2235;">{{ total_messages }}</p>
|
|
</div>
|
|
<div class="w-14 h-14 rounded-xl flex items-center justify-center" style="background-color: rgba(157, 34, 53, 0.1);">
|
|
<i data-lucide="message-square" class="w-7 h-7" style="color: #9d2235;"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-6">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<p class="text-sm text-gray-500 font-semibold">{% trans "Unread Messages" %}</p>
|
|
<p class="text-3xl font-bold mt-1" style="color: #9d2235;">{{ unread_messages }}</p>
|
|
</div>
|
|
<div class="w-14 h-14 rounded-xl flex items-center justify-center" style="background-color: rgba(157, 34, 53, 0.1);">
|
|
<i data-lucide="bell" class="w-7 h-7" style="color: #9d2235;"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Messages Table -->
|
|
<div class="bg-white rounded-xl shadow-sm border border-gray-200">
|
|
<div class="px-6 py-4 border-b border-gray-100" style="background-color: #f8f9fa;">
|
|
<h2 class="text-lg font-bold flex items-center gap-2">
|
|
<i data-lucide="list" class="w-5 h-5" style="color: #9d2235;"></i>
|
|
{% trans "Message Listings" %}
|
|
</h2>
|
|
</div>
|
|
<div class="overflow-x-auto">
|
|
{% if page_obj %}
|
|
<table class="min-w-full divide-y divide-gray-200">
|
|
<thead class="bg-gray-50">
|
|
<tr>
|
|
<th scope="col" class="px-6 py-3 text-left text-xs font-bold text-gray-700 tracking-wider whitespace-nowrap">{% trans "Subject" %}</th>
|
|
<th scope="col" class="px-6 py-3 text-left text-xs font-bold text-gray-700 tracking-wider whitespace-nowrap">{% trans "Sender" %}</th>
|
|
<th scope="col" class="px-6 py-3 text-left text-xs font-bold text-gray-700 tracking-wider whitespace-nowrap">{% trans "Recipient" %}</th>
|
|
<th scope="col" class="px-6 py-3 text-left text-xs font-bold text-gray-700 tracking-wider whitespace-nowrap">{% trans "Type" %}</th>
|
|
<th scope="col" class="px-6 py-3 text-left text-xs font-bold text-gray-700 tracking-wider whitespace-nowrap">{% trans "Status" %}</th>
|
|
<th scope="col" class="px-6 py-3 text-left text-xs font-bold text-gray-700 tracking-wider whitespace-nowrap">{% trans "Created" %}</th>
|
|
<th scope="col" class="px-6 py-3 text-center text-xs font-bold text-gray-700 tracking-wider whitespace-nowrap">{% trans "Actions" %}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="bg-white divide-y divide-gray-100">
|
|
{% for message in page_obj %}
|
|
<tr class="hover:bg-gray-50 transition-colors {% if not message.is_read %}" style="background-color: #f8f7f2;"{% endif %}>
|
|
<td class="px-6 py-4">
|
|
<a href="{% url 'message_detail' message.id %}"
|
|
class="font-semibold hover:underline transition-colors"
|
|
style="color: #9d2235;">
|
|
{{ message.subject|truncatechars:50 }}
|
|
</a>
|
|
{% if message.parent_message %}
|
|
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-[10px] font-bold uppercase bg-gray-200 text-gray-600 ml-2">
|
|
{% trans "Reply" %}
|
|
</span>
|
|
{% endif %}
|
|
</td>
|
|
<td class="px-6 py-4">
|
|
{% if message.sender == request.user %}
|
|
<span class="text-gray-700">{% trans "Me" %}</span>
|
|
{% else %}
|
|
<div class="text-gray-900 font-medium">{{ message.sender.get_full_name|default:message.sender.username }}</div>
|
|
{% endif %}
|
|
</td>
|
|
<td class="px-6 py-4">
|
|
{% if message.recipient == request.user %}
|
|
<span class="text-gray-700">{% trans "Me" %}</span>
|
|
{% else %}
|
|
<div class="text-gray-900 font-medium">{{ message.recipient.get_full_name|default:message.recipient.username }}</div>
|
|
{% endif %}
|
|
</td>
|
|
<td class="px-6 py-4">
|
|
<span class="inline-flex items-center px-2.5 py-1 rounded-full text-[10px] font-bold uppercase"
|
|
style="background-color: rgba(157, 34, 53, 0.1); color: #9d2235;">
|
|
{{ message.get_message_type_display }}
|
|
</span>
|
|
</td>
|
|
<td class="px-6 py-4">
|
|
{% if message.is_read %}
|
|
<span class="inline-flex items-center px-2.5 py-1 rounded-full text-[10px] font-bold uppercase text-white"
|
|
style="background-color: #9d2235;">
|
|
{% trans "Read" %}
|
|
</span>
|
|
{% else %}
|
|
<span class="inline-flex items-center px-2.5 py-1 rounded-full text-[10px] font-bold uppercase bg-yellow-500 text-white">
|
|
{% trans "Unread" %}
|
|
</span>
|
|
{% endif %}
|
|
</td>
|
|
<td class="px-6 py-4 text-sm text-gray-700">{{ message.created_at|date:"M d, Y H:i" }}</td>
|
|
<td class="px-6 py-4 text-center">
|
|
<div class="flex items-center justify-center gap-2">
|
|
<a href="{% url 'message_detail' message.id %}"
|
|
class="inline-flex items-center justify-center w-9 h-9 rounded-lg hover:bg-gray-100 transition"
|
|
style="border: 2px solid #9d2235; color: #9d2235;"
|
|
onmouseover="this.style.backgroundColor='rgba(157, 34, 53, 0.1)'"
|
|
onmouseout="this.style.backgroundColor='white'"
|
|
title="{% trans 'View' %}">
|
|
<i data-lucide="eye" class="w-4 h-4"></i>
|
|
</a>
|
|
{% if not message.is_read and message.recipient == request.user %}
|
|
<a href="{% url 'message_mark_read' message.id %}"
|
|
class="inline-flex items-center justify-center w-9 h-9 rounded-lg border-2 border-green-500 text-green-500 hover:bg-green-50 transition"
|
|
title="{% trans 'Mark as Read' %}">
|
|
<i data-lucide="check" class="w-4 h-4"></i>
|
|
</a>
|
|
{% endif %}
|
|
<a href="{% url 'message_reply' message.id %}"
|
|
class="inline-flex items-center justify-center w-9 h-9 rounded-lg border-2 border-gray-300 text-gray-600 hover:bg-gray-100 transition"
|
|
title="{% trans 'Reply' %}">
|
|
<i data-lucide="reply" class="w-4 h-4"></i>
|
|
</a>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{% empty %}
|
|
<tr>
|
|
<td colspan="7" class="px-6 py-12 text-center">
|
|
<div class="max-w-md mx-auto">
|
|
<i data-lucide="inbox" class="w-16 h-16 mx-auto mb-4" style="color: #9d2235;"></i>
|
|
<p class="text-xl font-semibold text-gray-900 mb-2">{% trans "No messages found." %}</p>
|
|
<p class="text-gray-500 mb-4">{% trans "Try adjusting your filters or compose a new message." %}</p>
|
|
<a href="{% url 'message_create' %}"
|
|
class="inline-flex items-center gap-2 px-6 py-3 rounded-xl font-semibold text-white transition-all duration-200"
|
|
style="background-color: #9d2235;"
|
|
onmouseover="this.style.backgroundColor='#7a1a29'"
|
|
onmouseout="this.style.backgroundColor='#9d2235'">
|
|
<i data-lucide="plus" class="w-4 h-4"></i>
|
|
{% trans "Compose Message" %}
|
|
</a>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
|
|
{% if page_obj.has_other_pages %}
|
|
<div class="px-6 py-4 border-t border-gray-200 flex justify-center items-center gap-2">
|
|
{% if page_obj.has_previous %}
|
|
<a href="?page={{ page_obj.previous_page_number }}&status={{ status_filter }}&type={{ type_filter }}&q={{ search_query }}"
|
|
class="inline-flex items-center gap-2 px-4 py-2 rounded-lg border-2 border-gray-200 text-gray-700 hover:bg-gray-50 transition-all duration-200">
|
|
<i data-lucide="chevron-left" class="w-4 h-4"></i>
|
|
</a>
|
|
{% endif %}
|
|
|
|
{% for num in page_obj.paginator.page_range %}
|
|
{% if page_obj.number == num %}
|
|
<span class="inline-flex items-center justify-center w-10 h-10 rounded-lg text-white font-semibold"
|
|
style="background-color: #9d2235;">
|
|
{{ num }}
|
|
</span>
|
|
{% else %}
|
|
<a href="?page={{ num }}&status={{ status_filter }}&type={{ type_filter }}&q={{ search_query }}"
|
|
class="inline-flex items-center justify-center w-10 h-10 rounded-lg border-2 border-gray-200 text-gray-700 hover:bg-gray-50 transition-all duration-200">
|
|
{{ num }}
|
|
</a>
|
|
{% endif %}
|
|
{% endfor %}
|
|
|
|
{% if page_obj.has_next %}
|
|
<a href="?page={{ page_obj.next_page_number }}&status={{ status_filter }}&type={{ type_filter }}&q={{ search_query }}"
|
|
class="inline-flex items-center gap-2 px-4 py-2 rounded-lg border-2 border-gray-200 text-gray-700 hover:bg-gray-50 transition-all duration-200">
|
|
<i data-lucide="chevron-right" class="w-4 h-4"></i>
|
|
</a>
|
|
{% endif %}
|
|
</div>
|
|
{% endif %}
|
|
{% else %}
|
|
<div class="px-6 py-12 text-center">
|
|
<div class="max-w-md mx-auto">
|
|
<i data-lucide="inbox" class="w-16 h-16 mx-auto mb-4" style="color: #9d2235;"></i>
|
|
<p class="text-xl font-semibold text-gray-900 mb-2">{% trans "No messages found." %}</p>
|
|
<p class="text-gray-500 mb-4">{% trans "Try adjusting your filters or compose a new message." %}</p>
|
|
<a href="{% url 'message_create' %}"
|
|
class="inline-flex items-center gap-2 px-6 py-3 rounded-xl font-semibold text-white transition-all duration-200"
|
|
style="background-color: #9d2235;"
|
|
onmouseover="this.style.backgroundColor='#7a1a29'"
|
|
onmouseout="this.style.backgroundColor='#9d2235'">
|
|
<i data-lucide="plus" class="w-4 h-4"></i>
|
|
{% trans "Compose Message" %}
|
|
</a>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<script>
|
|
// Initialize Lucide icons
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
if (typeof lucide !== 'undefined') {
|
|
lucide.createIcons();
|
|
}
|
|
});
|
|
</script>
|
|
{% endblock %} |