new list page addded"
This commit is contained in:
parent
d8a7442b9d
commit
ff42e35855
Binary file not shown.
Binary file not shown.
BIN
db.sqlite3
BIN
db.sqlite3
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -242,6 +242,14 @@ class JobPosting(Base):
|
||||
self.save()
|
||||
|
||||
|
||||
class JobPostingImage(models.Model):
|
||||
job=models.ForeignKey('JobPosting',on_delete=models.CASCADE,related_name='post_images')
|
||||
post_image = models.ImageField(upload_to='post/',
|
||||
height_field='photo_height',
|
||||
width_field='photo_width')
|
||||
post_image_height = models.PositiveIntegerField(null=True, blank=True)
|
||||
post_image_width = models.PositiveIntegerField(null=True, blank=True)
|
||||
|
||||
class Candidate(Base):
|
||||
class Stage(models.TextChoices):
|
||||
APPLIED = "Applied", _("Applied")
|
||||
|
||||
@ -2,12 +2,12 @@
|
||||
{% load static i18n crispy_forms_tags %}
|
||||
{% load partials %}
|
||||
|
||||
{% block title %}Form Templates - ATS{% endblock %}
|
||||
{% block title %}Form Templates - {{ block.super }}{% endblock %}
|
||||
|
||||
{% block customCSS %}
|
||||
<style>
|
||||
/* ================================================= */
|
||||
/* UI Variables (Matching Job List) */
|
||||
/* UI Variables (Matching Standard Theme) */
|
||||
/* ================================================= */
|
||||
:root {
|
||||
--kaauh-teal: #00636e;
|
||||
@ -20,23 +20,22 @@
|
||||
/* --- Typography and Color Overrides --- */
|
||||
.text-primary { color: var(--kaauh-teal) !important; }
|
||||
|
||||
/* --- Button Base Styles (Matching Job List) --- */
|
||||
/* --- Button Base Styles (Consistent) --- */
|
||||
.btn-main-action {
|
||||
background-color: var(--kaauh-teal);
|
||||
border-color: var(--kaauh-teal);
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
padding: 0.375rem 0.75rem;
|
||||
border-radius: 0.5rem;
|
||||
transition: all 0.2s ease;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
gap: 0.4rem;
|
||||
padding: 0.5rem 1rem;
|
||||
}
|
||||
.btn-main-action:hover {
|
||||
background-color: var(--kaauh-teal-dark);
|
||||
border-color: var(--kaauh-teal-dark);
|
||||
transform: translateY(-1px);
|
||||
transform: none; /* Removed translate to match other lists */
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
|
||||
color: white;
|
||||
}
|
||||
@ -51,18 +50,17 @@
|
||||
color: white;
|
||||
border-color: var(--kaauh-teal-dark);
|
||||
}
|
||||
|
||||
/* Size Utilities (matching Bootstrap convention) */
|
||||
.btn-lg {
|
||||
padding: 0.75rem 1.5rem;
|
||||
font-size: 1.1rem;
|
||||
/* Primary Outline for View/Preview */
|
||||
.btn-outline-primary {
|
||||
color: var(--kaauh-teal);
|
||||
border-color: var(--kaauh-teal);
|
||||
}
|
||||
.btn-sm {
|
||||
font-size: 0.8rem;
|
||||
padding: 0.3rem 0.6rem;
|
||||
.btn-outline-primary:hover {
|
||||
background-color: var(--kaauh-teal);
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* --- Card and Layout Styles (Matching Job List) --- */
|
||||
/* --- Card and Layout Styles (Consistent) --- */
|
||||
.card {
|
||||
border: 1px solid var(--kaauh-border);
|
||||
border-radius: 0.75rem;
|
||||
@ -70,42 +68,24 @@
|
||||
background-color: white;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
|
||||
/* Template Card Hover Effect (Consistent with job list card hover) */
|
||||
.template-card {
|
||||
height: 100%;
|
||||
}
|
||||
.template-card:hover {
|
||||
.card:not(.no-hover):hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 16px rgba(0,0,0,0.1) !important;
|
||||
}
|
||||
|
||||
/* Card Header Theming */
|
||||
.card.no-hover:hover {
|
||||
transform: none;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
|
||||
}
|
||||
|
||||
/* Card Header (For Search/Filter Card) */
|
||||
.card-header {
|
||||
/* FIX: Use !important to override default white/light backgrounds from Bootstrap */
|
||||
background-color: var(--kaauh-teal-dark) !important;
|
||||
border-bottom: 1px solid var(--kaauh-border);
|
||||
color: white !important; /* Base color for header text */
|
||||
font-weight: 600;
|
||||
padding: 1rem 1.25rem;
|
||||
border-radius: 0.75rem 0.75rem 0 0;
|
||||
}
|
||||
|
||||
/* Ensure all elements within the header are visible */
|
||||
.card-header h3 {
|
||||
color: white !important;
|
||||
font-weight: 700;
|
||||
}
|
||||
.card-header .fas {
|
||||
color: white !important;
|
||||
}
|
||||
.card-header .small {
|
||||
color: rgba(255, 255, 255, 0.7) !important;
|
||||
padding: 1.25rem;
|
||||
border-bottom: 1px solid var(--kaauh-border);
|
||||
background-color: var(--kaauh-gray-light);
|
||||
}
|
||||
|
||||
/* Stats Theming */
|
||||
|
||||
/* --- Content Styles (Stats, Description) --- */
|
||||
.stat-value {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 800;
|
||||
@ -116,58 +96,28 @@
|
||||
color: var(--kaauh-primary-text);
|
||||
font-weight: 500;
|
||||
}
|
||||
.card-description {
|
||||
min-height: 60px;
|
||||
color: var(--kaauh-primary-text);
|
||||
}
|
||||
|
||||
/* Search Input Theming */
|
||||
.form-control {
|
||||
border-radius: 0.5rem 0 0 0.5rem;
|
||||
/* Table Styling (Consistent) */
|
||||
.table-view .table thead th {
|
||||
background-color: var(--kaauh-teal-dark);
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
border-color: var(--kaauh-border);
|
||||
border-radius: 0 0.5rem 0.5rem 0;
|
||||
text-transform: uppercase;
|
||||
font-size: 0.8rem;
|
||||
letter-spacing: 0.5px;
|
||||
padding: 1rem;
|
||||
}
|
||||
.form-control-search:focus {
|
||||
border-color: var(--kaauh-teal);
|
||||
box-shadow: 0 0 0 0.1rem rgba(0, 99, 110, 0.25);
|
||||
}
|
||||
.input-group-search .input-group-text {
|
||||
background-color: white;
|
||||
border-right: none;
|
||||
.table-view .table tbody td {
|
||||
vertical-align: middle;
|
||||
padding: 1rem;
|
||||
border-color: var(--kaauh-border);
|
||||
border-radius: 0.5rem 0 0 0.5rem;
|
||||
}
|
||||
.input-group-search .form-control {
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
/* --- Danger Outline (Delete) --- */
|
||||
.btn-outline-danger {
|
||||
--bs-btn-color: #dc3545;
|
||||
--bs-btn-border-color: #dc3545;
|
||||
--bs-btn-hover-bg: #dc3545;
|
||||
--bs-btn-hover-color: white;
|
||||
}
|
||||
|
||||
/* Empty State Theming */
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 3rem 1rem;
|
||||
color: var(--kaauh-primary-text);
|
||||
border: 2px dashed var(--kaauh-border);
|
||||
border-radius: 0.75rem;
|
||||
.table-view .table tbody tr:hover {
|
||||
background-color: var(--kaauh-gray-light);
|
||||
}
|
||||
.empty-state i {
|
||||
font-size: 3.5rem;
|
||||
margin-bottom: 1rem;
|
||||
color: var(--kaauh-teal-dark);
|
||||
}
|
||||
.empty-state .btn-main-action .fas {
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
/* --- Pagination Styling (Matching Job List) --- */
|
||||
/* Pagination Styling (Consistent) */
|
||||
.pagination .page-item .page-link {
|
||||
color: var(--kaauh-teal-dark);
|
||||
border-color: var(--kaauh-border);
|
||||
@ -180,30 +130,40 @@
|
||||
.pagination .page-item:hover .page-link:not(.active) {
|
||||
background-color: #e9ecef;
|
||||
}
|
||||
</style>
|
||||
|
||||
/* Empty State Icon Color */
|
||||
.empty-state i, .text-center i.fa-3x {
|
||||
color: var(--kaauh-teal-dark) !important;
|
||||
}
|
||||
|
||||
/* Filter Buttons Container */
|
||||
.filter-buttons {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container py-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4 pb-2 border-bottom border-primary">
|
||||
<h1 class="h3 mb-0 fw-bold" style="color: var(--kaauh-teal-dark); font-weight: 700;">
|
||||
<div class="container-fluid py-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h1 class="h3 mb-0" style="color: var(--kaauh-teal-dark); font-weight: 700;">
|
||||
<i class="fas fa-file-alt me-2"></i>{% trans "Form Templates" %}
|
||||
</h1>
|
||||
<button type="button" class="btn btn-main-action" data-bs-toggle="modal" data-bs-target="#createTemplateModal">
|
||||
<i class="fas fa-plus me-1"></i> Create New Template
|
||||
<i class="fas fa-plus me-1"></i> {% trans "Create New Template" %}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{# Search/Filter Area - Matching Job List Structure #}
|
||||
{# Search/Filter Area - Matching Standard Structure #}
|
||||
<div class="card mb-4 shadow-sm no-hover">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title text-muted mb-3" style="font-weight: 500;">Search Templates</h5>
|
||||
<form method="get" class="row g-3 align-items-end">
|
||||
|
||||
<div class="col-md-6">
|
||||
<label for="search" class="form-label small text-muted">Search by Template Name</label>
|
||||
<div class="input-group input-group-lg input-group-search">
|
||||
<label for="searchInput" class="form-label small text-muted">{% trans "Search by Template Name" %}</label>
|
||||
<div class="input-group input-group-lg">
|
||||
<span class="input-group-text"><i class="fas fa-search text-muted"></i></span>
|
||||
<input type="text" name="q" id="searchInput" class="form-control form-control-search"
|
||||
placeholder="{% trans 'Search templates by name...' %}"
|
||||
@ -214,13 +174,13 @@
|
||||
<div class="col-md-6">
|
||||
<div class="filter-buttons">
|
||||
<button type="submit" class="btn btn-main-action btn-lg">
|
||||
<i class="fas fa-filter me-1"></i> Search
|
||||
<i class="fas fa-filter me-1"></i> {% trans "Search" %}
|
||||
</button>
|
||||
|
||||
{# Show Clear button if search is active #}
|
||||
{% if query %}
|
||||
<a href="{% url 'form_templates_list' %}" class="btn btn-outline-danger btn-sm">
|
||||
<i class="fas fa-times me-1"></i> Clear Search
|
||||
<a href="{% url 'form_templates_list' %}" class="btn btn-outline-secondary btn-lg">
|
||||
<i class="fas fa-times me-1"></i> {% trans "Clear Search" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
@ -239,59 +199,62 @@
|
||||
<div class="card-view active row g-4">
|
||||
{% for template in templates %}
|
||||
<div class="col-lg-4 col-md-6">
|
||||
<div class="card template-card h-100">
|
||||
<div class="card-header ">
|
||||
<h3 class="h5 mb-2">{{ template.name }}</h3>
|
||||
<span><i class="fas fa-sync-alt me-1"></i> {{ template.job }}</span>
|
||||
<div class="d-flex justify-content-between text-muted small">
|
||||
<span><i class="fas fa-calendar me-1"></i> {{ template.created_at|date:"M d, Y" }}</span>
|
||||
<span><i class="fas fa-sync-alt me-1"></i> {{ template.updated_at|timesince }} {% trans "ago" %}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card template-card h-100 shadow-sm">
|
||||
<div class="card-body d-flex flex-column">
|
||||
|
||||
{# Content area - includes stats and description #}
|
||||
<div class="flex-grow-1">
|
||||
<div class="row text-center mb-3">
|
||||
<div class="col-6">
|
||||
<div class="stat-value">{{ template.get_stage_count }}</div>
|
||||
<div class="stat-label">{% trans "Stages" %}</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="stat-value">{{ template.get_field_count }}</div>
|
||||
<div class="stat-label">{% trans "Fields" %}</div>
|
||||
</div>
|
||||
<h5 class="card-title fw-bold" style="color: var(--kaauh-teal-dark);">{{ template.name }}</h5>
|
||||
<span class="text-muted small mb-3">
|
||||
<i class="fas fa-briefcase me-1"></i> {{ template.job|default:"N/A" }}
|
||||
</span>
|
||||
|
||||
{# Stats #}
|
||||
<div class="row text-center mb-3">
|
||||
<div class="col-6 border-end">
|
||||
<div class="stat-value">{{ template.get_stage_count }}</div>
|
||||
<div class="stat-label">{% trans "Stages" %}</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="stat-value">{{ template.get_field_count }}</div>
|
||||
<div class="stat-label">{% trans "Fields" %}</div>
|
||||
</div>
|
||||
<p class="card-text card-description small">
|
||||
{% if template.description %}
|
||||
{{ template.description|truncatewords:20 }}
|
||||
{% else %}
|
||||
<em class="text-muted">{% trans "No description provided" %}</em>
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{# Description #}
|
||||
<p class="card-text small text-muted flex-grow-1">
|
||||
{% if template.description %}
|
||||
{{ template.description|truncatewords:20 }}
|
||||
{% else %}
|
||||
<em class="text-muted">{% trans "No description provided" %}</em>
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
{# Action area - visually separated with pt-2 border-top #}
|
||||
{# Action area #}
|
||||
<div class="mt-auto pt-2 border-top">
|
||||
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
|
||||
<div class="d-flex gap-2 justify-content-end">
|
||||
|
||||
<a href="{% url 'form_wizard' template.id %}" class="btn btn-outline-secondary btn-sm action-btn">
|
||||
<i class="fas fa-eye me-1"></i> {% trans "Preview" %}
|
||||
<a href="{% url 'form_wizard' template.id %}" class="btn btn-outline-primary btn-sm" title="{% trans 'Preview' %}">
|
||||
<i class="fas fa-eye"></i>
|
||||
</a>
|
||||
<a href="{% url 'form_builder' template.id %}" class="btn btn-outline-secondary btn-sm action-btn">
|
||||
<i class="fas fa-edit me-1"></i> {% trans "Edit" %}
|
||||
<a href="{% url 'form_builder' template.id %}" class="btn btn-outline-secondary btn-sm" title="{% trans 'Edit' %}">
|
||||
<i class="fas fa-edit"></i>
|
||||
</a>
|
||||
<a href="{% url 'form_template_submissions_list' template.slug %}" class="btn btn-outline-secondary btn-sm action-btn">
|
||||
<i class="fas fa-file-alt me-1"></i> {% trans "Submissions" %}
|
||||
<a href="{% url 'form_template_submissions_list' template.slug %}" class="btn btn-outline-secondary btn-sm" title="{% trans 'Submissions' %}">
|
||||
<i class="fas fa-file-alt"></i>
|
||||
</a>
|
||||
<button class="btn btn-outline-danger btn-sm action-btn delete"
|
||||
data-template-id="{{ template.id }}"
|
||||
data-template-name="{{ template.name }}">
|
||||
<i class="fas fa-trash me-1"></i> {% trans "Delete" %}
|
||||
<button type="button" class="btn btn-outline-danger btn-sm" title="{% trans 'Delete' %}"
|
||||
data-bs-toggle="modal" data-bs-target="#deleteModal"
|
||||
data-delete-url="#"
|
||||
data-item-name="{{ template.name }}">
|
||||
<i class="fas fa-trash-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer bg-light text-muted small">
|
||||
<div class="d-flex justify-content-between">
|
||||
<span><i class="fas fa-calendar-alt me-1"></i> {% trans "Created:" %} {{ template.created_at|date:"M d, Y" }}</span>
|
||||
<span><i class="fas fa-sync-alt me-1"></i> {{ template.updated_at|timesince }} {% trans "ago" %}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
@ -300,23 +263,23 @@
|
||||
{# Table View #}
|
||||
<div class="table-view">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<table class="table table-hover align-middle mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">{% trans "Template Name" %}</th>
|
||||
<th scope="col">{% trans "Job" %}</th>
|
||||
<th scope="col">{% trans "Stages" %}</th>
|
||||
<th scope="col">{% trans "Fields" %}</th>
|
||||
<th scope="col">{% trans "Created" %}</th>
|
||||
<th scope="col">{% trans "Last Updated" %}</th>
|
||||
<th scope="col" class="text-end">{% trans "Actions" %}</th>
|
||||
<th scope="col" style="width: 30%;">{% trans "Template Name" %}</th>
|
||||
<th scope="col" style="width: 15%;">{% trans "Job" %}</th>
|
||||
<th scope="col" style="width: 8%;">{% trans "Stages" %}</th>
|
||||
<th scope="col" style="width: 8%;">{% trans "Fields" %}</th>
|
||||
<th scope="col" style="width: 15%;">{% trans "Created" %}</th>
|
||||
<th scope="col" style="width: 15%;">{% trans "Last Updated" %}</th>
|
||||
<th scope="col" style="width: 9%;" class="text-end">{% trans "Actions" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for template in templates %}
|
||||
<tr>
|
||||
<td class="fw-medium">{{ template.name }}</td>
|
||||
<td>{{ template.job }}</td>
|
||||
<td class="fw-medium text-primary">{{ template.name }}</td>
|
||||
<td>{{ template.job|default:"N/A" }}</td>
|
||||
<td>{{ template.get_stage_count }}</td>
|
||||
<td>{{ template.get_field_count }}</td>
|
||||
<td>{{ template.created_at|date:"M d, Y" }}</td>
|
||||
@ -329,11 +292,14 @@
|
||||
<a href="{% url 'form_builder' template.id %}" class="btn btn-outline-secondary" title="{% trans 'Edit' %}">
|
||||
<i class="fas fa-edit"></i>
|
||||
</a>
|
||||
<a href="{% url 'form_template_submissions_list' template.slug %}" class="btn btn-outline-info" title="{% trans 'Submissions' %}">
|
||||
<a href="{% url 'form_template_submissions_list' template.slug %}" class="btn btn-outline-secondary" title="{% trans 'Submissions' %}">
|
||||
<i class="fas fa-file-alt"></i>
|
||||
</a>
|
||||
<button class="btn btn-outline-danger delete-btn" data-bs-toggle="modal" data-bs-target="#deleteModal" data-template-id="{{ template.id }}" data-template-name="{{ template.name }}" title="{% trans 'Delete' %}">
|
||||
<i class="fas fa-trash"></i>
|
||||
<button type="button" class="btn btn-outline-danger" title="{% trans 'Delete' %}"
|
||||
data-bs-toggle="modal" data-bs-target="#deleteModal"
|
||||
data-delete-url="#"
|
||||
data-item-name="{{ template.name }}">
|
||||
<i class="fas fa-trash-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
@ -345,10 +311,10 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Pagination (Standardized) #}
|
||||
{% if templates.has_other_pages %}
|
||||
<nav aria-label="Page navigation" class="mt-4">
|
||||
<ul class="pagination justify-content-center">
|
||||
{# Previous page logic #}
|
||||
{% if templates.has_previous %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page=1{% if query %}&q={{ query }}{% endif %}">First</a>
|
||||
@ -358,12 +324,10 @@
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{# Current Page #}
|
||||
<li class="page-item active">
|
||||
<span class="page-link">{{ templates.number }} of {{ templates.paginator.num_pages }}</span>
|
||||
</li>
|
||||
|
||||
{# Next page logic #}
|
||||
{% if templates.has_next %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ templates.next_page_number }}{% if query %}&q={{ query }}{% endif %}">Next</a>
|
||||
@ -387,9 +351,9 @@
|
||||
{% trans "You haven't created any form templates yet." %}
|
||||
{% endif %}
|
||||
</p>
|
||||
<a href="{% url 'form_builder' %}" class="btn btn-main-action mt-3">
|
||||
<i class="fas fa-plus me-1 text-white"></i> {% trans "Create Your First Template" %}
|
||||
</a>
|
||||
<button type="button" class="btn btn-main-action mt-3" data-bs-toggle="modal" data-bs-target="#createTemplateModal">
|
||||
<i class="fas fa-plus me-1"></i> {% trans "Create Your First Template" %}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
@ -398,13 +362,12 @@
|
||||
|
||||
{% include 'includes/delete_modal.html' %}
|
||||
|
||||
<!-- Create Template Modal -->
|
||||
<div class="modal fade" id="createTemplateModal" tabindex="-1" aria-labelledby="createTemplateModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<div class="modal-header bg-light">
|
||||
<h5 class="modal-title" id="createTemplateModalLabel">
|
||||
<i class="fas fa-file-alt me-2"></i>Create New Form Template
|
||||
<i class="fas fa-file-alt me-2"></i>{% trans "Create New Form Template" %}
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
@ -416,12 +379,12 @@
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="submit" form="createTemplateForm" class="btn btn-primary">
|
||||
<i class="fas fa-save me-1"></i>Create Template
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% trans "Cancel" %}</button>
|
||||
<button type="submit" form="createTemplateForm" class="btn btn-main-action">
|
||||
<i class="fas fa-save me-1"></i>{% trans "Create Template" %}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
@ -10,6 +10,8 @@
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* --- View Switcher Styles (Consolidated & Corrected) --- */
|
||||
|
||||
/* View Toggle Styles */
|
||||
.view-toggle {
|
||||
border-radius: 0.25rem;
|
||||
@ -28,13 +30,17 @@
|
||||
/* Hide elements by default */
|
||||
.table-view,
|
||||
.card-view {
|
||||
display: none;
|
||||
display: none !important; /* Use !important to ensure hiding works */
|
||||
}
|
||||
|
||||
/* Show active view */
|
||||
.table-view.active,
|
||||
.table-view.active {
|
||||
display: block !important;
|
||||
}
|
||||
.card-view.active {
|
||||
display: block;
|
||||
/* Rely on the 'row' class which uses display: flex for proper column alignment. */
|
||||
display: flex !important; /* rows often use display: flex in Bootstrap */
|
||||
flex-wrap: wrap !important;
|
||||
}
|
||||
|
||||
/* Card View Styles */
|
||||
@ -105,16 +111,19 @@
|
||||
.table-view .table tbody tr {
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
/* NOTE: We need to assume var(--kaauh-gray-light) is defined in base.html or job_list.html */
|
||||
.table-view .table tbody tr:hover {
|
||||
background-color: var(--kaauh-gray-light);
|
||||
background-color: #f0f0f0; /* Fallback color for hover */
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Get the list ID from the data attribute
|
||||
const listId = document.querySelector('.view-toggle').getAttribute('data-list-id');
|
||||
const listContainer = document.getElementById(listId);
|
||||
const listContainer = document.getElementById('{{ list_id }}');
|
||||
if (!listContainer) return; // Exit if container isn't found
|
||||
|
||||
// Get list ID from the data attribute (or use the variable from Django context if the button is loaded)
|
||||
const listId = listContainer.id;
|
||||
|
||||
// Get saved view preference from localStorage
|
||||
const savedView = localStorage.getItem(`list_view_${listId}`) || 'table';
|
||||
@ -124,15 +133,18 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
|
||||
// Add click event listeners to view toggle buttons
|
||||
document.querySelectorAll('.view-toggle').forEach(button => {
|
||||
button.addEventListener('click', function() {
|
||||
const view = this.getAttribute('data-view');
|
||||
setView(view);
|
||||
});
|
||||
// Ensure the button belongs to this list (optional check)
|
||||
if (button.getAttribute('data-list-id') === listId) {
|
||||
button.addEventListener('click', function() {
|
||||
const view = this.getAttribute('data-view');
|
||||
setView(view);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function setView(view) {
|
||||
// Update button states
|
||||
document.querySelectorAll('.view-toggle').forEach(button => {
|
||||
document.querySelectorAll('.view-toggle[data-list-id="{{ list_id }}"]').forEach(button => {
|
||||
if (button.getAttribute('data-view') === view) {
|
||||
button.classList.add('active');
|
||||
} else {
|
||||
@ -144,16 +156,17 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
const tableView = listContainer.querySelector('.table-view');
|
||||
const cardView = listContainer.querySelector('.card-view');
|
||||
|
||||
// Apply active class to the correct container
|
||||
if (view === 'table') {
|
||||
tableView.classList.add('active');
|
||||
cardView.classList.remove('active');
|
||||
if (tableView) tableView.classList.add('active');
|
||||
if (cardView) cardView.classList.remove('active');
|
||||
} else {
|
||||
tableView.classList.remove('active');
|
||||
cardView.classList.add('active');
|
||||
if (tableView) tableView.classList.remove('active');
|
||||
if (cardView) cardView.classList.add('active');
|
||||
}
|
||||
|
||||
// Save preference to localStorage
|
||||
localStorage.setItem(`list_view_${listId}`, view);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
@ -261,7 +261,20 @@
|
||||
</div>
|
||||
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<span class="badge bg-success status-badge">
|
||||
<span class="badge status-badge">
|
||||
{% if job.status == "ACTIVE" %}
|
||||
<span class="badge bg-success status-badge">
|
||||
{% elif job.status == "DRAFT" %}
|
||||
<span class="badge bg-secondary status-badge">
|
||||
{% elif job.status == "CLOSED" %}
|
||||
<span class="badge bg-warning status-badge">
|
||||
{% elif job.status == "CANCELLED" %}
|
||||
<span class="badge bg-danger status-badge">
|
||||
{% elif job.status == "ARCHIVED" %}
|
||||
<span class="badge bg-secondary status-badge">
|
||||
{% else %}
|
||||
<span class="badge bg-secondary status-badge">
|
||||
{% endif %}
|
||||
{{ job.get_status_display }}
|
||||
<button type="button" class="btn btn-outline-light btn-sm ms-2" data-bs-toggle="modal" data-bs-target="#editStatusModal">
|
||||
<i class="fas fa-edit text-primary"></i>
|
||||
@ -550,7 +563,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--image modal class-->
|
||||
{% include "jobs/partials/image_upload.html" %}
|
||||
|
||||
<!-- JOB STATUS MODAL-->
|
||||
|
||||
@ -171,7 +171,7 @@
|
||||
{# Card View (Default) #}
|
||||
<div class="card-view active row">
|
||||
{% for job in page_obj %}
|
||||
<div class="col-md-6 col-lg-4 mb-4">
|
||||
<div class="col-md-6 col-lg-4 mb-4 ">
|
||||
<div class="card job-card h-100">
|
||||
<div class="card-body d-flex flex-column">
|
||||
<div class="d-flex justify-content-between align-items-start mb-2">
|
||||
|
||||
@ -2,11 +2,11 @@
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="myModalLabel">Add New Comment</h5>
|
||||
<h5 class="modal-title" id="myModalLabel">Add New Image</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form method="post" action="{% url 'job_create' %}">
|
||||
<form method="post" action="{% url 'job_detail' job.slug %}">
|
||||
{% csrf_token %}
|
||||
{{ image_form }}
|
||||
<div class="modal-footer">
|
||||
|
||||
@ -2,199 +2,120 @@
|
||||
{% load static i18n %}
|
||||
|
||||
{% block title %}{% trans "Zoom Meetings" %} - {{ block.super }}{% endblock %}
|
||||
|
||||
{% block customCSS %}
|
||||
<style>
|
||||
/* UI Variables for the KAAT-S Theme */
|
||||
/* UI Variables for the KAAT-S Theme (Consistent with Reference) */
|
||||
:root {
|
||||
--kaauh-teal: #00636e;
|
||||
--kaauh-teal-dark: #004a53;
|
||||
--kaauh-border: #eaeff3;
|
||||
--kaauh-primary-text: #343a40;
|
||||
--kaauh-gray: #6c757d;
|
||||
|
||||
/* Status Colors based on KAAT-S example */
|
||||
--kaauh-success: var(--kaauh-teal);
|
||||
--kaauh-warning: #ffc107;
|
||||
--kaauh-danger: #dc3545;
|
||||
--kaauh-secondary: #6c757d;
|
||||
--kaauh-gray-light: #f8f9fa;
|
||||
}
|
||||
|
||||
/* Base style for all buttons to inherit Bootstrap's basic structure/reset */
|
||||
.btn-base {
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
padding: 0.375rem 0.75rem; /* Standard default padding */
|
||||
font-size: 1rem;
|
||||
line-height: 1.5;
|
||||
border-radius: 0.25rem;
|
||||
border: 1px solid transparent;
|
||||
transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
|
||||
/* FIX: Remove link underline for anchor tags used as buttons */
|
||||
text-decoration: none;
|
||||
/* Enhanced Card Styling (Consistent) */
|
||||
.card {
|
||||
border: 1px solid var(--kaauh-border);
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
background-color: white;
|
||||
}
|
||||
.card:not(.no-hover):hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 16px rgba(0,0,0,0.1);
|
||||
}
|
||||
.card.no-hover:hover {
|
||||
transform: none;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
|
||||
}
|
||||
|
||||
/* Small Button Size */
|
||||
.btn-sm {
|
||||
padding: 0.3rem 0.6rem;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* Main Action Button (Create Meeting) */
|
||||
/* Main Action Button Style (Teal Theme) */
|
||||
.btn-main-action {
|
||||
background-color: var(--kaauh-teal);
|
||||
border-color: var(--kaauh-teal);
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
transition: all 0.2s ease;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
padding: 0.5rem 1rem;
|
||||
}
|
||||
|
||||
.btn-main-action:hover {
|
||||
background-color: var(--kaauh-teal-dark);
|
||||
border-color: var(--kaauh-teal-dark);
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
|
||||
text-decoration: none; /* Ensure no hover underline if base fails */
|
||||
}
|
||||
|
||||
/* Outline Primary (View/Join buttons) */
|
||||
.btn-kaats-outline-primary {
|
||||
/* Secondary Button Style (For Edit/Outline - Consistent) */
|
||||
.btn-outline-secondary {
|
||||
color: var(--kaauh-teal-dark);
|
||||
border-color: var(--kaauh-teal);
|
||||
}
|
||||
.btn-outline-secondary:hover {
|
||||
background-color: var(--kaauh-teal-dark);
|
||||
color: white;
|
||||
border-color: var(--kaauh-teal-dark);
|
||||
}
|
||||
/* Primary Outline for View/Join */
|
||||
.btn-outline-primary {
|
||||
color: var(--kaauh-teal);
|
||||
border-color: var(--kaauh-teal);
|
||||
background-color: transparent;
|
||||
}
|
||||
.btn-kaats-outline-primary:hover {
|
||||
.btn-outline-primary:hover {
|
||||
background-color: var(--kaauh-teal);
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Outline Secondary (Update button) */
|
||||
.btn-kaats-outline-secondary {
|
||||
color: var(--kaauh-secondary);
|
||||
border-color: var(--kaauh-secondary);
|
||||
background-color: transparent;
|
||||
}
|
||||
.btn-kaats-outline-secondary:hover {
|
||||
background-color: var(--kaauh-secondary);
|
||||
color: white;
|
||||
border-color: var(--kaauh-secondary);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Outline Danger (Delete button) */
|
||||
.btn-kaats-outline-danger {
|
||||
color: var(--kaauh-danger);
|
||||
border-color: var(--kaauh-danger);
|
||||
background-color: transparent;
|
||||
}
|
||||
.btn-kaats-outline-danger:hover {
|
||||
background-color: var(--kaauh-danger);
|
||||
color: white;
|
||||
border-color: var(--kaauh-danger);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* --- General UI Styles (Unchanged) --- */
|
||||
|
||||
/* CARD GRID STYLES */
|
||||
.meetings-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||
gap: 1.5rem;
|
||||
padding: 1rem;
|
||||
}
|
||||
.meeting-card {
|
||||
background: white;
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
|
||||
padding: 1.5rem;
|
||||
border: 1px solid var(--kaauh-border);
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
height: 100%;
|
||||
}
|
||||
.meeting-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 16px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
/* TOPIC AND DETAILS STYLES */
|
||||
.meeting-topic {
|
||||
font-size: 1.15rem;
|
||||
font-weight: 600;
|
||||
/* Meeting Card Specifics (Adapted to Standard Card View) */
|
||||
.meeting-card .card-title {
|
||||
color: var(--kaauh-teal-dark);
|
||||
margin-bottom: 1rem;
|
||||
border-bottom: 1px solid var(--kaauh-border);
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
.meeting-detail {
|
||||
display: flex;
|
||||
margin-bottom: 0.75rem;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.detail-label {
|
||||
font-weight: 600;
|
||||
min-width: 80px;
|
||||
color: var(--kaauh-gray);
|
||||
font-size: 0.9rem;
|
||||
flex-shrink: 0;
|
||||
font-size: 1.15rem;
|
||||
}
|
||||
.detail-value {
|
||||
flex: 1;
|
||||
font-size: 0.9rem;
|
||||
word-break: break-word;
|
||||
color: var(--kaauh-primary-text);
|
||||
.meeting-card .card-text i {
|
||||
color: var(--kaauh-teal);
|
||||
width: 1.25rem;
|
||||
}
|
||||
|
||||
/* STATUS BADGE STYLES */
|
||||
/* Status Badges (Standardized) */
|
||||
.status-badge {
|
||||
display: inline-block;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
font-size: 0.8rem;
|
||||
padding: 0.4em 0.8em;
|
||||
border-radius: 0.4rem;
|
||||
text-align: center;
|
||||
color: white;
|
||||
}
|
||||
.bg-warning {
|
||||
background: var(--kaauh-warning) !important;
|
||||
color: var(--kaauh-primary-text) !important;
|
||||
}
|
||||
.bg-success {
|
||||
background: var(--kaauh-success) !important;
|
||||
color: white !important;
|
||||
}
|
||||
.bg-danger {
|
||||
background: var(--kaauh-danger) !important;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
/* ACTION AREA STYLES */
|
||||
.actions {
|
||||
margin-top: 1rem;
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
/* Header Styling */
|
||||
.card-header h1 {
|
||||
color: var(--kaauh-teal-dark);
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.7px;
|
||||
}
|
||||
.card {
|
||||
border: 1px solid var(--kaauh-border);
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
|
||||
}
|
||||
/* Status Badge Mapping */
|
||||
.bg-waiting { background-color: #ffc107 !important; color: var(--kaauh-primary-text) !important;}
|
||||
.bg-started { background-color: var(--kaauh-teal) !important; color: white !important;}
|
||||
.bg-ended { background-color: #dc3545 !important; color: white !important;}
|
||||
|
||||
/* Empty State Icon Color */
|
||||
.text-muted.mb-3 {
|
||||
color: var(--kaauh-teal-dark) !important;
|
||||
/* Table Styling (Consistent with Reference) */
|
||||
.table-view .table thead th {
|
||||
background-color: var(--kaauh-teal-dark);
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
border-color: var(--kaauh-border);
|
||||
text-transform: uppercase;
|
||||
font-size: 0.8rem;
|
||||
letter-spacing: 0.5px;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
/* Pagination Link Styling */
|
||||
.table-view .table tbody td {
|
||||
vertical-align: middle;
|
||||
padding: 1rem;
|
||||
border-color: var(--kaauh-border);
|
||||
}
|
||||
.table-view .table tbody tr:hover {
|
||||
background-color: var(--kaauh-gray-light);
|
||||
}
|
||||
|
||||
/* Pagination Link Styling (Consistent) */
|
||||
.pagination .page-item .page-link {
|
||||
color: var(--kaauh-teal-dark);
|
||||
border-color: var(--kaauh-border);
|
||||
@ -208,120 +129,123 @@
|
||||
background-color: #e9ecef;
|
||||
}
|
||||
|
||||
/* RESPONSIVE STYLES */
|
||||
@media (max-width: 768px) {
|
||||
.meetings-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.meeting-detail {
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
.detail-label {
|
||||
min-width: auto;
|
||||
}
|
||||
/* Filter & Search Layout Adjustments */
|
||||
.filter-buttons {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
/* Icon color for empty state */
|
||||
.text-muted.fa-3x {
|
||||
color: var(--kaauh-teal-dark) !important;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<h1 class="h3 mb-0">
|
||||
{% include "icons/meeting.html" %}
|
||||
{% trans "Zoom Meetings" %}
|
||||
</h1>
|
||||
<div class="d-flex gap-2 align-items-center">
|
||||
{% include "includes/search_form.html" with search_query=search_query %}
|
||||
<div class="container-fluid py-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h1 style="color: var(--kaauh-teal-dark); font-weight: 700;">
|
||||
<i class="fas fa-video me-2"></i> {% trans "Zoom Meetings" %}
|
||||
</h1>
|
||||
<a href="{% url 'create_meeting' %}" class="btn btn-main-action">
|
||||
<i class="fas fa-plus me-1"></i> {% trans "Create Meeting" %}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<a href="{% url 'create_meeting' %}" class="btn-base btn-main-action">
|
||||
<svg class="heroicon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 4v16m8-8H4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
|
||||
</svg>
|
||||
{% trans "Create Meeting" %}
|
||||
</a>
|
||||
<div class="card mb-4 shadow-sm no-hover">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<label for="search" class="form-label small text-muted">{% trans "Search by Topic" %}</label>
|
||||
<div class="input-group input-group-lg mb-3">
|
||||
<form method="get" action="" class="w-100">
|
||||
{% include "includes/search_form.html" with search_query=search_query %}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<form method="GET" class="row g-3 align-items-end" >
|
||||
{% if search_query %}<input type="hidden" name="q" value="{{ search_query }}">{% endif %}
|
||||
|
||||
<div class="col-md-3">
|
||||
<label for="status" class="form-label small text-muted">{% trans "Filter by Status" %}</label>
|
||||
<select name="status" id="status" class="form-select form-select-sm">
|
||||
<option value="">{% trans "All Statuses" %}</option>
|
||||
<option value="waiting" {% if status_filter == 'waiting' %}selected{% endif %}>{% trans "Waiting" %}</option>
|
||||
<option value="started" {% if status_filter == 'started' %}selected{% endif %}>{% trans "Started" %}</option>
|
||||
<option value="ended" {% if status_filter == 'ended' %}selected{% endif %}>{% trans "Ended" %}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-md-5">
|
||||
<div class="filter-buttons">
|
||||
<button type="submit" class="btn btn-main-action btn-lg">
|
||||
<i class="fas fa-filter me-1"></i> {% trans "Apply Filters" %}
|
||||
</button>
|
||||
{% if status_filter or search_query %}
|
||||
<a href="{% url 'meeting_list' %}" class="btn btn-outline-secondary btn-lg">
|
||||
<i class="fas fa-times me-1"></i> {% trans "Clear" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if meetings %}
|
||||
<div id="meetings-list">
|
||||
{# View Switcher #}
|
||||
{% include "includes/_list_view_switcher.html" with list_id="meetings-list" %}
|
||||
|
||||
{# Card View (Default) #}
|
||||
<div class="card-view active">
|
||||
<div class="meetings-grid">
|
||||
{% for meeting in meetings %}
|
||||
<div class="meeting-card">
|
||||
<div class="meeting-topic">{{ meeting.topic }}</div>
|
||||
|
||||
<div class="meeting-detail">
|
||||
<div class="detail-label">{% trans "ID" %}:</div>
|
||||
<div class="detail-value">{{ meeting.meeting_id|default:meeting.id }}</div>
|
||||
</div>
|
||||
|
||||
<div class="meeting-detail">
|
||||
<div class="detail-label">{% trans "Start Time" %}:</div>
|
||||
<div class="detail-value">{{ meeting.start_time|date:"M d, Y H:i" }}</div>
|
||||
</div>
|
||||
|
||||
<div class="meeting-detail">
|
||||
<div class="detail-label">{% trans "Duration" %}:</div>
|
||||
<div class="detail-value">{{ meeting.duration }} minutes</div>
|
||||
</div>
|
||||
|
||||
<div class="meeting-detail">
|
||||
<div class="detail-label">{% trans "Status" %}:</div>
|
||||
<div class="detail-value">
|
||||
<span class="status-badge {% if meeting.status == 'waiting' %}bg-warning{% elif meeting.status == 'started' %}bg-success{% elif meeting.status == 'ended' %}bg-danger{% endif %}">
|
||||
{% if meeting.status == 'waiting' %}
|
||||
{% trans "Waiting" %}
|
||||
{% elif meeting.status == 'started' %}
|
||||
{% trans "Started" %}
|
||||
{% elif meeting.status == 'ended' %}
|
||||
{% trans "Ended" %}
|
||||
{% endif %}
|
||||
{# Card View #}
|
||||
<div class="card-view active row">
|
||||
{% for meeting in meetings %}
|
||||
<div class="col-md-6 col-lg-4 mb-4">
|
||||
<div class="card meeting-card h-100 shadow-sm">
|
||||
<div class="card-body d-flex flex-column">
|
||||
<div class="d-flex justify-content-between align-items-start mb-2">
|
||||
<h5 class="card-title flex-grow-1 me-3">{{ meeting.topic }}</h5>
|
||||
<span class="status-badge bg-{{ meeting.status }}">
|
||||
{{ meeting.status|title }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if meeting.join_url %}
|
||||
<div class="meeting-detail">
|
||||
<div class="detail-label">{% trans "Join URL" %}:</div>
|
||||
<div class="detail-value">
|
||||
<a href="{{ meeting.join_url }}" target="_blank" class="btn-base btn-kaats-outline-primary btn-sm">
|
||||
{% trans "Join Meeting" %}
|
||||
<p class="card-text text-muted small mb-3">
|
||||
<i class="fas fa-hashtag"></i> {% trans "ID" %}: {{ meeting.meeting_id|default:meeting.id }}<br>
|
||||
<i class="fas fa-clock"></i> {% trans "Start" %}: {{ meeting.start_time|date:"M d, Y H:i" }}<br>
|
||||
<i class="fas fa-stopwatch"></i> {% trans "Duration" %}: {{ meeting.duration }} minutes
|
||||
</p>
|
||||
|
||||
<div class="mt-auto pt-2 border-top">
|
||||
<div class="d-flex gap-2">
|
||||
<a href="{% url 'meeting_details' meeting.pk %}" class="btn btn-sm btn-outline-primary">
|
||||
<i class="fas fa-eye"></i> {% trans "View" %}
|
||||
</a>
|
||||
|
||||
{% if meeting.join_url %}
|
||||
<a href="{{ meeting.join_url }}" target="_blank" class="btn btn-sm btn-main-action">
|
||||
<i class="fas fa-link"></i> {% trans "Join" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
<a href="{% url 'update_meeting' meeting.pk %}" class="btn btn-sm btn-outline-secondary">
|
||||
<i class="fas fa-edit"></i>
|
||||
</a>
|
||||
<button type="button" class="btn btn-outline-danger btn-sm" title="{% trans 'Delete' %}"
|
||||
data-bs-toggle="modal" data-bs-target="#deleteModal"
|
||||
data-delete-url="{% url 'delete_meeting' meeting.pk %}"
|
||||
data-item-name="{{ meeting.topic }}">
|
||||
<i class="fas fa-trash-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="actions">
|
||||
<a href="{% url 'meeting_details' meeting.pk %}" class="btn-base btn-kaats-outline-primary btn-sm" title="{% trans 'View' %}">
|
||||
<svg class="heroicon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
|
||||
<path d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0 8.268-2.943-9.542-7z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
|
||||
</svg>
|
||||
</a>
|
||||
<a href="{% url 'update_meeting' meeting.pk %}" class="btn-base btn-kaats-outline-secondary btn-sm" title="{% trans 'Update' %}">
|
||||
<svg class="heroicon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
|
||||
</svg>
|
||||
</a>
|
||||
<button type="button" class="btn-base btn-kaats-outline-danger btn-sm" title="{% trans 'Delete' %}"
|
||||
data-bs-toggle="deleteModal"
|
||||
data-delete-url="{% url 'delete_meeting' meeting.pk %}"
|
||||
data-item-name="{{ meeting.topic }}">
|
||||
<svg class="heroicon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{# Table View #}
|
||||
@ -330,34 +254,33 @@
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">{% trans "Topic" %}</th>
|
||||
<th scope="col">{% trans "ID" %}</th>
|
||||
<th scope="col">{% trans "Start Time" %}</th>
|
||||
<th scope="col">{% trans "Duration" %}</th>
|
||||
<th scope="col">{% trans "Status" %}</th>
|
||||
<th scope="col" class="text-end">{% trans "Actions" %}</th>
|
||||
<th scope="col" style="width: 30%;">{% trans "Topic" %}</th>
|
||||
<th scope="col" style="width: 15%;">{% trans "ID" %}</th>
|
||||
<th scope="col" style="width: 20%;">{% trans "Start Time" %}</th>
|
||||
<th scope="col" style="width: 10%;">{% trans "Duration" %}</th>
|
||||
<th scope="col" style="width: 15%;">{% trans "Status" %}</th>
|
||||
<th scope="col" style="width: 10%;" class="text-end">{% trans "Actions" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for meeting in meetings %}
|
||||
<tr>
|
||||
<td><strong>{{ meeting.topic }}</strong></td>
|
||||
<td><strong class="text-primary">{{ meeting.topic }}</strong></td>
|
||||
<td>{{ meeting.meeting_id|default:meeting.id }}</td>
|
||||
<td>{{ meeting.start_time|date:"M d, Y H:i" }}</td>
|
||||
<td>{{ meeting.duration }} minutes</td>
|
||||
<td>{{ meeting.duration }} min</td>
|
||||
<td>
|
||||
<span class="status-badge {% if meeting.status == 'waiting' %}bg-warning{% elif meeting.status == 'started' %}bg-success{% elif meeting.status == 'ended' %}bg-danger{% endif %}">
|
||||
{% if meeting.status == 'waiting' %}
|
||||
{% trans "Waiting" %}
|
||||
{% elif meeting.status == 'started' %}
|
||||
{% trans "Started" %}
|
||||
{% elif meeting.status == 'ended' %}
|
||||
{% trans "Ended" %}
|
||||
{% endif %}
|
||||
<span class="status-badge bg-{{ meeting.status }}">
|
||||
{{ meeting.status|title }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<div class="btn-group btn-group-sm" role="group">
|
||||
{% if meeting.join_url %}
|
||||
<a href="{{ meeting.join_url }}" target="_blank" class="btn btn-main-action" title="{% trans 'Join' %}">
|
||||
<i class="fas fa-sign-in-alt"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
<a href="{% url 'meeting_details' meeting.pk %}" class="btn btn-outline-primary" title="{% trans 'View' %}">
|
||||
<i class="fas fa-eye"></i>
|
||||
</a>
|
||||
@ -365,10 +288,10 @@
|
||||
<i class="fas fa-edit"></i>
|
||||
</a>
|
||||
<button type="button" class="btn btn-outline-danger" title="{% trans 'Delete' %}"
|
||||
data-bs-toggle="deleteModal"
|
||||
data-bs-toggle="modal" data-bs-target="#deleteModal"
|
||||
data-delete-url="{% url 'delete_meeting' meeting.pk %}"
|
||||
data-item-name="{{ meeting.topic }}">
|
||||
<i class="fas fa-trash"></i>
|
||||
<i class="fas fa-trash-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
@ -380,52 +303,45 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Pagination (Standardized) #}
|
||||
{% if is_paginated %}
|
||||
<nav aria-label="Page navigation" class="mt-4">
|
||||
<ul class="pagination justify-content-center">
|
||||
{% if page_obj.has_previous %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ page_obj.previous_page_number }}&search={{ search_query }}" aria-label="Previous">
|
||||
<span aria-hidden="true">«</span>
|
||||
</a>
|
||||
<a class="page-link" href="?page=1{% if status_filter %}&status={{ status_filter }}{% endif %}{% if search_query %}&q={{ search_query }}{% endif %}">First</a>
|
||||
</li>
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ page_obj.previous_page_number }}{% if status_filter %}&status={{ status_filter }}{% endif %}{% if search_query %}&q={{ search_query }}{% endif %}">Previous</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{% for num in page_obj.paginator.page_range %}
|
||||
{% if page_obj.number == num %}
|
||||
<li class="page-item active"><span class="page-link">{{ num }}</span></li>
|
||||
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ num }}&search={{ search_query }}">{{ num }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<li class="page-item active">
|
||||
<span class="page-link">{{ page_obj.number }} of {{ page_obj.paginator.num_pages }}</span>
|
||||
</li>
|
||||
|
||||
{% if page_obj.has_next %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ page_obj.next_page_number }}&search={{ search_query }}" aria-label="Next">
|
||||
<span aria-hidden="true">»</span>
|
||||
</a>
|
||||
<a class="page-link" href="?page={{ page_obj.next_page_number }}{% if status_filter %}&status={{ status_filter }}{% endif %}{% if search_query %}&q={{ search_query }}{% endif %}">Next</a>
|
||||
</li>
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ page_obj.paginator.num_pages }}{% if status_filter %}&status={{ status_filter }}{% endif %}{% if search_query %}&q={{ search_query }}{% endif %}">Last</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<div class="text-center py-5">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="text-muted mb-3" style="width: 80px;">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9.879 7.519c1.171-1.025 3.071-1.025 4.242 0 1.172 1.025 1.172 2.687 0 3.712-.203.179-.43.326-.67.442-.745.361-1.45.999-1.45 1.827v.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9 5.25h.008v.008H12v-.008Z" />
|
||||
</svg>
|
||||
<p class="text-muted">{% trans "No meetings found." %}</p>
|
||||
{% if user.is_staff %}
|
||||
<a href="{% url 'create_meeting' %}" class="btn-base btn-main-action mt-3">
|
||||
<svg class="heroicon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 4v16m8-8H4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
|
||||
</svg>
|
||||
{% trans "Create Your First Meeting" %}
|
||||
<div class="text-center py-5 card shadow-sm">
|
||||
<div class="card-body">
|
||||
<i class="fas fa-video fa-3x mb-3" style="color: var(--kaauh-teal-dark);"></i>
|
||||
<h3>{% trans "No Zoom meetings found" %}</h3>
|
||||
<p class="text-muted">{% trans "Create your first meeting or adjust your filters." %}</p>
|
||||
<a href="{% url 'create_meeting' %}" class="btn btn-main-action mt-3">
|
||||
<i class="fas fa-plus me-1"></i> {% trans "Create Your First Meeting" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
@ -115,8 +115,8 @@
|
||||
color: var(--kaauh-teal);
|
||||
}
|
||||
.main-tabs .nav-link.active {
|
||||
color: var(--kaauh-teal-dark);
|
||||
background-color: white;
|
||||
color: var(--kaauh-teal-dark) !important;
|
||||
background-color: white !important;
|
||||
border-bottom: 3px solid var(--kaauh-teal);
|
||||
font-weight: 600;
|
||||
}
|
||||
@ -141,8 +141,8 @@
|
||||
border-right: none;
|
||||
}
|
||||
.right-column-card .nav-link.active {
|
||||
background-color: white;
|
||||
color: var(--kaauh-teal-dark);
|
||||
background-color: white !important;
|
||||
color: var(--kaauh-teal-dark) !important;
|
||||
border-bottom: 3px solid var(--kaauh-teal);
|
||||
border-right-color: transparent;
|
||||
margin-bottom: -1px;
|
||||
|
||||
@ -5,15 +5,16 @@
|
||||
|
||||
{% block customCSS %}
|
||||
<style>
|
||||
/* UI Variables for the KAAT-S Theme */
|
||||
/* UI Variables for the KAAT-S Theme (Consistent with Reference) */
|
||||
:root {
|
||||
--kaauh-teal: #00636e;
|
||||
--kaauh-teal-dark: #004a53;
|
||||
--kaauh-border: #eaeff3;
|
||||
--kaauh-primary-text: #343a40;
|
||||
--kaauh-gray-light: #f8f9fa; /* Added for hover/background consistency */
|
||||
}
|
||||
|
||||
/* Enhanced Card Styling */
|
||||
/* Enhanced Card Styling (Consistent) */
|
||||
.card {
|
||||
border: 1px solid var(--kaauh-border);
|
||||
border-radius: 0.75rem;
|
||||
@ -21,19 +22,15 @@
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
background-color: white;
|
||||
}
|
||||
.card:hover {
|
||||
/* Remove hover effect from the main list card to avoid visual noise */
|
||||
.card:not(.no-hover):hover { /* Use no-hover class for main structure cards */
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 16px rgba(0,0,0,0.1);
|
||||
}
|
||||
.card.no-hover:hover {
|
||||
transform: none;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
|
||||
}
|
||||
|
||||
.card-header {
|
||||
font-weight: 600;
|
||||
padding: 1.25rem;
|
||||
border-bottom: 1px solid var(--kaauh-border);
|
||||
background-color: #f8f9fa; /* Light header background */
|
||||
}
|
||||
|
||||
/* Main Action Button Style (Teal Theme) */
|
||||
.btn-main-action {
|
||||
background-color: var(--kaauh-teal);
|
||||
@ -53,50 +50,63 @@
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
|
||||
}
|
||||
|
||||
/* Secondary Action Buttons (used in table) */
|
||||
.btn-group .btn-outline-primary {
|
||||
color: var(--kaauh-teal);
|
||||
border-color: var(--kaauh-border);
|
||||
background-color: white;
|
||||
}
|
||||
.btn-group .btn-outline-primary:hover {
|
||||
background-color: var(--kaauh-teal);
|
||||
color: white;
|
||||
/* Secondary Button Style (For Edit/Outline - Consistent) */
|
||||
.btn-outline-secondary {
|
||||
color: var(--kaauh-teal-dark);
|
||||
border-color: var(--kaauh-teal);
|
||||
}
|
||||
|
||||
/* Table Styling */
|
||||
.table thead th {
|
||||
.btn-outline-secondary:hover {
|
||||
background-color: var(--kaauh-teal-dark);
|
||||
color: white;
|
||||
border-color: var(--kaauh-teal-dark);
|
||||
}
|
||||
|
||||
/* Card Specifics (Adapted from Job Card to Candidate Card) */
|
||||
.candidate-card .card-title {
|
||||
color: var(--kaauh-teal-dark);
|
||||
font-weight: 600;
|
||||
border-bottom: 2px solid var(--kaauh-teal); /* Highlight bottom border */
|
||||
vertical-align: middle;
|
||||
padding: 0.75rem 1rem;
|
||||
font-size: 0.95rem;
|
||||
font-size: 1.15rem;
|
||||
}
|
||||
.candidate-card .card-text i {
|
||||
color: var(--kaauh-teal);
|
||||
width: 1.25rem;
|
||||
}
|
||||
|
||||
.table tbody tr:hover {
|
||||
background-color: #f3f9f9; /* Light teal hover for rows */
|
||||
}
|
||||
|
||||
.table tbody td {
|
||||
vertical-align: middle;
|
||||
padding: 0.75rem 1rem;
|
||||
}
|
||||
|
||||
/* Badge Styling */
|
||||
/* Table & Card Badge Styling (Unified) */
|
||||
.badge {
|
||||
font-weight: 600;
|
||||
padding: 0.4em 0.7em;
|
||||
border-radius: 0.3rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
/* Status Badge Mapping */
|
||||
.table .bg-primary { background-color: var(--kaauh-teal) !important; color: white !important;} /* Job Title Badge */
|
||||
.table .bg-success { background-color: #28a745 !important; } /* Applied: Yes */
|
||||
.table .bg-warning { background-color: #ffc107 !important; } /* Applied: No */
|
||||
/* Status Badge Mapping (Using standard Bootstrap names where possible) */
|
||||
.bg-primary { background-color: var(--kaauh-teal) !important; color: white !important;} /* Main job/stage badge */
|
||||
.bg-success { background-color: #28a745 !important; color: white !important;}
|
||||
.bg-warning { background-color: #ffc107 !important; color: #343a40 !important;}
|
||||
|
||||
/* Pagination Link Styling */
|
||||
/* Table Styling (Consistent with Reference) */
|
||||
.table-view .table thead th {
|
||||
background-color: var(--kaauh-teal-dark); /* Dark header background */
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
border-color: var(--kaauh-border);
|
||||
text-transform: uppercase;
|
||||
font-size: 0.8rem;
|
||||
letter-spacing: 0.5px;
|
||||
padding: 1rem;
|
||||
}
|
||||
.table-view .table tbody td {
|
||||
vertical-align: middle;
|
||||
padding: 1rem;
|
||||
border-color: var(--kaauh-border);
|
||||
}
|
||||
.table-view .table tbody tr:hover {
|
||||
background-color: var(--kaauh-gray-light);
|
||||
}
|
||||
|
||||
/* Pagination Link Styling (Consistent) */
|
||||
.pagination .page-item .page-link {
|
||||
color: var(--kaauh-teal-dark);
|
||||
border-color: var(--kaauh-border);
|
||||
@ -109,189 +119,213 @@
|
||||
.pagination .page-item:hover .page-link:not(.active) {
|
||||
background-color: #e9ecef;
|
||||
}
|
||||
|
||||
/* Icon Sizing in Buttons */
|
||||
.btn-group .btn-sm svg {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
|
||||
/* Filter & Search Layout Adjustments */
|
||||
.filter-buttons {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid py-4">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<h1 class="h3 mb-0" style="color: var(--kaauh-teal-dark); font-weight: 700;">
|
||||
<i class="fas fa-users me-2"></i>
|
||||
{% trans "Candidate Profiles" %}
|
||||
</h1>
|
||||
<div class="d-flex gap-3 align-items-center">
|
||||
{# The search form structure should be updated to align with the job_list style if possible #}
|
||||
{% include "includes/search_form.html" with search_query=search_query %}
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h1 style="color: var(--kaauh-teal-dark); font-weight: 700;">
|
||||
<i class="fas fa-users me-2"></i> {% trans "Candidate Profiles" %}
|
||||
</h1>
|
||||
{% if user.is_staff %}
|
||||
<a href="{% url 'candidate_create' %}" class="btn btn-main-action">
|
||||
<i class="fas fa-plus me-1"></i> {% trans "Add New Candidate" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if user.is_staff %}
|
||||
<a href="{% url 'candidate_create' %}" class="btn btn-main-action">
|
||||
<i class="fas fa-plus"></i>
|
||||
{% trans "Add New Candidate" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
<div class="card mb-4 shadow-sm no-hover">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<label for="search" class="form-label small text-muted">{% trans "Search by Name or Email" %}</label>
|
||||
<div class="input-group input-group-lg mb-3">
|
||||
<form method="get" action="" class="w-100">
|
||||
{% include 'includes/search_form.html' %}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
{% url 'candidate_list' as candidate_list_url %}
|
||||
|
||||
<form method="GET" class="row g-3 align-items-end" >
|
||||
{% if search_query %}<input type="hidden" name="q" value="{{ search_query }}">{% endif %}
|
||||
|
||||
<div class="col-md-3">
|
||||
<label for="job_filter" class="form-label small text-muted">{% trans "Filter by Job" %}</label>
|
||||
<select name="job" id="job_filter" class="form-select form-select-sm">
|
||||
<option value="">{% trans "All Jobs" %}</option>
|
||||
{% for job in available_jobs %} {# Assuming you pass a context variable 'available_jobs' #}
|
||||
<option value="{{ job.slug }}" {% if job_filter == job.slug %}selected{% endif %}>{{ job.title }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-md-5">
|
||||
<div class="filter-buttons">
|
||||
<button type="submit" class="btn btn-main-action btn-lg">
|
||||
<i class="fas fa-filter me-1"></i> {% trans "Apply Filters" %}
|
||||
</button>
|
||||
{% if job_filter or search_query %}
|
||||
<a href="{% url 'candidate_list' %}" class="btn btn-outline-secondary btn-lg">
|
||||
<i class="fas fa-times me-1"></i> {% trans "Clear" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if candidates %}
|
||||
<div id="candidate-list">
|
||||
{# View Switcher - list_id must match the container ID #}
|
||||
{% include "includes/_list_view_switcher.html" with list_id="candidate-list" %}
|
||||
|
||||
{% if candidates %}
|
||||
<div id="candidate-list">
|
||||
{# View Switcher #}
|
||||
{% include "includes/_list_view_switcher.html" with list_id="candidate-list" %}
|
||||
|
||||
{# Table View (Default) #}
|
||||
<div class="table-view active">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover mb-0">
|
||||
<thead>
|
||||
{# Table View (Default) #}
|
||||
<div class="table-view active">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" style="width: 20%;">{% trans "Name" %}</th>
|
||||
<th scope="col" style="width: 20%;">{% trans "Email" %}</th>
|
||||
<th scope="col" style="width: 15%;">{% trans "Phone" %}</th>
|
||||
<th scope="col" style="width: 15%;">{% trans "Job" %}</th>
|
||||
<th scope="col" style="width: 10%;">{% trans "Stage" %}</th>
|
||||
<th scope="col" style="width: 10%;">{% trans "Created" %}</th>
|
||||
<th scope="col" style="width: 10%;" class="text-end">{% trans "Actions" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for candidate in candidates %}
|
||||
<tr>
|
||||
<th scope="col" style="width: 20%;">{% trans "Name" %}</th>
|
||||
<th scope="col" style="width: 20%;">{% trans "Email" %}</th>
|
||||
<th scope="col" style="width: 15%;">{% trans "Phone" %}</th>
|
||||
<th scope="col" style="width: 15%;">{% trans "Job" %}</th>
|
||||
<th scope="col" style="width: 10%;">{% trans "Stage" %}</th>
|
||||
<th scope="col" style="width: 10%;">{% trans "Created" %}</th>
|
||||
<th scope="col" style="width: 10%;" class="text-center">{% trans "Actions" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for candidate in candidates %}
|
||||
<tr>
|
||||
<td><strong>{{ candidate.name }}</strong></td>
|
||||
<td>{{ candidate.email }}</td>
|
||||
<td>{{ candidate.phone }}</td>
|
||||
<td> <span class="badge bg-primary">{{ candidate.job.title }}</span></td>
|
||||
<td>
|
||||
<span class="badge bg-primary">
|
||||
{{ candidate.stage }}
|
||||
</span>
|
||||
</td>
|
||||
<td>{{ candidate.created_at|date:"M d, Y" }}</td>
|
||||
<td class="text-center">
|
||||
<div class="btn-group btn-group-sm" role="group">
|
||||
<a href="{% url 'candidate_detail' candidate.slug %}" class="btn btn-outline-primary" title="{% trans 'View' %}">
|
||||
<i class="fas fa-eye"></i>
|
||||
</a>
|
||||
{% if user.is_staff %}
|
||||
<a href="{% url 'candidate_update' candidate.slug %}" class="btn btn-outline-primary" title="{% trans 'Edit' %}">
|
||||
<i class="fas fa-edit"></i>
|
||||
</a>
|
||||
<button type="button" class="btn btn-outline-danger" title="{% trans 'Delete' %}"
|
||||
data-bs-toggle="deleteModal"
|
||||
data-delete-url="{% url 'candidate_delete' candidate.slug %}"
|
||||
data-item-name="{{ candidate.name }}">
|
||||
<i class="fas fa-trash-alt"></i>
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Card View #}
|
||||
<div class="card-view">
|
||||
<div class="row g-4">
|
||||
{% for candidate in candidates %}
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-header">
|
||||
<h5 class="h5 mb-1">{{ candidate.name }}</h5>
|
||||
<small class="text-white-50">{{ candidate.email }}</small>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="card-text">
|
||||
<strong>{% trans "Phone" %}:</strong> {{ candidate.phone|default:"N/A" }}<br>
|
||||
<strong>{% trans "Job" %}:</strong> <span class="badge bg-primary">{{ candidate.job.title }}</span><br>
|
||||
<strong>{% trans "Stage" %}:</strong> <span class="badge bg-primary">{{ candidate.stage }}</span><br>
|
||||
<strong>{% trans "Created" %}:</strong> {{ candidate.created_at|date:"M d, Y" }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<div class="d-flex gap-2">
|
||||
<a href="{% url 'candidate_detail' candidate.slug %}" class="btn btn-sm btn-outline-primary w-100">
|
||||
<i class="fas fa-eye"></i> {% trans "View" %}
|
||||
<td class="fw-medium">{{ candidate.name }}</td>
|
||||
<td>{{ candidate.email }}</td>
|
||||
<td>{{ candidate.phone }}</td>
|
||||
<td> <span class="badge bg-primary">{{ candidate.job.title }}</span></td>
|
||||
<td>
|
||||
<span class="badge bg-primary">
|
||||
{{ candidate.stage }}
|
||||
</span>
|
||||
</td>
|
||||
<td>{{ candidate.created_at|date:"M d, Y" }}</td>
|
||||
<td class="text-end">
|
||||
<div class="btn-group btn-group-sm" role="group">
|
||||
<a href="{% url 'candidate_detail' candidate.slug %}" class="btn btn-outline-primary" title="{% trans 'View' %}">
|
||||
<i class="fas fa-eye"></i>
|
||||
</a>
|
||||
{% if user.is_staff %}
|
||||
<div class="btn-group w-100" role="group">
|
||||
<a href="{% url 'candidate_update' candidate.slug %}" class="btn btn-sm btn-outline-secondary" title="{% trans 'Edit' %}">
|
||||
<i class="fas fa-edit"></i>
|
||||
</a>
|
||||
<button type="button" class="btn btn-outline-danger btn-sm" title="{% trans 'Delete' %}"
|
||||
data-bs-toggle="deleteModal"
|
||||
data-delete-url="{% url 'candidate_delete' candidate.slug %}"
|
||||
data-item-name="{{ candidate.name }}">
|
||||
<i class="fas fa-trash-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
<a href="{% url 'candidate_update' candidate.slug %}" class="btn btn-outline-secondary" title="{% trans 'Edit' %}">
|
||||
<i class="fas fa-edit"></i>
|
||||
</a>
|
||||
<button type="button" class="btn btn-outline-danger" title="{% trans 'Delete' %}"
|
||||
data-bs-toggle="modal" data-bs-target="#deleteModal" {# Updated to standard Bootstrap usage #}
|
||||
data-delete-url="{% url 'candidate_delete' candidate.slug %}"
|
||||
data-item-name="{{ candidate.name }}">
|
||||
<i class="fas fa-trash-alt"></i>
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Card View #}
|
||||
<div class="card-view row"> {# Added 'row' class for grid structure #}
|
||||
{% for candidate in candidates %}
|
||||
<div class="col-md-6 col-lg-4 mb-4"> {# Column wrapper for grid #}
|
||||
<div class="card candidate-card h-100 shadow-sm">
|
||||
<div class="card-body d-flex flex-column">
|
||||
<div class="d-flex justify-content-between align-items-start mb-2">
|
||||
<h5 class="card-title flex-grow-1 me-3">{{ candidate.name }}</h5>
|
||||
<span class="badge bg-primary">{{ candidate.stage }}</span>
|
||||
</div>
|
||||
|
||||
<p class="card-text text-muted small">
|
||||
<i class="fas fa-envelope"></i> {{ candidate.email }}<br>
|
||||
<i class="fas fa-phone-alt"></i> {{ candidate.phone|default:"N/A" }}<br>
|
||||
<i class="fas fa-briefcase"></i> <span class="badge bg-primary">{{ candidate.job.title }}</span>
|
||||
</p>
|
||||
|
||||
<div class="mt-auto pt-2 border-top">
|
||||
<div class="d-flex gap-2">
|
||||
<a href="{% url 'candidate_detail' candidate.slug %}" class="btn btn-sm btn-main-action">
|
||||
<i class="fas fa-eye"></i> {% trans "View" %}
|
||||
</a>
|
||||
{% if user.is_staff %}
|
||||
<a href="{% url 'candidate_update' candidate.slug %}" class="btn btn-sm btn-outline-secondary">
|
||||
<i class="fas fa-edit"></i> {% trans "Edit" %}
|
||||
</a>
|
||||
<button type="button" class="btn btn-outline-danger btn-sm" title="{% trans 'Delete' %}"
|
||||
data-bs-toggle="modal" data-bs-target="#deleteModal"
|
||||
data-delete-url="{% url 'candidate_delete' candidate.slug %}"
|
||||
data-item-name="{{ candidate.name }}">
|
||||
<i class="fas fa-trash-alt"></i>
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if is_paginated %}
|
||||
<div class="card-footer bg-white border-top">
|
||||
<nav aria-label="Page navigation">
|
||||
<ul class="pagination justify-content-center mb-0">
|
||||
{% if page_obj.has_previous %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ page_obj.previous_page_number }}{% if search_query %}&q={{ search_query }}{% endif %}" aria-label="Previous">
|
||||
<span aria-hidden="true">«</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{# Pagination (Standardized to Reference) #}
|
||||
{% if is_paginated %}
|
||||
<nav aria-label="Page navigation" class="mt-4">
|
||||
<ul class="pagination justify-content-center">
|
||||
{% if page_obj.has_previous %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page=1{% if search_query %}&q={{ search_query }}{% endif %}{% if job_filter %}&job={{ job_filter }}{% endif %}">First</a>
|
||||
</li>
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ page_obj.previous_page_number }}{% if search_query %}&q={{ search_query }}{% endif %}{% if job_filter %}&job={{ job_filter }}{% endif %}">Previous</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{# Simplified pagination logic for theme consistency #}
|
||||
{% for num in page_obj.paginator.page_range %}
|
||||
{% if page_obj.number == num %}
|
||||
<li class="page-item active"><span class="page-link">{{ num }}</span></li>
|
||||
{% elif num > page_obj.number|add:'-2' and num < page_obj.number|add:'2' %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ num }}{% if search_query %}&q={{ search_query }}{% endif %}">{{ num }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<li class="page-item active">
|
||||
<span class="page-link">{{ page_obj.number }} of {{ page_obj.paginator.num_pages }}</span>
|
||||
</li>
|
||||
|
||||
{% if page_obj.has_next %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ page_obj.next_page_number }}{% if search_query %}&q={{ search_query }}{% endif %}" aria-label="Next">
|
||||
<span aria-hidden="true">»</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<div class="text-center py-5">
|
||||
{% if page_obj.has_next %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ page_obj.next_page_number }}{% if search_query %}&q={{ search_query }}{% endif %}{% if job_filter %}&job={{ job_filter }}{% endif %}">Next</a>
|
||||
</li>
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ page_obj.paginator.num_pages }}{% if search_query %}&q={{ search_query }}{% endif %}{% if job_filter %}&job={{ job_filter }}{% endif %}">Last</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<div class="text-center py-5 card shadow-sm">
|
||||
<div class="card-body">
|
||||
<i class="fas fa-users fa-3x mb-3" style="color: var(--kaauh-teal-dark);"></i>
|
||||
<h4 class="text-muted">{% trans "No candidates found." %}</h4>
|
||||
<p class="text-muted">{% trans "Start by adding a new profile or adjusting your search filters." %}</p>
|
||||
<h3>{% trans "No candidate profiles found" %}</h3>
|
||||
<p class="text-muted">{% trans "Create your first candidate profile or adjust your filters." %}</p>
|
||||
{% if user.is_staff %}
|
||||
<a href="{% url 'candidate_create' %}" class="btn btn-main-action mt-3">
|
||||
<i class="fas fa-plus me-1"></i>
|
||||
{% trans "Add Your First Candidate" %}
|
||||
<i class="fas fa-plus me-1"></i> {% trans "Add Candidate" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
@ -5,48 +5,53 @@
|
||||
|
||||
{% block customCSS %}
|
||||
<style>
|
||||
/* ================================================= */
|
||||
/* THEME VARIABLES AND GLOBAL STYLES (FROM JOB DETAIL) */
|
||||
/* ================================================= */
|
||||
/* UI Variables for the KAAT-S Theme (Consistent with Reference) */
|
||||
:root {
|
||||
--kaauh-teal: #00636e;
|
||||
--kaauh-teal-dark: #004a53;
|
||||
--kaauh-border: #eaeff3;
|
||||
--kaauh-primary-text: #343a40;
|
||||
--kaauh-gray-light: #f8f9fa; /* Added for hover/background consistency */
|
||||
}
|
||||
|
||||
/* Primary Color Overrides */
|
||||
.text-primary { color: var(--kaauh-teal) !important; }
|
||||
/* Enhanced Card Styling (Consistent) */
|
||||
.card {
|
||||
border: 1px solid var(--kaauh-border);
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
background-color: white;
|
||||
}
|
||||
/* Standard card hover effect for list items */
|
||||
.card:not(.no-hover):hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 16px rgba(0,0,0,0.1);
|
||||
}
|
||||
.card.no-hover:hover {
|
||||
transform: none;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
|
||||
}
|
||||
|
||||
/* Main Action Button Style (Applied to .btn-primary) */
|
||||
.btn-main-action, .btn-primary {
|
||||
/* Main Action Button Style (Teal Theme) */
|
||||
.btn-main-action {
|
||||
background-color: var(--kaauh-teal);
|
||||
border-color: var(--kaauh-teal);
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
padding: 0.6rem 1.2rem;
|
||||
transition: all 0.2s ease;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
text-decoration: none; /* Ensure links look like buttons */
|
||||
gap: 0.4rem;
|
||||
padding: 0.5rem 1rem;
|
||||
}
|
||||
.btn-main-action:hover, .btn-primary:hover {
|
||||
|
||||
.btn-main-action:hover {
|
||||
background-color: var(--kaauh-teal-dark);
|
||||
border-color: var(--kaauh-teal-dark);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
|
||||
}
|
||||
|
||||
/* Outlined Button Styles for Table Actions */
|
||||
.btn-outline-primary {
|
||||
color: var(--kaauh-teal);
|
||||
border-color: var(--kaauh-teal);
|
||||
}
|
||||
.btn-outline-primary:hover {
|
||||
background-color: var(--kaauh-teal);
|
||||
color: white;
|
||||
}
|
||||
/* Secondary Button Style (For Edit/Outline - Consistent) */
|
||||
.btn-outline-secondary {
|
||||
color: var(--kaauh-teal-dark);
|
||||
border-color: var(--kaauh-teal);
|
||||
@ -56,54 +61,44 @@
|
||||
color: white;
|
||||
border-color: var(--kaauh-teal-dark);
|
||||
}
|
||||
/* Danger button remains standard for deletion */
|
||||
|
||||
/* Card enhancements */
|
||||
.card {
|
||||
border: 1px solid var(--kaauh-border);
|
||||
border-radius: 0.75rem;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
|
||||
background-color: white;
|
||||
.btn-outline-primary {
|
||||
color: var(--kaauh-teal);
|
||||
border-color: var(--kaauh-teal);
|
||||
}
|
||||
|
||||
/* Colored Header Card */
|
||||
.list-header-card {
|
||||
background: linear-gradient(135deg, var(--kaauh-teal), #004d57);
|
||||
.btn-outline-primary:hover {
|
||||
background-color: var(--kaauh-teal);
|
||||
color: white;
|
||||
border-radius: 0.75rem 0.75rem 0 0;
|
||||
padding: 1.5rem;
|
||||
box-shadow: 0 4px 10px rgba(0,0,0,0.15);
|
||||
}
|
||||
.list-header-card h1 {
|
||||
font-weight: 700;
|
||||
margin: 0;
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
.heroicon {
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
vertical-align: text-bottom;
|
||||
stroke: currentColor;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
/* Table Styling */
|
||||
.table thead th {
|
||||
background-color: #f8f9fa;
|
||||
color: var(--kaauh-primary-text);
|
||||
/* Training Card Specifics */
|
||||
.training-card .card-title {
|
||||
color: var(--kaauh-teal-dark);
|
||||
font-weight: 600;
|
||||
border-bottom: 2px solid var(--kaauh-border);
|
||||
}
|
||||
.table tbody tr:hover {
|
||||
background-color: #f0f8ff; /* Light hover color */
|
||||
}
|
||||
.btn-group .btn-sm {
|
||||
padding: 0.35rem 0.6rem;
|
||||
font-size: 1.15rem;
|
||||
}
|
||||
|
||||
/* Pagination Styling */
|
||||
.pagination .page-link {
|
||||
/* Table Styling (Consistent with Reference) */
|
||||
.table-view .table thead th {
|
||||
background-color: var(--kaauh-teal-dark); /* Dark header background */
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
border-color: var(--kaauh-border);
|
||||
text-transform: uppercase;
|
||||
font-size: 0.8rem;
|
||||
letter-spacing: 0.5px;
|
||||
padding: 1rem;
|
||||
}
|
||||
.table-view .table tbody td {
|
||||
vertical-align: middle;
|
||||
padding: 1rem;
|
||||
border-color: var(--kaauh-border);
|
||||
}
|
||||
.table-view .table tbody tr:hover {
|
||||
background-color: var(--kaauh-gray-light);
|
||||
}
|
||||
|
||||
/* Pagination Link Styling (Consistent) */
|
||||
.pagination .page-item .page-link {
|
||||
color: var(--kaauh-teal-dark);
|
||||
border-color: var(--kaauh-border);
|
||||
}
|
||||
@ -112,173 +107,179 @@
|
||||
border-color: var(--kaauh-teal);
|
||||
color: white;
|
||||
}
|
||||
.pagination .page-item:hover .page-link:not(.active) {
|
||||
background-color: #e9ecef;
|
||||
}
|
||||
|
||||
/* Filter & Search Layout Adjustments */
|
||||
.filter-buttons {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
/* Override for the primary text color being used for card-titles in table */
|
||||
.text-primary { color: var(--kaauh-teal) !important; }
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid py-4">
|
||||
<div class="card shadow-sm">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h1 style="color: var(--kaauh-teal-dark); font-weight: 700;">
|
||||
<i class="fas fa-graduation-cap me-2"></i> {% trans "Training Materials" %}
|
||||
</h1>
|
||||
{% if user.is_authenticated %}
|
||||
<a href="{% url 'training_create' %}" class="btn btn-main-action">
|
||||
<i class="fas fa-plus me-1"></i> {% trans "Add New Material" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="list-header-card">
|
||||
<div class="d-flex justify-content-between align-items-center flex-wrap">
|
||||
<h1 class="h3 mb-0">
|
||||
<i class="fas fa-graduation-cap me-2"></i>
|
||||
{% trans "Training Materials" %}
|
||||
</h1>
|
||||
<div class="d-flex gap-3 align-items-center mt-2 mt-md-0">
|
||||
|
||||
<div class="order-3 order-md-1">
|
||||
{% include "includes/search_form.html" with search_query=search_query %}
|
||||
<div class="card mb-4 shadow-sm no-hover">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<label for="search" class="form-label small text-muted">{% trans "Search by Title or Creator" %}</label>
|
||||
<div class="input-group input-group-lg mb-3">
|
||||
<form method="get" action="" class="w-100">
|
||||
{% include "includes/search_form.html" with search_query=search_query %}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 d-flex align-items-end">
|
||||
{# Additional Filters can go here if needed #}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if materials %}
|
||||
<div id="training-materials-list">
|
||||
{# View Switcher - list_id must match the container ID #}
|
||||
{% include "includes/_list_view_switcher.html" with list_id="training-materials-list" %}
|
||||
|
||||
{% if user.is_authenticated %}
|
||||
<a href="{% url 'training_create' %}" class="btn btn-main-action btn-sm order-1 order-md-2" title="{% trans 'Add New Material' %}">
|
||||
<i class="fas fa-plus"></i>
|
||||
<span class="d-none d-sm-inline">{% trans "Add New Material" %}</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
{# Card View (Default) - Must have 'row' class for grid layout #}
|
||||
<div class="card-view active row">
|
||||
{% for material in materials %}
|
||||
<div class="col-md-6 col-lg-4 mb-4">
|
||||
<div class="card training-card h-100 shadow-sm">
|
||||
<div class="card-body d-flex flex-column">
|
||||
<div class="d-flex justify-content-between align-items-start mb-2">
|
||||
<h5 class="card-title flex-grow-1 me-3">{{ material.title }}</h5>
|
||||
</div>
|
||||
|
||||
<p class="card-text text-muted small">
|
||||
<i class="fas fa-user-edit"></i> {% trans "Created By" %}: {{ material.created_by.username|default:"Anonymous" }}<br>
|
||||
<i class="fas fa-calendar-alt"></i> {% trans "Created On" %}: {{ material.created_at|date:"M d, Y" }}
|
||||
</p>
|
||||
|
||||
<div class="mt-auto pt-2 border-top">
|
||||
<div class="d-flex gap-2">
|
||||
<a href="{% url 'training_detail' material.pk %}" class="btn btn-sm btn-main-action">
|
||||
<i class="fas fa-eye"></i> {% trans "View" %}
|
||||
</a>
|
||||
{% if user.is_authenticated and material.created_by == user %}
|
||||
<a href="{% url 'training_update' material.pk %}" class="btn btn-sm btn-outline-secondary">
|
||||
<i class="fas fa-edit"></i> {% trans "Edit" %}
|
||||
</a>
|
||||
<button type="button" class="btn btn-outline-danger btn-sm" title="{% trans 'Delete' %}"
|
||||
data-bs-toggle="modal" data-bs-target="#deleteModal" {# Assuming standard Bootstrap modal trigger #}
|
||||
data-delete-url="{% url 'training_delete' material.pk %}"
|
||||
data-item-name="{{ material.title }}">
|
||||
<i class="fas fa-trash-alt"></i>
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{# Table View #}
|
||||
<div class="table-view">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover align-middle mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" style="width: 40%;">{% trans "Title" %}</th>
|
||||
<th scope="col" style="width: 30%;">{% trans "Created By" %}</th>
|
||||
<th scope="col" style="width: 20%;">{% trans "Created" %}</th>
|
||||
<th scope="col" style="width: 10%;" class="text-end">{% trans "Actions" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for material in materials %}
|
||||
<tr>
|
||||
<td><strong class="text-primary">{{ material.title }}</strong></td>
|
||||
<td>{{ material.created_by.username|default:"Anonymous" }}</td>
|
||||
<td>{{ material.created_at|date:"M d, Y" }}</td>
|
||||
<td class="text-end">
|
||||
<div class="btn-group btn-group-sm" role="group">
|
||||
<a href="{% url 'training_detail' material.pk %}" class="btn btn-outline-primary" title="{% trans 'View' %}">
|
||||
<i class="fas fa-eye"></i>
|
||||
</a>
|
||||
{% if user.is_authenticated and material.created_by == user %}
|
||||
<a href="{% url 'training_update' material.pk %}" class="btn btn-outline-secondary" title="{% trans 'Edit' %}">
|
||||
<i class="fas fa-edit"></i>
|
||||
</a>
|
||||
<button type="button" class="btn btn-outline-danger" title="{% trans 'Delete' %}"
|
||||
data-bs-toggle="modal" data-bs-target="#deleteModal"
|
||||
data-delete-url="{% url 'training_delete' material.pk %}"
|
||||
data-item-name="{{ material.title }}">
|
||||
<i class="fas fa-trash-alt"></i>
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Pagination (Standardized to Reference) #}
|
||||
{% if is_paginated %}
|
||||
<nav aria-label="Page navigation" class="mt-4">
|
||||
<ul class="pagination justify-content-center">
|
||||
{% if page_obj.has_previous %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page=1{% if search_query %}&q={{ search_query }}{% endif %}">First</a>
|
||||
</li>
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ page_obj.previous_page_number }}{% if search_query %}&q={{ search_query }}{% endif %}">Previous</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{% if materials %}
|
||||
<div id="training-materials-list">
|
||||
{# View Switcher #}
|
||||
{% include "includes/_list_view_switcher.html" with list_id="training-materials-list" %}
|
||||
<li class="page-item active">
|
||||
<span class="page-link">{{ page_obj.number }} of {{ page_obj.paginator.num_pages }}</span>
|
||||
</li>
|
||||
|
||||
{# Table View (Default) #}
|
||||
<div class="table-view active">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover align-middle mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">{% trans "Title" %}</th>
|
||||
<th scope="col">{% trans "Created By" %}</th>
|
||||
<th scope="col">{% trans "Created" %}</th>
|
||||
<th scope="col" class="text-center">{% trans "Actions" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for material in materials %}
|
||||
<tr>
|
||||
<td><strong class="text-primary">{{ material.title }}</strong></td>
|
||||
<td>{{ material.created_by.username|default:"Anonymous" }}</td>
|
||||
<td>{{ material.created_at|date:"M d, Y" }}</td>
|
||||
<td class="text-center">
|
||||
<div class="btn-group btn-group-sm" role="group">
|
||||
<a href="{% url 'training_detail' material.pk %}" class="btn btn-outline-primary" title="{% trans 'View' %}">
|
||||
<i class="fas fa-eye"></i>
|
||||
</a>
|
||||
{% if user.is_authenticated and material.created_by == user %}
|
||||
<a href="{% url 'training_update' material.pk %}" class="btn btn-outline-secondary" title="{% trans 'Edit' %}">
|
||||
<i class="fas fa-edit"></i>
|
||||
</a>
|
||||
<button type="button" class="btn btn-outline-danger" title="{% trans 'Delete' %}"
|
||||
data-bs-toggle="deleteModal"
|
||||
data-delete-url="{% url 'training_delete' material.pk %}"
|
||||
data-item-name="{{ material.title }}">
|
||||
<i class="fas fa-trash-alt"></i>
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Card View #}
|
||||
<div class="card-view">
|
||||
<div class="row g-4">
|
||||
{% for material in materials %}
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-header">
|
||||
<h5 class="h5 mb-1">{{ material.title }}</h5>
|
||||
<small class="text-white-50">{{ material.created_by.username|default:"Anonymous" }}</small>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="card-text">
|
||||
<strong>{% trans "Created" %}:</strong> {{ material.created_at|date:"M d, Y" }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<div class="d-flex gap-2">
|
||||
<a href="{% url 'training_detail' material.pk %}" class="btn btn-sm btn-outline-primary w-100">
|
||||
<i class="fas fa-eye"></i> {% trans "View" %}
|
||||
</a>
|
||||
{% if user.is_authenticated and material.created_by == user %}
|
||||
<div class="btn-group w-100" role="group">
|
||||
<a href="{% url 'training_update' material.pk %}" class="btn btn-sm btn-outline-secondary" title="{% trans 'Edit' %}">
|
||||
<i class="fas fa-edit"></i>
|
||||
</a>
|
||||
<button type="button" class="btn btn-outline-danger btn-sm" title="{% trans 'Delete' %}"
|
||||
data-bs-toggle="deleteModal"
|
||||
data-delete-url="{% url 'training_delete' material.pk %}"
|
||||
data-item-name="{{ material.title }}">
|
||||
<i class="fas fa-trash-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if is_paginated %}
|
||||
<div class="card-footer bg-light border-top">
|
||||
<nav aria-label="Page navigation">
|
||||
<ul class="pagination justify-content-center mb-0">
|
||||
{% if page_obj.has_previous %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ page_obj.previous_page_number }}" aria-label="Previous">
|
||||
<span aria-hidden="true">«</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{% for num in page_obj.paginator.page_range %}
|
||||
{% if page_obj.number == num %}
|
||||
<li class="page-item active"><span class="page-link">{{ num }}</span></li>
|
||||
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ num }}">{{ num }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if page_obj.has_next %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ page_obj.next_page_number }}" aria-label="Next">
|
||||
<span aria-hidden="true">»</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% else %}
|
||||
<div class="text-center py-5">
|
||||
<i class="fas fa-book-open fa-3x text-muted mb-3"></i>
|
||||
<h5 class="mb-3">{% trans "No training materials found." %}</h5>
|
||||
<p class="text-muted mb-4">{% trans "It looks like there are no materials yet. Start by adding one!" %}</p>
|
||||
{% if page_obj.has_next %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ page_obj.next_page_number }}{% if search_query %}&q={{ search_query }}{% endif %}">Next</a>
|
||||
</li>
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ page_obj.paginator.num_pages }}{% if search_query %}&q={{ search_query }}{% endif %}">Last</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<div class="text-center py-5 card shadow-sm">
|
||||
<div class="card-body">
|
||||
<i class="fas fa-graduation-cap fa-3x mb-3" style="color: var(--kaauh-teal-dark);"></i>
|
||||
<h3>{% trans "No training materials found" %}</h3>
|
||||
<p class="text-muted">{% trans "It looks like there are no materials yet. Start by adding one!" %}</p>
|
||||
{% if user.is_authenticated %}
|
||||
<a href="{% url 'training_create' %}" class="btn btn-main-action">
|
||||
<i class="fas fa-plus me-1"></i>
|
||||
{% trans "Create Your First Material" %}
|
||||
<a href="{% url 'training_create' %}" class="btn btn-main-action mt-3">
|
||||
<i class="fas fa-plus me-1"></i> {% trans "Create Your First Material" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
Loading…
x
Reference in New Issue
Block a user