ATS/templates/recruitment/agency_portal_persons_list.html
2026-02-01 13:38:06 +03:00

281 lines
16 KiB
HTML

{% extends 'portal_base.html' %}
{% load static i18n crispy_forms_tags %}
{% block title %}{% trans "Agency Applicant List" %} - ATS{% endblock %}
{% block content %}
<div class="container mx-auto px-4 py-8">
<!-- Header -->
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 mb-6 px-2 py-2">
<div>
<h1 class="text-3xl font-bold text-gray-900 mb-2 flex items-center gap-3">
<div class="bg-temple-red/10 p-3 rounded-xl">
<i data-lucide="users" class="w-8 h-8 text-temple-red"></i>
</div>
{% trans "All Applicants" %}
</h1>
<p class="text-gray-600">{% trans "All applicants who come through" %} {{ agency.name }}</p>
</div>
<button type="button" class="inline-flex items-center gap-2 bg-temple-red hover:bg-[#7a1a29] text-white font-semibold px-4 py-2.5 rounded-xl transition shadow-sm hover:shadow-md" data-bs-toggle="modal" data-bs-target="#personModal">
<i data-lucide="plus" class="w-4 h-4"></i> {% trans "Add New Applicant" %}
</button>
</div>
<!-- Search and Filter Section -->
<div class="bg-white rounded-2xl shadow-sm border border-gray-200 overflow-hidden mb-6">
<div class="p-6">
<form method="get">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label for="search" class="block text-sm font-semibold text-gray-700 mb-2 flex items-center gap-2">
<i data-lucide="search" class="w-4 h-4"></i>{% trans "Search" %}
</label>
<input type="text"
class="w-full px-4 py-2.5 border border-gray-300 rounded-lg focus:ring-2 focus:ring-temple-red focus:border-transparent transition"
id="search"
name="q"
value="{{ search_query }}"
placeholder="{% trans 'Search by name, email, phone...' %}">
</div>
</div>
</form>
</div>
</div>
<!-- Results Summary -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
<div class="bg-white rounded-2xl shadow-sm border border-gray-200 overflow-hidden">
<div class="p-6 text-center">
<div class="w-12 h-12 bg-temple-red/10 rounded-lg flex items-center justify-center mx-auto mb-3">
<i data-lucide="users" class="w-6 h-6 text-temple-red"></i>
</div>
<h4 class="text-2xl font-bold text-gray-900 mb-1">{{ total_persons }}</h4>
<p class="text-gray-600">{% trans "Total Persons" %}</p>
</div>
</div>
<div class="bg-white rounded-2xl shadow-sm border border-gray-200 overflow-hidden">
<div class="p-6 text-center">
<div class="w-12 h-12 bg-temple-red/10 rounded-lg flex items-center justify-center mx-auto mb-3">
<i data-lucide="check-circle" class="w-6 h-6 text-temple-red"></i>
</div>
<h4 class="text-2xl font-bold text-gray-900 mb-1">{{ page_obj|length }}</h4>
<p class="text-gray-600">{% trans "Showing on this page" %}</p>
</div>
</div>
</div>
<!-- Persons Table -->
<div class="bg-white rounded-2xl shadow-sm border border-gray-200 overflow-hidden">
<div class="overflow-x-auto">
{% if page_obj %}
<table class="w-full">
<thead class="bg-gray-50 border-b border-gray-200">
<tr>
<th class="text-left py-4 px-4 text-sm font-semibold text-gray-700">{% trans "Name" %}</th>
<th class="text-left py-4 px-4 text-sm font-semibold text-gray-700">{% trans "Email" %}</th>
<th class="text-left py-4 px-4 text-sm font-semibold text-gray-700">{% trans "Phone" %}</th>
<th class="text-left py-4 px-4 text-sm font-semibold text-gray-700">{% trans "Created At" %}</th>
<th class="text-center py-4 px-4 text-sm font-semibold text-gray-700">{% trans "Actions" %}</th>
</tr>
</thead>
<tbody>
{% for person in page_obj %}
<tr class="border-b border-gray-100 hover:bg-gray-50 transition cursor-pointer">
<td class="py-4 px-4">
<div class="flex items-center gap-3">
<div class="w-10 h-10 bg-temple-red text-white rounded-lg flex items-center justify-center font-bold text-sm">
{{ person.first_name|first|upper }}{{ person.last_name|first|upper }}
</div>
<div>
<div class="font-semibold text-gray-900">{{ person.first_name }} {{ person.last_name }}</div>
{% if person.address %}
<div class="text-sm text-gray-500">{{ person.address|truncatechars:50 }}</div>
{% endif %}
</div>
</div>
</td>
<td class="py-4 px-4">
<a href="mailto:{{ person.email }}" class="text-gray-900 hover:text-temple-red transition">{{ person.email }}</a>
</td>
<td class="py-4 px-4">{{ person.phone|default:"-" }}</td>
<td class="py-4 px-4">{{ person.created_at|date:"d-m-Y" }}</td>
<td class="py-4 px-4 text-center">
<button type="button" data-bs-toggle="modal" data-bs-target="#updateModal"
hx-get="{% url 'person_update' person.slug %}"
hx-target="#updateModalBody"
hx-swap="outerrHTML"
hx-select="#person-form"
hx-vals='{"view":"portal"}'
class="inline-flex items-center justify-center w-9 h-9 rounded-lg border border-gray-300 hover:border-temple-red hover:text-temple-red text-gray-600 transition"
title="{% trans 'Edit Person' %}">
<i data-lucide="edit-2" class="w-4 h-4"></i>
</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<div class="text-center py-10">
<div class="w-16 h-16 bg-gray-100 rounded-full flex items-center justify-center mx-auto mb-4">
<i data-lucide="users" class="w-8 h-8 text-gray-400"></i>
</div>
<h5 class="text-gray-600 mb-2">{% trans "No persons found" %}</h5>
<p class="text-gray-500 mb-4">
{% if search_query or stage_filter %}
{% trans "Try adjusting your search or filter criteria." %}
{% else %}
{% trans "No persons have been added yet." %}
{% endif %}
</p>
{% if not search_query and not stage_filter and agency.assignments.exists %}
<a href="{% url 'agency_portal_submit_application_page' agency.assignments.first.slug %}"
class="inline-flex items-center gap-2 bg-temple-red hover:bg-[#7a1a29] text-white font-semibold px-6 py-2.5 rounded-xl transition shadow-sm hover:shadow-md">
<i data-lucide="user-plus" class="w-4 h-4"></i> {% trans "Add First Person" %}
</a>
{% endif %}
</div>
{% endif %}
</div>
</div>
<!-- Pagination -->
{% if page_obj.has_other_pages %}
<nav aria-label="{% trans 'Persons pagination' %}" class="mt-6">
<div class="flex justify-center items-center gap-2">
{% if page_obj.has_previous %}
<a href="?page=1{% if search_query %}&q={{ search_query }}{% endif %}{% if stage_filter %}&stage={{ stage_filter }}{% endif %}" class="inline-flex items-center justify-center w-10 h-10 rounded-lg border border-gray-300 hover:border-temple-red hover:text-temple-red text-gray-600 transition">
<i data-lucide="chevrons-left" class="w-4 h-4"></i>
</a>
<a href="?page={{ page_obj.previous_page_number }}{% if search_query %}&q={{ search_query }}{% endif %}{% if stage_filter %}&stage={{ stage_filter }}{% endif %}" class="inline-flex items-center justify-center w-10 h-10 rounded-lg border border-gray-300 hover:border-temple-red hover:text-temple-red text-gray-600 transition">
<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 bg-temple-red text-white font-semibold">{{ num }}</span>
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
<a href="?page={{ num }}{% if search_query %}&q={{ search_query }}{% endif %}{% if stage_filter %}&stage={{ stage_filter }}{% endif %}" class="inline-flex items-center justify-center w-10 h-10 rounded-lg border border-gray-300 hover:border-temple-red hover:text-temple-red text-gray-600 transition">{{ num }}</a>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}{% if search_query %}&q={{ search_query }}{% endif %}{% if stage_filter %}&stage={{ stage_filter }}{% endif %}" class="inline-flex items-center justify-center w-10 h-10 rounded-lg border border-gray-300 hover:border-temple-red hover:text-temple-red text-gray-600 transition">
<i data-lucide="chevron-right" class="w-4 h-4"></i>
</a>
<a href="?page={{ page_obj.paginator.num_pages }}{% if search_query %}&q={{ search_query }}{% endif %}{% if stage_filter %}&stage={{ stage_filter }}{% endif %}" class="inline-flex items-center justify-center w-10 h-10 rounded-lg border border-gray-300 hover:border-temple-red hover:text-temple-red text-gray-600 transition">
<i data-lucide="chevrons-right" class="w-4 h-4"></i>
</a>
{% endif %}
</div>
</nav>
{% endif %}
</div>
<!-- Empty Modal -->
<div class="modal fade" id="updateModal" tabindex="-1" aria-labelledby="updateModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content" hx-boost="true" hx-vals='{"view":"portal"}' hx-select=".person-table" hx-target=".person-table"
hx-swap="outerHTML" hx-on::after-request="closeOpenBootstrapModal()">
<div class="modal-header">
<h5 class="modal-title" id="updateModalLabel">{% trans "Update" %}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body" id="updateModalBody">
</div>
<div class="modal-footer">
<div class="flex gap-2">
<button form="person-form" type="submit" class="inline-flex items-center gap-2 bg-temple-red hover:bg-[#7a1a29] text-white font-semibold px-4 py-2 rounded-xl transition">
<i data-lucide="save" class="w-4 h-4"></i> {% trans "Update" %}
</button>
</div>
</div>
</div>
</div>
</div>
<!-- Person Modal -->
<div class="modal fade" id="personModal" tabindex="-1" aria-labelledby="personModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title flex items-center gap-2" id="personModalLabel">
<i data-lucide="users" class="w-5 h-5"></i>
{% trans "Applicant Details" %}
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body" id="personModalBody">
<form id="person_form" method="post" action="{% url 'person_create' %}" >
{% csrf_token %}
<input type="hidden" name="view" value="portal">
<input type="hidden" name="agency" value="{{ agency.slug }}">
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div>
{{ person_form.first_name|as_crispy_field }}
</div>
<div>
{{ person_form.middle_name|as_crispy_field }}
</div>
<div>
{{ person_form.last_name|as_crispy_field }}
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
{{ person_form.email|as_crispy_field }}
{{person_form.errors}}
</div>
<div>
{{ person_form.phone|as_crispy_field }}
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
{{ person_form.gpa|as_crispy_field }}
</div>
<div>
{{ person_form.national_id|as_crispy_field }}
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
{{ person_form.date_of_birth|as_crispy_field }}
</div>
<div>
{{ person_form.nationality|as_crispy_field }}
</div>
</div>
<div>
{{ person_form.address|as_crispy_field }}
</div>
</form>
</div>
<div class="modal-footer">
<button class="inline-flex items-center gap-2 bg-temple-red hover:bg-[#7a1a29] text-white font-semibold px-4 py-2 rounded-xl transition" type="submit" form="person_form">{% trans "Save" %}</button>
<button type="button" class="inline-flex items-center gap-2 border border-gray-300 text-gray-700 hover:bg-gray-50 font-medium px-4 py-2 rounded-xl transition" data-bs-dismiss="modal">
{% trans "Close" %}
</button>
</div>
</div>
</div>
</div>
<script>
function openPersonModal(personId, personName) {
const modal = new bootstrap.Modal(document.getElementById('personModal'));
document.getElementById('person-modal-text').innerHTML = `<strong>${personName}</strong> (ID: ${personId})`;
modal.show();
}
function editPerson(personId) {
console.log('Edit person:', personId);
}
document.addEventListener('DOMContentLoaded', function() {
lucide.createIcons();
});
</script>
{% endblock %}