ckeditor added #9
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