324 lines
20 KiB
HTML
324 lines
20 KiB
HTML
{% extends 'base.html' %}
|
|
{% load static i18n crispy_forms_tags %}
|
|
|
|
|
|
{% block title %}{% trans "Form Templates" %} - {{ block.super }}{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="space-y-6">
|
|
|
|
<!-- Desktop Header -->
|
|
<div class="hidden lg:block">
|
|
<!-- Breadcrumb -->
|
|
<nav class="mb-6" aria-label="breadcrumb">
|
|
<ol class="flex items-center gap-2 text-sm flex-wrap">
|
|
<li><a href="{% url 'dashboard' %}" class="text-gray-500 hover:text-temple-red transition flex items-center gap-1">
|
|
<i data-lucide="home" class="w-4 h-4"></i> {% trans "Home" %}
|
|
</a></li>
|
|
<li class="text-gray-400">/</li>
|
|
<li class="text-temple-red font-semibold">{% trans "Form Templates" %}</li>
|
|
</ol>
|
|
</nav>
|
|
|
|
<div class="flex justify-between items-start mb-6">
|
|
<h1 class="text-3xl font-bold text-gray-900 flex items-center gap-3">
|
|
<div class="bg-temple-red/10 p-3 rounded-xl">
|
|
<i data-lucide="file-text" class="w-8 h-8 text-temple-red"></i>
|
|
</div>
|
|
{% trans "Form Templates" %}
|
|
</h1>
|
|
<button type="button" class="inline-flex items-center gap-2 bg-temple-red hover:bg-[#7a1a29] text-white font-semibold px-6 py-2.5 rounded-xl transition shadow-sm hover:shadow-md"
|
|
onclick="document.getElementById('createTemplateModal').classList.remove('hidden'); document.getElementById('createTemplateModal').classList.add('flex');">
|
|
<i data-lucide="plus" class="w-4 h-4"></i> {% trans "Create New Template" %}
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Desktop Filters -->
|
|
<div class="bg-white rounded-2xl shadow-sm border border-gray-100 overflow-hidden mb-6">
|
|
<div class="bg-gradient-to-br from-temple-red to-[#7a1a29] text-white p-4">
|
|
<h5 class="text-lg font-bold flex items-center gap-2">
|
|
<i data-lucide="filter" class="w-5 h-5"></i>
|
|
{% trans "Filter Templates" %}
|
|
</h5>
|
|
</div>
|
|
<div class="p-6">
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<div>
|
|
<label for="searchInput" class="block text-xs font-semibold text-gray-600 mb-2">{% trans "Search by Template Name" %}</label>
|
|
<form method="get" class="flex gap-3">
|
|
<div class="relative flex-1">
|
|
<i data-lucide="search" class="absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400"></i>
|
|
<input type="text" name="q" id="searchInput"
|
|
class="w-full pl-10 pr-4 py-3 bg-white border border-gray-200 rounded-xl text-sm focus:ring-2 focus:ring-temple-red/20 focus:border-temple-red outline-none transition"
|
|
placeholder="{% trans 'Search templates by name...' %}"
|
|
value="{{ query|default_if_none:'' }}">
|
|
</div>
|
|
<button type="submit" class="inline-flex items-center gap-2 bg-temple-red hover:bg-[#7a1a29] text-white font-medium px-5 py-2.5 rounded-xl text-sm transition whitespace-nowrap">
|
|
<i data-lucide="filter" class="w-4 h-4"></i> {% trans "Search" %}
|
|
</button>
|
|
{% if query %}
|
|
<a href="{% url 'form_templates_list' %}" class="inline-flex items-center gap-2 border border-gray-300 text-gray-600 hover:bg-gray-100 px-4 py-2.5 rounded-xl text-sm transition whitespace-nowrap">
|
|
<i data-lucide="x" class="w-4 h-4"></i> {% trans "Clear" %}
|
|
</a>
|
|
{% endif %}
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Mobile Header -->
|
|
<div class="lg:hidden mb-4">
|
|
<div class="flex items-center justify-between mb-4">
|
|
<h1 class="text-2xl font-bold text-gray-900 flex items-center gap-2">
|
|
<div class="bg-temple-red/10 p-2 rounded-lg">
|
|
<i data-lucide="file-text" class="w-6 h-6 text-temple-red"></i>
|
|
</div>
|
|
{% trans "Form Templates" %}
|
|
</h1>
|
|
<button type="button" class="inline-flex items-center gap-2 bg-temple-red hover:bg-[#7a1a29] text-white font-semibold px-4 py-2.5 rounded-xl text-sm transition shadow-sm"
|
|
onclick="document.getElementById('createTemplateModal').classList.remove('hidden'); document.getElementById('createTemplateModal').classList.add('flex');">
|
|
<i data-lucide="plus" class="w-4 h-4"></i> {% trans "Create" %}
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Mobile Filters -->
|
|
<div class="space-y-3">
|
|
<div>
|
|
<label for="searchInputMobile" class="block text-xs font-semibold text-gray-600 mb-2">{% trans "Search Templates" %}</label>
|
|
<form method="get" class="flex gap-2">
|
|
<div class="relative flex-1">
|
|
<i data-lucide="search" class="absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400"></i>
|
|
<input type="text" name="q" id="searchInputMobile"
|
|
class="w-full pl-10 pr-4 py-3 bg-white border border-gray-200 rounded-xl text-sm focus:ring-2 focus:ring-temple-red/20 focus:border-temple-red outline-none transition"
|
|
placeholder="{% trans 'Search...' %}"
|
|
value="{{ query|default_if_none:'' }}">
|
|
</div>
|
|
<button type="submit" class="bg-temple-red hover:bg-[#7a1a29] text-white px-4 py-3 rounded-xl transition">
|
|
<i data-lucide="search" class="w-4 h-4"></i>
|
|
</button>
|
|
{% if query %}
|
|
<a href="{% url 'form_templates_list' %}" class="bg-gray-100 hover:bg-gray-200 text-gray-600 px-4 py-3 rounded-xl transition">
|
|
<i data-lucide="x" class="w-4 h-4"></i>
|
|
</a>
|
|
{% endif %}
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{% if templates %}
|
|
<div id="form-templates-list">
|
|
{# View Switcher #}
|
|
{% include "includes/_list_view_switcher.html" with list_id="form-templates-list" %}
|
|
|
|
{# Card View (Default) #}
|
|
<div class="card-view active lg:hidden grid grid-cols-1 gap-4">
|
|
{% for template in templates %}
|
|
<div class="bg-white rounded-2xl shadow-sm border border-gray-100 overflow-hidden">
|
|
<div class="bg-gradient-to-br from-temple-red to-[#7a1a29] text-white p-4">
|
|
<h5 class="font-bold text-lg">{{ template.name }}</h5>
|
|
<span class="text-sm text-white/80">
|
|
<i data-lucide="briefcase" class="w-4 h-4 inline mr-1"></i> {{ template.job|default:"N/A" }}
|
|
</span>
|
|
</div>
|
|
<div class="p-4 space-y-3">
|
|
{# Stats #}
|
|
<div class="grid grid-cols-2 gap-2 text-center mb-3">
|
|
<div class="p-3 bg-gray-50 rounded-xl">
|
|
<div class="text-2xl font-bold text-temple-red">{{ template.get_stage_count }}</div>
|
|
<div class="text-[10px] uppercase text-gray-500 font-semibold">{% trans "Stages" %}</div>
|
|
</div>
|
|
<div class="p-3 bg-gray-50 rounded-xl">
|
|
<div class="text-2xl font-bold text-temple-red">{{ template.get_field_count }}</div>
|
|
<div class="text-[10px] uppercase text-gray-500 font-semibold">{% trans "Fields" %}</div>
|
|
</div>
|
|
</div>
|
|
|
|
{# Description #}
|
|
<p class="text-sm text-gray-600">
|
|
{% if template.description %}
|
|
{{ template.description|truncatewords:20 }}
|
|
{% else %}
|
|
<em class="text-gray-400">{% trans "No description provided" %}</em>
|
|
{% endif %}
|
|
</p>
|
|
|
|
{# Actions #}
|
|
<div class="flex gap-2 pt-3 border-t border-gray-100">
|
|
<a href="{% url 'application_submit_form' template.job.slug %}" class="inline-flex items-center justify-center gap-2 bg-temple-red hover:bg-[#7a1a29] text-white font-medium px-4 py-2.5 rounded-xl text-sm transition flex-1">
|
|
<i data-lucide="eye" class="w-4 h-4"></i> {% trans "Preview" %}
|
|
</a>
|
|
<a href="{% url 'form_builder' template.slug %}" class="inline-flex items-center justify-center w-10 h-10 rounded-xl border border-gray-300 hover:bg-gray-100 text-gray-600 transition">
|
|
<i data-lucide="edit-2" class="w-4 h-4"></i>
|
|
</a>
|
|
<a href="{% url 'form_template_submissions_list' template.slug %}" class="inline-flex items-center justify-center w-10 h-10 rounded-xl border border-gray-300 hover:bg-gray-100 text-gray-600 transition">
|
|
<i data-lucide="file-text" class="w-4 h-4"></i>
|
|
</a>
|
|
<button type="button" class="inline-flex items-center justify-center w-10 h-10 rounded-xl border border-red-300 bg-red-50 hover:bg-red-100 text-red-600 transition"
|
|
onclick="deleteTemplate('{{ template.name }}', '#')">
|
|
<i data-lucide="trash-2" class="w-4 h-4"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="bg-gray-50 text-gray-500 text-xs p-3 flex justify-between">
|
|
<span><i data-lucide="calendar" class="w-3 h-3 inline mr-1"></i> {% trans "Created:" %} {{ template.created_at|date:"M d, Y" }}</span>
|
|
<span><i data-lucide="refresh-cw" class="w-3 h-3 inline mr-1"></i> {{ template.updated_at|timesince }} {% trans "ago" %}</span>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
|
|
{# Table View #}
|
|
<div class="hidden lg:block bg-white rounded-2xl shadow-sm border border-gray-100 overflow-hidden">
|
|
<div class="bg-gradient-to-br from-temple-red to-[#7a1a29] text-white p-4">
|
|
<h5 class="text-lg font-bold flex items-center gap-2">
|
|
<i data-lucide="list" class="w-5 h-5"></i>
|
|
{% trans "Template Listings" %}
|
|
</h5>
|
|
</div>
|
|
<div class="overflow-x-auto">
|
|
<table class="min-w-full divide-y divide-gray-200">
|
|
<thead class="bg-gray-50">
|
|
<tr>
|
|
<th scope="col" class="px-6 py-3 text-left text-xs font-bold text-gray-700 tracking-wider whitespace-nowrap">{% trans "Template Name" %}</th>
|
|
<th scope="col" class="px-6 py-3 text-left text-xs font-bold text-gray-700 tracking-wider whitespace-nowrap">{% trans "Job" %}</th>
|
|
<th scope="col" class="px-6 py-3 text-left text-xs font-bold text-gray-700 tracking-wider whitespace-nowrap">{% trans "Stages" %}</th>
|
|
<th scope="col" class="px-6 py-3 text-left text-xs font-bold text-gray-700 tracking-wider whitespace-nowrap">{% trans "Fields" %}</th>
|
|
<th scope="col" class="px-6 py-3 text-left text-xs font-bold text-gray-700 tracking-wider whitespace-nowrap">{% trans "Created" %}</th>
|
|
<th scope="col" class="px-6 py-3 text-left text-xs font-bold text-gray-700 tracking-wider whitespace-nowrap">{% trans "Last Updated" %}</th>
|
|
<th scope="col" class="px-6 py-3 text-center text-xs font-bold text-gray-700 tracking-wider whitespace-nowrap">{% trans "Actions" %}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="bg-white divide-y divide-gray-100">
|
|
{% for template in templates %}
|
|
<tr class="hover:bg-gray-50 transition-colors">
|
|
<td class="px-6 py-4">
|
|
<a href="#" class="text-temple-red font-semibold hover:text-[#7a1a29] transition-colors">{{ template.name }}</a>
|
|
</td>
|
|
<td class="px-6 py-4 text-sm text-gray-700">{{ template.job|default:"N/A" }}</td>
|
|
<td class="px-6 py-4 text-sm text-gray-700">{{ template.get_stage_count }}</td>
|
|
<td class="px-6 py-4 text-sm text-gray-700">{{ template.get_field_count }}</td>
|
|
<td class="px-6 py-4 text-sm text-gray-700">{{ template.created_at|date:"M d, Y" }}</td>
|
|
<td class="px-6 py-4 text-sm text-gray-700">{{ template.updated_at|date:"M d, Y" }}</td>
|
|
<td class="px-6 py-4 text-center">
|
|
<div class="flex items-center justify-center gap-2">
|
|
<a href="{% url 'application_submit_form' template.job.slug %}" class="inline-flex items-center justify-center w-9 h-9 rounded-lg bg-temple-red/10 hover:bg-temple-red/20 text-temple-red transition" title="{% trans 'Preview' %}">
|
|
<i data-lucide="eye" class="w-4 h-4"></i>
|
|
</a>
|
|
<a href="{% url 'form_builder' template.slug %}" class="inline-flex items-center justify-center w-9 h-9 rounded-lg border border-gray-300 hover:bg-gray-100 text-gray-600 transition" title="{% trans 'Edit' %}">
|
|
<i data-lucide="edit-2" class="w-4 h-4"></i>
|
|
</a>
|
|
<a href="{% url 'form_template_submissions_list' template.slug %}" class="inline-flex items-center justify-center w-9 h-9 rounded-lg border border-gray-300 hover:bg-gray-100 text-gray-600 transition" title="{% trans 'Submissions' %}">
|
|
<i data-lucide="file-text" class="w-4 h-4"></i>
|
|
</a>
|
|
<button type="button" class="inline-flex items-center justify-center w-9 h-9 rounded-lg border border-red-300 bg-red-50 hover:bg-red-100 text-red-600 transition" title="{% trans 'Delete' %}"
|
|
onclick="deleteTemplate('{{ template.name }}', '#')">
|
|
<i data-lucide="trash-2" class="w-4 h-4"></i>
|
|
</button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{# Pagination #}
|
|
{% if templates.has_other_pages %}
|
|
<nav aria-label="Page navigation" class="flex justify-center items-center gap-2">
|
|
{% if templates.has_previous %}
|
|
<a href="?page=1{% if query %}&q={{ query }}{% endif %}" class="px-3 py-2 bg-white border border-gray-200 rounded-lg text-sm text-gray-700 hover:bg-gray-50 transition">
|
|
{% trans "First" %}
|
|
</a>
|
|
<a href="?page={{ templates.previous_page_number }}{% if query %}&q={{ query }}{% endif %}" class="px-3 py-2 bg-white border border-gray-200 rounded-lg text-sm text-gray-700 hover:bg-gray-50 transition">
|
|
{% trans "Previous" %}
|
|
</a>
|
|
{% endif %}
|
|
|
|
<span class="px-3 py-2 bg-temple-red text-white rounded-lg text-sm font-semibold">
|
|
{{ templates.number }} {% trans "of" %} {{ templates.paginator.num_pages }}
|
|
</span>
|
|
|
|
{% if templates.has_next %}
|
|
<a href="?page={{ templates.next_page_number }}{% if query %}&q={{ query }}{% endif %}" class="px-3 py-2 bg-white border border-gray-200 rounded-lg text-sm text-gray-700 hover:bg-gray-50 transition">
|
|
{% trans "Next" %}
|
|
</a>
|
|
<a href="?page={{ templates.paginator.num_pages }}{% if query %}&q={{ query }}{% endif %}" class="px-3 py-2 bg-white border border-gray-200 rounded-lg text-sm text-gray-700 hover:bg-gray-50 transition">
|
|
{% trans "Last" %}
|
|
</a>
|
|
{% endif %}
|
|
</nav>
|
|
{% endif %}
|
|
{% else %}
|
|
<!-- No Results -->
|
|
<div class="bg-white rounded-2xl shadow-sm border border-gray-100 p-12 text-center">
|
|
<i data-lucide="file-text" class="w-16 h-16 text-temple-red mx-auto mb-4"></i>
|
|
<h3 class="text-xl font-semibold text-gray-900 mb-2">{% trans "No Form Templates Found" %}</h3>
|
|
<p class="text-gray-500 mb-6">
|
|
{% if query %}
|
|
{% blocktrans with query=query %}No templates match your search "{{ query }}".{% endblocktrans %}
|
|
{% else %}
|
|
{% trans "You haven't created any form templates yet." %}
|
|
{% endif %}
|
|
</p>
|
|
<button type="button" class="inline-flex items-center gap-2 bg-temple-red hover:bg-[#7a1a29] text-white font-semibold px-6 py-3 rounded-xl transition shadow-sm hover:shadow-md"
|
|
onclick="document.getElementById('createTemplateModal').classList.remove('hidden'); document.getElementById('createTemplateModal').classList.add('flex');">
|
|
<i data-lucide="plus" class="w-5 h-5"></i> {% trans "Create Your First Template" %}
|
|
</button>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
{% include 'includes/delete_modal.html' %}
|
|
|
|
<!-- Create Template Modal -->
|
|
<div id="createTemplateModal" class="fixed inset-0 z-50 hidden">
|
|
<div class="absolute inset-0 bg-black/50 backdrop-blur-sm" onclick="closeCreateModal()"></div>
|
|
<div class="relative min-h-screen flex items-center justify-center p-4">
|
|
<div class="relative bg-white rounded-2xl shadow-2xl w-full max-w-lg">
|
|
<div class="bg-gray-50 px-6 py-4 border-b border-gray-200 rounded-t-2xl">
|
|
<h3 class="text-lg font-bold text-gray-900 flex items-center gap-2">
|
|
<i data-lucide="file-text" class="w-5 h-5 text-temple-red"></i>
|
|
{% trans "Create New Form Template" %}
|
|
</h3>
|
|
<button type="button" onclick="closeCreateModal()" class="absolute top-4 right-4 text-gray-400 hover:text-gray-600 transition">
|
|
<i data-lucide="x" class="w-6 h-6"></i>
|
|
</button>
|
|
</div>
|
|
<div class="p-6">
|
|
<form id="createTemplateForm" method="post" action="{% url 'create_form_template' %}">
|
|
{% csrf_token %}
|
|
{{form|crispy}}
|
|
</form>
|
|
</div>
|
|
<div class="px-6 py-4 border-t border-gray-200 flex gap-3 justify-end">
|
|
<button type="button" onclick="closeCreateModal()" class="px-4 py-2 border border-gray-300 text-gray-700 rounded-xl hover:bg-gray-50 transition text-sm">
|
|
{% trans "Cancel" %}
|
|
</button>
|
|
<button type="submit" form="createTemplateForm" class="px-4 py-2 bg-temple-red hover:bg-[#7a1a29] text-white rounded-xl transition text-sm font-semibold flex items-center gap-2">
|
|
<i data-lucide="save" class="w-4 h-4"></i> {% trans "Create Template" %}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
lucide.createIcons();
|
|
|
|
function closeCreateModal() {
|
|
document.getElementById('createTemplateModal').classList.add('hidden');
|
|
document.getElementById('createTemplateModal').classList.remove('flex');
|
|
}
|
|
|
|
function deleteTemplate(name, url) {
|
|
if (confirm('{% trans "Are you sure you want to delete this template?" %}')) {
|
|
window.location.href = url;
|
|
}
|
|
}
|
|
</script>
|
|
{% endblock %} |