base setup
This commit is contained in:
25
at_django_boilerplate/backend_admin/templates/admin_dashboard.html
Executable file
25
at_django_boilerplate/backend_admin/templates/admin_dashboard.html
Executable file
@@ -0,0 +1,25 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block content %}
|
||||
{% load crispy_forms_tags %}
|
||||
|
||||
<h2 class="text-2xl font-bold mb-6 text-gray-800">Admin Dashboard</h2>
|
||||
|
||||
<div class="flex gap-5">
|
||||
|
||||
<a href="{% url 'contact_list' %}"
|
||||
class="px-6 py-3 border-2 border-blue-600 rounded-xl font-semibold text-blue-600 hover:text-blue-800 transition-colors">
|
||||
View Contacts
|
||||
</a>
|
||||
|
||||
<a href="{% url 'subscriber_list' %}"
|
||||
class="px-6 py-3 border-2 border-green-600 rounded-xl font-semibold text-green-600 hover:text-green-800 transition-colors">
|
||||
View Subscribers
|
||||
</a>
|
||||
<a href="{% url 'user_activity' %}"
|
||||
class="px-6 py-3 border-2 border-green-600 rounded-xl font-semibold text-green-600 hover:text-green-800 transition-colors">
|
||||
View Activiy
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
188
at_django_boilerplate/backend_admin/templates/appointment_list.html
Executable file
188
at_django_boilerplate/backend_admin/templates/appointment_list.html
Executable file
@@ -0,0 +1,188 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
{% block title %}Appointment Leads - Admin{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container mx-auto mt-10 px-4 max-w-7xl">
|
||||
<div class="bg-white shadow-lg rounded-2xl overflow-hidden">
|
||||
|
||||
<!-- Header -->
|
||||
<div class="px-8 py-6 border-b border-gray-200 bg-gradient-to-r from-indigo-50 to-purple-50">
|
||||
<h2 class="text-3xl font-bold text-gray-800">Appointment Requests</h2>
|
||||
<p class="text-gray-600 mt-2">Manage appointments: update status, reschedule, and track progress</p>
|
||||
</div>
|
||||
|
||||
{% if appointments %}
|
||||
<div class="overflow-x-auto">
|
||||
<table class="min-w-full divide-y divide-gray-200">
|
||||
|
||||
<!-- Table Head -->
|
||||
<thead class="bg-gray-100">
|
||||
<tr>
|
||||
<th class="px-6 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">#</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Ticket ID</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Name</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Contact</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Expert</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Scheduled For</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody class="bg-white divide-y divide-gray-200">
|
||||
{% for apt in appointments %}
|
||||
<tr class="hover:bg-gray-50 transition">
|
||||
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-600">{{ forloop.counter }}</td>
|
||||
|
||||
<td class="px-6 py-4 whitespace-nowrap font-medium text-indigo-600">
|
||||
APP-{{ apt.pk|stringformat:"06d" }}
|
||||
</td>
|
||||
|
||||
<td class="px-6 py-4 whitespace-nowrap font-medium text-gray-900">
|
||||
{{ apt.full_name }}
|
||||
</td>
|
||||
|
||||
<td class="px-6 py-4 text-sm text-gray-600">
|
||||
{{ apt.email }}<br>
|
||||
<small class="text-gray-500">{{ apt.phone }}</small>
|
||||
</td>
|
||||
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm">
|
||||
{{ apt.get_meeting_with_display }}
|
||||
</td>
|
||||
|
||||
<td class="px-6 py-4 text-sm">
|
||||
{{ apt.appointment_datetime|date:"d M Y" }} at {{ apt.appointment_datetime|time:"h:i A" }}
|
||||
</td>
|
||||
|
||||
<!-- Status Badge -->
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
<span class="px-3 py-1 inline-flex text-xs font-semibold rounded-full
|
||||
{% if apt.status == 'pending' %}bg-yellow-100 text-yellow-800
|
||||
{% elif apt.status == 'contacted' %}bg-blue-100 text-blue-800
|
||||
{% elif apt.status == 'in_process' %}bg-purple-100 text-purple-800
|
||||
{% elif apt.status == 'rescheduled' %}bg-indigo-100 text-indigo-800
|
||||
{% elif apt.status == 'completed' %}bg-green-100 text-green-800
|
||||
{% elif apt.status == 'cancelled' %}bg-red-100 text-red-800
|
||||
{% else %}bg-gray-100 text-gray-800{% endif %}">
|
||||
{{ apt.get_status_display }}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<!-- Actions -->
|
||||
<td class="px-6 py-4 text-sm">
|
||||
<button onclick="openModal('modal-{{ apt.id }}')"
|
||||
class="bg-gradient-to-r from-indigo-600 to-purple-600 text-white px-4 py-2 rounded-lg text-xs font-medium hover:shadow-lg transition">
|
||||
Manage
|
||||
</button>
|
||||
|
||||
<!-- MODAL -->
|
||||
<div id="modal-{{ apt.id }}" class="fixed inset-0 bg-black bg-opacity-60 hidden flex items-center justify-center z-50">
|
||||
<div class="bg-white w-full max-w-lg rounded-2xl shadow-2xl p-8 relative animate-fadeIn">
|
||||
|
||||
<button onclick="closeModal('modal-{{ apt.id }}')"
|
||||
class="absolute top-4 right-6 text-gray-400 hover:text-gray-600 text-3xl">×</button>
|
||||
|
||||
<h3 class="text-2xl font-bold mb-6 text-gray-800">
|
||||
Manage Appointment – {{ apt.full_name }}
|
||||
</h3>
|
||||
<p class="text-sm text-gray-500 mb-6">Ticket: APP-{{ apt.pk|stringformat:"06d" }}</p>
|
||||
|
||||
<!-- Update Status -->
|
||||
<form method="post" class="mb-8">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="appointment_id" value="{{ apt.id }}">
|
||||
<input type="hidden" name="action" value="update_status">
|
||||
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Update Status</label>
|
||||
<select name="status" class="w-full border border-gray-300 rounded-lg px-4 py-3 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500">
|
||||
{% for value, label in status_choices %}
|
||||
<option value="{{ value }}" {% if apt.status == value %}selected{% endif %}>
|
||||
{{ label }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
|
||||
<button type="submit" class="mt-4 w-full bg-indigo-600 text-white py-3 rounded-lg font-medium hover:bg-indigo-700 transition">
|
||||
Update Status
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<!-- Reschedule -->
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="appointment_id" value="{{ apt.id }}">
|
||||
<input type="hidden" name="action" value="reschedule">
|
||||
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Reschedule Appointment</label>
|
||||
<div class="grid grid-cols-2 gap-4 mb-4">
|
||||
<input type="date" name="new_date"
|
||||
value="{{ apt.appointment_datetime|date:'Y-m-d' }}"
|
||||
class="border border-gray-300 rounded-lg px-4 py-3" required>
|
||||
<input type="time" name="new_time"
|
||||
value="{{ apt.appointment_datetime|time:'H:i' }}"
|
||||
class="border border-gray-300 rounded-lg px-4 py-3" required>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="w-full bg-green-600 text-white py-3 rounded-lg font-medium hover:bg-green-700 transition">
|
||||
Reschedule Appointment
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<!-- Notes (Read-only) -->
|
||||
{% if apt.notes %}
|
||||
<div class="mt-8 p-4 bg-gray-50 rounded-lg">
|
||||
<p class="text-sm font-medium text-gray-700">User Notes:</p>
|
||||
<p class="text-sm text-gray-600 mt-1">{{ apt.notes }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{% else %}
|
||||
<div class="p-16 text-center">
|
||||
<p class="text-xl text-gray-500">No appointment requests yet.</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Scripts -->
|
||||
<script>
|
||||
function openModal(id) {
|
||||
document.getElementById(id).classList.remove('hidden');
|
||||
document.getElementById(id).classList.add('flex');
|
||||
}
|
||||
function closeModal(id) {
|
||||
document.getElementById(id).classList.add('hidden');
|
||||
document.getElementById(id).classList.remove('flex');
|
||||
}
|
||||
|
||||
// Close modal when clicking outside
|
||||
window.addEventListener('click', function(e) {
|
||||
document.querySelectorAll('[id^="modal-"]').forEach(modal => {
|
||||
if (e.target === modal) {
|
||||
modal.classList.add('hidden');
|
||||
modal.classList.remove('flex');
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; transform: translateY(20px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
.animate-fadeIn { animation: fadeIn 0.3s ease-out; }
|
||||
</style>
|
||||
|
||||
{% endblock %}
|
||||
239
at_django_boilerplate/backend_admin/templates/contact_list.html
Executable file
239
at_django_boilerplate/backend_admin/templates/contact_list.html
Executable file
@@ -0,0 +1,239 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load crispy_forms_tags %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<!-- Back -->
|
||||
<div class="mb-6">
|
||||
<a href="{% url 'admin_dashboard' %}"
|
||||
class="inline-block px-4 py-2 border-2 border-gray-800 rounded-xl font-bold text-gray-800 hover:text-gray-900 hover:border-gray-900">
|
||||
← Admin Dashboard
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 mt-8">
|
||||
|
||||
<h1 class="text-3xl font-bold mb-6 text-gray-800 text-center">All Contacts</h1>
|
||||
|
||||
<!-- ================= FILTER ================= -->
|
||||
<!-- ================= FILTER ================= -->
|
||||
<form method="get" class="mb-6 flex flex-col sm:flex-row gap-3">
|
||||
|
||||
<!-- Search -->
|
||||
<input
|
||||
type="text"
|
||||
name="search"
|
||||
value="{{ request.GET.search }}"
|
||||
placeholder="Search by name, email, or message..."
|
||||
class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring"
|
||||
>
|
||||
|
||||
<!-- Junk Filter -->
|
||||
<select
|
||||
name="status"
|
||||
class="px-4 py-2 border rounded-lg focus:outline-none focus:ring">
|
||||
|
||||
<option value="">All Messages</option>
|
||||
<option value="inbox"
|
||||
{% if request.GET.status == "inbox" %}selected{% endif %}>
|
||||
Inbox
|
||||
</option>
|
||||
<option value="junk"
|
||||
{% if request.GET.status == "junk" %}selected{% endif %}>
|
||||
Junk
|
||||
</option>
|
||||
</select>
|
||||
|
||||
<button class="px-6 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700">
|
||||
Apply
|
||||
</button>
|
||||
|
||||
</form>
|
||||
|
||||
|
||||
<!-- ================= TABLE ================= -->
|
||||
<div class="overflow-x-auto shadow-lg rounded-lg">
|
||||
<table class="min-w-[700px] w-full table-auto bg-white divide-y divide-gray-200">
|
||||
|
||||
<thead class="bg-indigo-600">
|
||||
<tr>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-white uppercase">Name</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-white uppercase">Email</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-white uppercase">Message</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-white uppercase">Date</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-white uppercase">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody class="divide-y divide-gray-100">
|
||||
|
||||
{% for c in contacts %}
|
||||
<tr class="hover:bg-gray-50">
|
||||
|
||||
<td class="px-6 py-4 font-medium">
|
||||
{{ c.name }}
|
||||
</td>
|
||||
|
||||
<td class="px-6 py-4 text-gray-600">
|
||||
{{ c.email }}
|
||||
</td>
|
||||
|
||||
<td class="px-6 py-4 max-w-xs truncate text-gray-700">
|
||||
{{ c.message }}
|
||||
</td>
|
||||
|
||||
<td class="px-6 py-4 text-gray-500 whitespace-nowrap">
|
||||
{{ c.created_at|date:"M d, Y H:i" }}
|
||||
</td>
|
||||
|
||||
<!-- ================= ACTIONS ================= -->
|
||||
<td class="px-6 py-4 flex gap-3">
|
||||
|
||||
<!-- View -->
|
||||
<button
|
||||
onclick="openModal(
|
||||
'{{ c.name }}',
|
||||
'{{ c.email }}',
|
||||
'{{ c.message|escapejs }}',
|
||||
'{{ c.created_at|date:"M d, Y H:i" }}'
|
||||
)"
|
||||
class="text-indigo-600 hover:text-indigo-800"
|
||||
title="View">
|
||||
<i class="fas fa-eye"></i>
|
||||
</button>
|
||||
|
||||
<!-- Junk -->
|
||||
{% if not c.is_junk %}
|
||||
<form method="post"
|
||||
action="{% url 'set_message_to_junk' c.id %}"
|
||||
onsubmit="return confirmJunk('{{ c.email }}', '{{ c.phone|default:'' }}')">
|
||||
{% csrf_token %}
|
||||
<button
|
||||
type="submit"
|
||||
class="text-red-600 hover:text-red-800"
|
||||
title="Mark as junk">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<span class="text-xs text-gray-400">Junk</span>
|
||||
{% endif %}
|
||||
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td colspan="5" class="text-center py-10 text-gray-400">
|
||||
No contacts found.
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- ================= PAGINATION ================= -->
|
||||
{% if is_paginated %}
|
||||
<div class="mt-6 flex justify-center items-center gap-2">
|
||||
|
||||
{% if page_obj.has_previous %}
|
||||
<a href="?page={{ page_obj.previous_page_number }}&search={{ request.GET.search }}&status={{ request.GET.status }}"
|
||||
|
||||
class="px-3 py-1 border rounded hover:bg-gray-100">
|
||||
Prev
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
<span class="px-3 py-1 bg-indigo-600 text-white rounded">
|
||||
{{ page_obj.number }} / {{ page_obj.paginator.num_pages }}
|
||||
</span>
|
||||
|
||||
{% if page_obj.has_next %}
|
||||
<a href="?page={{ page_obj.next_page_number }}&search={{ request.GET.search }}&status={{ request.GET.status }}"
|
||||
|
||||
class="px-3 py-1 border rounded hover:bg-gray-100">
|
||||
Next
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ================= MODAL ================= -->
|
||||
|
||||
<div id="contactModal"
|
||||
class="fixed inset-0 bg-black bg-opacity-50 hidden flex items-center justify-center z-50">
|
||||
|
||||
<div class="bg-white rounded-xl shadow-2xl max-w-lg w-full p-6 relative">
|
||||
|
||||
<button onclick="closeModal()"
|
||||
class="absolute top-3 right-3 text-gray-400 hover:text-gray-700 text-2xl">
|
||||
×
|
||||
</button>
|
||||
|
||||
<h2 class="text-2xl font-bold mb-4 text-gray-800">Contact Details</h2>
|
||||
|
||||
<div class="space-y-4">
|
||||
|
||||
<p><strong>Name:</strong> <span id="modalName"></span></p>
|
||||
<p><strong>Email:</strong> <span id="modalEmail"></span></p>
|
||||
<p><strong>Date:</strong> <span id="modalDate"></span></p>
|
||||
|
||||
<div>
|
||||
<p class="font-semibold mb-1">Message</p>
|
||||
<div id="modalMessage"
|
||||
class="bg-gray-100 p-3 rounded-lg text-sm whitespace-pre-wrap">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="mt-6 text-right">
|
||||
<button onclick="closeModal()"
|
||||
class="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700">
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ================= JS ================= -->
|
||||
|
||||
<script>
|
||||
function confirmJunk(email, phone) {
|
||||
let message = "Set ALL messages";
|
||||
|
||||
if (email) {
|
||||
message += " from email: " + email;
|
||||
}
|
||||
|
||||
if (phone) {
|
||||
message += email ? " and phone: " + phone : " from phone: " + phone;
|
||||
}
|
||||
|
||||
message += " to junk?\n\nThis will also add the user to the spam list.";
|
||||
|
||||
return confirm(message);
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<script>
|
||||
function openModal(name, email, message, date) {
|
||||
document.getElementById("modalName").innerText = name;
|
||||
document.getElementById("modalEmail").innerText = email;
|
||||
document.getElementById("modalMessage").innerText = message;
|
||||
document.getElementById("modalDate").innerText = date;
|
||||
document.getElementById("contactModal").classList.remove("hidden");
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
document.getElementById("contactModal").classList.add("hidden");
|
||||
}
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
22
at_django_boilerplate/backend_admin/templates/seo_config.html
Executable file
22
at_django_boilerplate/backend_admin/templates/seo_config.html
Executable file
@@ -0,0 +1,22 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block content %}
|
||||
{% load crispy_forms_tags %}
|
||||
|
||||
{% load static %}
|
||||
|
||||
<h2 class="mb-4">SEO Configuration</h2>
|
||||
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
<div class="alert alert-{{ message.tags }}">{{ message }}</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
<form method="post" class="card p-4 shadow-sm">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<button type="submit" class="btn btn-primary">Save</button>
|
||||
</form>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
60
at_django_boilerplate/backend_admin/templates/subscriber.html
Executable file
60
at_django_boilerplate/backend_admin/templates/subscriber.html
Executable file
@@ -0,0 +1,60 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block content %}
|
||||
{% load crispy_forms_tags %}
|
||||
|
||||
<div class="mb-6">
|
||||
<a href="{% url 'admin_dashboard' %}"
|
||||
class="inline-block px-4 py-2 border-2 border-gray-800 rounded-xl font-bold text-gray-800 hover:text-gray-900 hover:border-gray-900 transition-colors">
|
||||
← Admin Dashboard
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 mt-8">
|
||||
|
||||
|
||||
<h2 class="text-3xl font-bold mb-6 text-gray-800 text-center">Subscriber List</h2>
|
||||
|
||||
<div class="overflow-x-auto shadow-lg rounded-lg">
|
||||
<table class="min-w-full bg-white divide-y divide-gray-200">
|
||||
<thead class="bg-indigo-600">
|
||||
<tr>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-white uppercase tracking-wider">ID</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-white uppercase tracking-wider">Email</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-white uppercase tracking-wider">Subscribed At</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-white uppercase tracking-wider">Status</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-white uppercase tracking-wider">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-100">
|
||||
{% for subscriber in subscribers %}
|
||||
<tr class="hover:bg-gray-50 transition-colors">
|
||||
<td class="px-6 py-4 whitespace-nowrap text-gray-800 font-medium">{{ subscriber.id }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-gray-700">{{ subscriber.email }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-gray-600">{{ subscriber.subscribed_at|date:"M d, Y H:i" }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
{% if subscriber.is_active %}
|
||||
<span class="text-green-600 font-semibold">✅ Active</span>
|
||||
{% else %}
|
||||
<span class="text-red-600 font-semibold">❌ Inactive</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
<a href="{% url 'toggle_subscriber' subscriber.id %}"
|
||||
class="text-indigo-600 hover:text-indigo-800 font-medium">
|
||||
{% if subscriber.is_active %}Deactivate{% else %}Activate{% endif %}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td colspan="6" class="text-center py-8 text-gray-400">No subscribers yet.</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user