haikal/templates/inventory/car_list_view.html
Marwan Alwali ffb770bfe2 update
2025-06-17 20:48:46 +03:00

425 lines
25 KiB
HTML

{% extends "base.html" %}
{% load static i18n custom_filters humanize %}
{%block title%} {%trans 'Inventory'%} {%endblock%}
{% block customCSS %}
<style>
.htmx-indicator{
opacity:0;
transition: opacity 500ms ease-in;
}
.htmx-request .htmx-indicator{
opacity:1;
}
.htmx-request.htmx-indicator{
opacity:1;
}
.on-before-request{
opacity: 0.5;
pointer-events: none;
}
.transition {
transition: all ease-in 1s ;
}
</style>
{% endblock customCSS %}
{% block content %}
<div class="mb-9">
<div id="projectSummary">
<!-- Page Header -->
<div class="row g-3 justify-content-between align-items-end mb-4">
<div class="col-12 col-sm-auto">
<h1 class="text-body-emphasis fw-bold fs-2 mb-0">{{ _("Inventory") }}</h1>
</div>
</div>
<!-- Navigation Tabs -->
<div class="row g-3 justify-content-between align-items-end mb-4">
<div class="col-12 col-sm-auto">
<ul class="nav nav-links mx-n2"
hx-boost="true"
hx-push-url='false'
hx-target=".vehicles-container"
hx-select=".vehicles-container"
hx-swap="innerHTML show:window:top"
hx-indicator=".htmx-indicator"
hx-on::before-request="on_before_request()"
hx-on::after-request="on_after_request()">
<li class="nav-item">
<a class="nav-link px-2 py-1 active"
aria-current="page"
href="{% url 'car_list' %}">
<span>{{ _("All") }}</span>
<span class="text-body-tertiary fw-semibold">({{ stats.all }})</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link px-2 py-1"
href="{% url 'car_list' %}?status=available">
<span>{{ _("Available") }}</span>
<span class="text-body-tertiary fw-semibold">({{ stats.available }})</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link px-2 py-1"
href="{% url 'car_list' %}?status=reserved">
<span>{{ _("Reserved") }}</span>
<span class="text-body-tertiary fw-semibold">({{ stats.reserved }})</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link px-2 py-1"
href="{% url 'car_list' %}?status=transfer">
<span>{{ _("Transfer") }}</span>
<span class="text-body-tertiary fw-semibold">({{ stats.transfer }})</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link px-2 py-1"
href="{% url 'car_list' %}?status=sold">
<span>{{ _("Sold") }}</span>
<span class="text-body-tertiary fw-semibold">({{ stats.sold }})</span>
</a>
</li>
<li class="nav-item">
<button hx-on:click="toggle_filter()"
class="btn btn-sm btn-phoenix-primary px-2 py-1">
<span><span class="fa fa-filter me-1"></span>{{ _("Filter") }}</span>
<span class="fas fa-caret-down fs-9 ms-1 filter-icon"></span>
</button>
</li>
</ul>
</div>
<div class="col-12 col-sm-auto">
<div class="d-flex align-items-center">
<div class="spinner-border mx-3 htmx-indicator" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<div class="search-box me-3">
<form class="position-relative">
<input class="form-control search-input search"
name='search'
type="search"
placeholder="Search vehicles..."
aria-label="Search"
hx-get="{% url 'car_list' %}"
hx-trigger='keyup changed delay:500ms'
hx-target='.vehicles-container'
hx-select='.vehicles-container'
hx-swap="innerHTML show:window:top"
hx-indicator=".htmx-indicator"
hx-on::before-request="on_before_request()"
hx-on::after-request="on_after_request()" />
<span class="fas fa-search search-box-icon"></span>
</form>
</div>
</div>
</div>
</div>
<!-- Filter Section -->
<div class="d-flex align-items-center d-none filter mb-4">
<select hx-get="{% url 'car_list' %}"
name="make"
hx-target='.model-select'
hx-select='.model-select'
hx-swap="outerHTML show:window:top"
hx-indicator=".htmx-indicator"
class="form-select form-control-sm me-1 make"
aria-label="Select make"
hx-on::before-request="filter_before_request()"
hx-on::after-request="filter_after_request()">
<option selected="" value="" disabled>{{ _("Make") }}</option>
{% for m in make %}<option value="{{ m.pk }}">{{ m.get_local_name|default:m.name }}</option>{% endfor %}
</select>
<select hx-get="{% url 'car_list' %}"
hx-include=".make"
name="model"
hx-target='.year'
hx-select='.year'
hx-swap="outerHTML show:window:top"
hx-indicator=".htmx-indicator"
class="form-select form-control-sm me-1 model-select"
aria-label="Select model"
hx-on::before-request="filter_before_request()"
hx-on::after-request="filter_after_request()">
<option selected="" value="" disabled>{{ _("Model") }}</option>
{% for m in model %}<option value="{{ m.pk }}">{{ m.get_local_name|default:m.name }}</option>{% endfor %}
</select>
<select class="form-select form-control-sm me-1 year"
name="year"
aria-label="Select year">
<option selected="" value="" disabled>{{ _("Year") }}</option>
{% for y in year %}<option value="{{ y.0 }}">{{ y.0 }}</option>{% endfor %}
</select>
<select class="form-select form-control-sm me-1 car_status"
name="car_status"
aria-label="Select status">
<option selected="" value="">{{ _("All Status") }}</option>
<option value="available">{{ _("Available") }}</option>
<option value="reserved">{{ _("Reserved") }}</option>
<option value="sold">{{ _("Sold") }}</option>
<option value="transfer">{{ _("Transfer") }}</option>
</select>
<button id="search"
hx-get="{% url 'car_list' %}"
hx-include=".make,.model,.year,.car_status"
hx-indicator=".htmx-indicator"
hx-target='.vehicles-container'
hx-select='.vehicles-container'
hx-swap="outerHTML show:window:top"
class="btn btn-sm btn-phoenix-primary ms-1"
hx-on::before-request="filter_before_request()"
hx-on::after-request="filter_after_request()">
<span class="fas fa-search me-1"></span>{{ _("Search") }}
</button>
</div>
<!-- Vehicles Container -->
<div class="row">
<div class="vehicles-container transition">
<div class="d-flex flex-wrap align-items-center justify-content-between py-3 pe-0 fs-9">
<div class="d-flex"
hx-boost="true"
hx-push-url='false'
hx-include=".make,.model,.year,.car_status"
hx-target=".vehicles-container"
hx-select=".vehicles-container"
hx-swap="innerHTML show:window:top"
hx-indicator=".htmx-indicator"
hx-on::before-request="on_before_request()"
hx-on::after-request="on_after_request()"></div>
<!-- Vehicle Cards Grid -->
<div class="w-100">
{% for car in cars %}
<div class="card border mb-3">
<div class="card-body">
<div class="row align-items-center">
<!-- Vehicle Image/Icon -->
<div class="col-auto">
{% if car.main_image %}
<img src="{{ car.main_image.url }}"
alt="{{ car.id_car_make.name }} {{ car.id_car_model.name }}"
class="rounded border car-image"
style="width: 120px; height: 80px; object-fit: cover;">
{% else %}
<!-- Dynamic Car Image with Color Styling -->
<div class="rounded border d-flex align-items-center justify-content-center position-relative overflow-hidden"
style="width: 120px; height: 80px;
{% if car.colors.exterior.rgb %}
background: linear-gradient(135deg, rgba({{ car.colors.exterior.rgb }}, 0.5) 0%, rgba({{ car.colors.exterior.rgb }}, 0.5) 100%);
{% endif %}">
<!-- Car Image -->
<img src="{% static 'images/cars/' %}{{ car.id_car_serie|get_vehicle_image }}"
alt="{{ car.id_car_serie|get_vehicle_type_name|title }}"
class="car-image"
style="width: 100%; height: 100%; object-fit: contain;
{% if car.colors.exterior.rgb %}
filter: sepia(0.3) saturate(1.5) brightness(1.1);
{% endif %}">
<!-- Vehicle Type Badge -->
<span class="badge bg-dark bg-opacity-75 text-white position-absolute bottom-0 start-0 m-1 fs-10">
{{ car.id_car_serie|get_vehicle_type_name|title }}
</span>
</div>
{% endif %}
</div>
<!-- Vehicle Details -->
<div class="col">
<div class="row">
<!-- Make/Model/Specs -->
<div class="col-md-4">
<h5 class="text-body-emphasis fw-bold mb-1">
<a href="{% url 'car_detail' car.slug %}"
class="text-decoration-none text-body-emphasis">
{% if car.id_car_make %}
{{ car.id_car_make.get_local_name|default:car.id_car_make.name }}
{% endif %}
</a>
</h5>
<p class="text-body mb-1 fw-semibold">
{% if car.id_car_model %}
{{ car.id_car_model.get_local_name|default:car.id_car_model.name }}
{% endif %}
</p>
<small class="text-body-secondary">
{% if car.id_car_trim %}{{ car.id_car_trim }}{% endif %}
{% if car.year %} ({{ car.year }}){% endif %}
</small>
</div>
<!-- Color and Date -->
<div class="col-md-3">
<p class="text-body mb-1">
{% if car.colors.exterior %}
{{ car.colors.exterior.get_local_name }}
{% endif %}
</p>
<small class="text-body-secondary">
{{ car.receiving_date|naturalday|capfirst }}
</small>
</div>
<!-- Status Badge -->
<div class="col-md-3">
{% if car.status == "available" %}
<span class="badge badge-phoenix fs-11 badge-phoenix-success text-uppercase px-3 py-2">{{ _("Available") }}</span>
{% elif car.status == "reserved" %}
<span class="badge badge-phoenix fs-11 badge-phoenix-warning text-uppercase px-3 py-2">{{ _("Reserved") }}</span>
{% elif car.status == "sold" %}
<span class="badge badge-phoenix fs-11 badge-phoenix-danger text-uppercase px-3 py-2">{{ _("Sold") }}</span>
{% elif car.status == "transfer" %}
<span class="badge badge-phoenix fs-11 badge-phoenix-info text-uppercase px-3 py-2">{{ _("Transfer") }}</span>
{% endif %}
</div>
<!-- Ready Status -->
<div class="col-md-2">
<div class="d-flex align-items-center">
{% if car.ready %}
<span class="badge bg-success rounded-circle p-1 me-2">
<span class="visually-hidden">Ready</span>
</span>
<span class="text-success fw-semibold">YES</span>
{% else %}
<span class="badge bg-danger rounded-circle p-1 me-2">
<span class="visually-hidden">Not Ready</span>
</span>
<span class="text-danger fw-semibold">NO</span>
{% endif %}
</div>
</div>
</div>
</div>
<!-- Action Menu -->
<div class="col-auto">
<div class="btn-reveal-trigger position-static">
<button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10"
type="button"
data-bs-toggle="dropdown"
data-boundary="window"
aria-haspopup="true"
aria-expanded="false"
data-bs-reference="parent">
<span class="fas fa-ellipsis-h fs-10"></span>
</button>
<div class="dropdown-menu dropdown-menu-end py-2">
<a class="dropdown-item" href="{% url 'car_detail' car.slug %}">
<span class="fas fa-eye me-2"></span>{{ _("View") }}
</a>
<a class="dropdown-item" href="{% url 'car_update' car.slug %}">
<span class="fas fa-edit me-2"></span>{{ _("Edit") }}
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger" href="{% url 'car_delete' car.slug %}">
<span class="fas fa-trash me-2"></span>{{ _("Remove") }}
</a>
</div>
</div>
</div>
</div>
</div>
</div>
{% empty %}
<div class="text-center py-5">
<div class="text-body-secondary">
<span class="fas fa-car fa-4x mb-3 opacity-50"></span>
<h4 class="text-body-secondary">{{ _("No vehicles found") }}</h4>
<p class="text-body-tertiary">{{ _("Try adjusting your search criteria or filters") }}</p>
</div>
</div>
{% endfor %}
</div>
<!-- Pagination -->
{% if is_paginated %}
<div class="d-flex justify-content-between align-items-center mt-4 w-100">
<div class="text-body-secondary">
{{ _("Showing") }} {{ page_obj.start_index }} {{ _("to") }} {{ page_obj.end_index }}
{{ _("of") }} {{ page_obj.paginator.count }} {{ _("results") }}
</div>
<nav aria-label="Page navigation">
<ul class="pagination pagination-sm mb-0">
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.previous_page_number }}">
<span class="fas fa-chevron-left"></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 }}">
<span class="fas fa-chevron-right"></span>
</a>
</li>
{% endif %}
</ul>
</nav>
</div>
{% endif %}
</div>
</div>
</div>
</div>
</div>
<script>
function toggle_filter() {
const filter = document.querySelector('.filter');
filter.classList.toggle('d-none');
const icon = document.querySelector('.filter-icon');
if (filter.classList.contains('d-none')) {
icon.classList.remove('fa-caret-up');
icon.classList.add('fa-caret-down');
} else {
icon.classList.remove('fa-caret-down');
icon.classList.add('fa-caret-up');
}
}
function on_before_request() {
const container = document.querySelector('.vehicles-container');
if (container) {
container.classList.add('on-before-request');
}
}
function on_after_request() {
const container = document.querySelector('.vehicles-container');
if (container) {
container.classList.remove('on-before-request');
}
}
function filter_before_request() {
on_before_request();
}
function filter_after_request() {
on_after_request();
}
</script>
{% endblock content %}