This commit is contained in:
Marwan Alwali 2025-06-22 23:50:50 +03:00
parent ebd2f06eb6
commit e1a01ce2d5
52 changed files with 365 additions and 400 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@ -1053,7 +1053,7 @@ class CarListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
model = models.Car model = models.Car
template_name = "inventory/car_list_view.html" template_name = "inventory/car_list_view.html"
context_object_name = "cars" context_object_name = "cars"
paginate_by = 30 paginate_by = 10
permission_required = "inventory.view_car" permission_required = "inventory.view_car"
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):

BIN
static/.DS_Store vendored

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 KiB

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 909 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 878 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 864 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 873 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 875 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 921 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 906 KiB

View File

@ -19,3 +19,6 @@
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,37 +1,35 @@
{% extends "base.html" %} {% extends "base.html" %}
{% load static i18n custom_filters humanize %} {% load static i18n custom_filters humanize %}
{%block title%} {%trans 'Stocks'%} {%endblock%} {%block title%} {%trans 'Inventory'%} {%endblock%}
{% block customCSS %} {% block customCSS %}
<style> <style>
.htmx-indicator { .htmx-indicator{
opacity: 0; opacity:0;
transition: opacity 500ms ease-in; transition: opacity 500ms ease-in;
} }
.htmx-request .htmx-indicator { .htmx-request .htmx-indicator{
opacity: 1; opacity:1;
} }
.htmx-request.htmx-indicator { .htmx-request.htmx-indicator{
opacity: 1; opacity:1;
} }
.on-before-request { .on-before-request{
opacity: 0.5; opacity: 0.5;
pointer-events: none; pointer-events: none;
} }
.transition { .transition {
transition: all ease-in 1s; transition: all ease-in 1s ;
} }
</style> </style>
{% endblock customCSS %} {% endblock customCSS %}
{% block content %} {% block content %}
<div class="mb-9"> <div class="mb-9">
<div id="projectSummary"> <div id="projectSummary">
<div class="row g-3 justify-content-between align-items-end mb-4"> <div class="row g-3 justify-content-between align-items-end mb-4">
<div class="col-12 col-sm-auto"> <div class="col-12 col-sm-auto">
<ul <ul class="nav nav-links mx-n2"
class="nav nav-links mx-n2"
hx-boost="true" hx-boost="true"
hx-push-url="false" hx-push-url='false'
hx-target=".table-responsive" hx-target=".table-responsive"
hx-select=".table-responsive" hx-select=".table-responsive"
hx-swap="innerHTML show:window:top" hx-swap="innerHTML show:window:top"
@ -39,22 +37,28 @@
hx-on::before-request="on_before_request()" hx-on::before-request="on_before_request()"
hx-on::after-request="on_after_request()"> hx-on::after-request="on_after_request()">
<li class="nav-item"> <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> <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>
<li class="nav-item"> <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> <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>
<li class="nav-item"> <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> <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>
<li class="nav-item"> <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> <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>
<li class="nav-item"> <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> <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>
<li class="nav-item"> <li class="nav-item">
<button hx-on:click="toggle_filter()" class="btn btn-sm btn-phoenix-primary px-2 py-1"> <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> <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> </button>
</li> </li>
@ -67,21 +71,19 @@
</div> </div>
<div class="search-box me-3"> <div class="search-box me-3">
<form class="position-relative"> <form class="position-relative">
<input <input class="form-control search-input search"
class="form-control search-input search" name='search'
name="search"
type="search" type="search"
placeholder="Search" placeholder="Search"
aria-label="Search" aria-label="Search"
hx-get="{% url 'car_list' %}" hx-get="{% url 'car_list' %}"
hx-trigger="keyup changed delay:500ms" hx-trigger='keyup changed delay:500ms'
hx-target=".table-responsive" hx-target='.table-responsive'
hx-select=".table-responsive" hx-select='.table-responsive'
hx-swap="innerHTML show:window:top" hx-swap="innerHTML show:window:top"
hx-indicator=".htmx-indicator" hx-indicator=".htmx-indicator"
hx-on::before-request="on_before_request()" hx-on::before-request="on_before_request()"
hx-on::after-request="on_after_request()" hx-on::after-request="on_after_request()" />
/>
<span class="fas fa-search search-box-icon"></span> <span class="fas fa-search search-box-icon"></span>
</form> </form>
</div> </div>
@ -89,11 +91,10 @@
</div> </div>
</div> </div>
<div class="d-flex align-items-center d-none filter"> <div class="d-flex align-items-center d-none filter">
<select <select hx-get="{% url 'car_list' %}"
hx-get="{% url 'car_list' %}"
name="make" name="make"
hx-target=".model-select" hx-target='.model-select'
hx-select=".model-select" hx-select='.model-select'
hx-swap="outerHTML show:window:top" hx-swap="outerHTML show:window:top"
hx-indicator=".htmx-indicator" hx-indicator=".htmx-indicator"
class="form-select form-control-sm me-1 make" class="form-select form-control-sm me-1 make"
@ -101,16 +102,13 @@
hx-on::before-request="filter_before_request()" hx-on::before-request="filter_before_request()"
hx-on::after-request="filter_after_request()"> hx-on::after-request="filter_after_request()">
<option selected="" value="" disabled>{{ _("Make") }}</option> <option selected="" value="" disabled>{{ _("Make") }}</option>
{% for m in make %} {% for m in make %}<option value="{{ m.pk }}">{{ m.get_local_name|default:m.name }}</option>{% endfor %}
<option value="{{ m.pk }}">{{ m.get_local_name|default:m.name }}</option>
{% endfor %}
</select> </select>
<select <select hx-get="{% url 'car_list' %}"
hx-get="{% url 'car_list' %}"
hx-include=".make" hx-include=".make"
name="model" name="model"
hx-target=".year" hx-target='.year'
hx-select=".year" hx-select='.year'
hx-swap="outerHTML show:window:top" hx-swap="outerHTML show:window:top"
hx-indicator=".htmx-indicator" hx-indicator=".htmx-indicator"
class="form-select form-control-sm me-1 model-select" class="form-select form-control-sm me-1 model-select"
@ -118,52 +116,50 @@
hx-on::before-request="filter_before_request()" hx-on::before-request="filter_before_request()"
hx-on::after-request="filter_after_request()"> hx-on::after-request="filter_after_request()">
<option selected="" value="" disabled>{{ _("Model") }}</option> <option selected="" value="" disabled>{{ _("Model") }}</option>
{% for m in model %} {% for m in model %}<option value="{{ m.pk }}">{{ m.get_local_name|default:m.name }}</option>{% endfor %}
<option value="{{ m.pk }}">{{ m.get_local_name|default:m.name }}</option>
{% endfor %}
</select> </select>
<select class="form-select form-control-sm me-1 year" name="year" aria-label="Default select example"> <select class="form-select form-control-sm me-1 year"
name="year"
aria-label="Default select example">
<option selected="" value="" disabled>{{ _("Year") }}</option> <option selected="" value="" disabled>{{ _("Year") }}</option>
{% for y in year %} {% for y in year %}<option value="{{ y.0 }}">{{ y.0 }}</option>{% endfor %}
<option value="{{ y.0 }}">{{ y.0 }}</option>
{% endfor %}
</select> </select>
<select class="form-select form-control-sm me-1 car_status" name="car_status" aria-label="Default select example"> <select class="form-select form-control-sm me-1 car_status"
name="car_status"
aria-label="Default select example">
<option selected="" value="">{{ _("All") }}</option> <option selected="" value="">{{ _("All") }}</option>
<option value="available">{{ _("Available") }}</option> <option value="available">{{ _("Available") }}</option>
<option value="reserved">{{ _("Reserved") }}</option> <option value="reserved">{{ _("Reserved") }}</option>
<option value="sold">{{ _("Sold") }}</option> <option value="sold">{{ _("Sold") }}</option>
<option value="transfer">{{ _("Transfer") }}</option> <option value="transfer">{{ _("Transfer") }}</option>
</select> </select>
<button <button id="search"
id="search"
hx-get="{% url 'car_list' %}" hx-get="{% url 'car_list' %}"
hx-include=".make,.model,.year,.car_status" hx-include=".make,.model,.year,.car_status"
hx-indicator=".htmx-indicator" hx-indicator=".htmx-indicator"
hx-target=".table-responsive" hx-target='.table-responsive'
hx-select=".table-responsive" hx-select='.table-responsive'
hx-swap="outerHTML show:window:top" hx-swap="outerHTML show:window:top"
class="btn btn-sm btn-phoenix-primary ms-1" class="btn btn-sm btn-phoenix-primary ms-1"
hx-on::before-request="filter_before_request()" hx-on::before-request="filter_before_request()"
hx-on::after-request="filter_after_request()"> hx-on::after-request="filter_after_request()">{{ _("Search") }}</button>
{{ _("Search") }}
</button>
</div> </div>
<div class="row"> <div class="row">
<form hx-boost="true" action="{% url 'bulk_update_car_price' %}" method="post" hx-include=".car-checkbox" class="update-price-form d-flex flex-row align-items-center ms-auto w-25 d-none" style="float: right;"> <form hx-boost='true' action="{% url 'bulk_update_car_price' %}" method="post"
hx-include=".car-checkbox"
class="update-price-form d-flex flex-row align-items-center ms-auto w-25 d-none" style="float:right;">
{% csrf_token %} {% csrf_token %}
<div class="form-floating me-2"> <div class="form-floating me-2">
<input class="form-control" type="number" placeholder='{{ _("Search") }}' name="price" aria-label="Price" id="price" /> <input class="form-control" type="number" placeholder='{{ _("Search") }}' name="price" aria-label="Price" id="price">
<label for="price">{{ _("Price") }}</label> <label for="price">{{ _("Price") }}</label>
</div> </div>
<button class="btn btn-outline-primary" type="submit">{{ _("Search") }}</button> <button class="btn btn-outline-primary" type="submit">{{ _("Search") }}</button>
</form> </form>
<div class="table-responsive scrollbar transition"> <div class="table-responsive scrollbar transition">
<div class="d-flex flex-wrap align-items-center justify-content-between py-3 pe-0 fs-9"> <div class="d-flex flex-wrap align-items-center justify-content-between py-3 pe-0 fs-9">
<div <div class="d-flex"
class="d-flex"
hx-boost="true" hx-boost="true"
hx-push-url="false" hx-push-url='false'
hx-include=".make,.model,.year,.car_status" hx-include=".make,.model,.year,.car_status"
hx-target=".table-responsive" hx-target=".table-responsive"
hx-select=".table-responsive" hx-select=".table-responsive"
@ -171,90 +167,91 @@
hx-indicator=".htmx-indicator" hx-indicator=".htmx-indicator"
hx-on::before-request="on_before_request()" hx-on::before-request="on_before_request()"
hx-on::after-request="on_after_request()"></div> hx-on::after-request="on_after_request()"></div>
<div class="w-100 list table-responsive" > <table class="table align-items-center table-flush">
<thead class="text-body">
<tr class="bg-body-highlight">
<th class="sort white-space-nowrap align-middle" scope="col">
<div class="form-check"> <div class="form-check">
<input class="form-check-input ms-4" type="checkbox" id="select-all" /> <span class="ms-1 text-body-tertiary">{{ _("Select All") }}</span> <input class="form-check-input" type="checkbox" id="select-all" />
</div> </div>
</th>
<th class="sort white-space-nowrap align-middle" scope="col">{{ _("VIN") }}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{{ _("Make") }}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{{ _("Model") }}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{{ _("Year") }}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{{ _("Trim") }}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{{ _("Color") }}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{{ _("Date Received") }}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{{ _("Status") }}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{{ _("Inventory Ready") }}</th>
<th class="sort white-space-nowrap align-middle" scope="col"></th>
</tr>
</thead>
<tbody class="list" id="project-list-table-body">
{% for car in cars %} {% for car in cars %}
<div class="card border mb-3 py-0 px-0" id="project-list-table-body"> <tr class="position-static">
<div class="card-body"> <td class="align-middle white-space-nowrap">
<div class="row align-items-center">
<div class="col-auto">
<div class="form-check"> <div class="form-check">
<input class="form-check-input car-checkbox" type="checkbox" name="car" value="{{ car.pk }}" id="car-{{car.pk}}" /> <input class="form-check-input car-checkbox" type="checkbox" name="car" value="{{ car.pk }}" id="car-{{car.pk}}">
</div>
</td>
<td class="align-middle white-space-nowrap ps-1">
<a class="fw-bold" href="{% url 'car_detail' car.slug %}">{{ car.vin }}</a>
</td>
<td class="align-middle white-space-nowrap">
{% if car.id_car_make %}
<p class="text-body mb-0">{{ car.id_car_make.get_local_name|default:car.id_car_make.name }}</p>
{% endif %}
</td>
<td class="align-middle white-space-nowrap">
{% if car.id_car_model %}
<p class="text-body mb-0">{{ car.id_car_model.get_local_name|default:car.id_car_model.name }}</p>
{% endif %}
</td>
<td class="align-middle white-space-nowrap">
<p class="text-body mb-0">{{ car.year }}</p>
</td>
<td class="align-middle white-space-nowrap">
<p class="fw-bold text-body mb-0">{{ car.id_car_trim }}</p>
</td>
<td class="align-middle white-space-nowrap">
<div class="d-flex flex-row align-items-center">
<div class="d-flex flex-column align-items-center">
<span class="color-div"
style="background: linear-gradient(90deg, rgba({{ car.colors.exterior.rgb }},1) 10%, rgba({{ car.colors.exterior.rgb }},0.10) 100%)"
title="{{ car.colors.exterior.get_local_name }}"></span><span>{{ car.colors.exterior.get_local_name }}</span>
</div>
<div class="d-flex flex-column align-items-center">
<span class="color-div"
style="background: linear-gradient(90deg, rgba({{ car.colors.interior.rgb }},1) 10%, rgba({{ car.colors.interior.rgb }},0.10) 100%)"
title="{{ car.colors.interior.get_local_name }}"></span><span>{{ car.colors.interior.get_local_name }}</span>
</div> </div>
</div> </div>
<!-- Vehicle Image/Icon --> </td>
<div class="col-auto"> <td class="align-middle white-space-nowrap">
<div class="avatar avatar-3xl"> <p class="fw-bold text-body mb-0">{{ car.receiving_date|naturalday|capfirst }}</p>
<img class="rounded-soft shadow shadow-lg" src="{% static 'images/cars/' %}{{ car.vin }}.png" alt="{{ car.vin }}" /> </td>
</div> <td class="align-middle white-space-nowrap statuses">
</div>
<!-- Vehicle Details -->
<div class="col">
<div class="row">
<!-- Make/Model/Specs -->
<div class="col-md-4">
<h5 class="text-body-emphasis fw-bold">{{ car.year }}</h5>
<p class="text-body-emphasis fw-bold">
<a href="{% url 'car_detail' car.slug %}" class="text-decoration-none text-body-emphasis">
{{ car.id_car_make.get_local_name }}
</a>
<small>{{ car.id_car_model.get_local_name }}</small>
</p>
<small class="text-body-secondary" dir="ltr">
{{ car.id_car_trim }}
</small>
</div>
<!-- Color and Date -->
<div class="col-md-3">
<p class="text-body mb-1">
{{ car.colors.exterior.get_local_name }}
</p>
<small class="text-body-secondary">
{{ car.receiving_date|naturalday|capfirst }}
</small>
</div>
<!-- Status Badge -->
<div class="col-md-3">
{% if car.status == "available" %} {% if car.status == "available" %}
<span class="badge badge-phoenix fs-10 badge-phoenix-success text-uppercase px-3 py-2">{{ _("Available") }}</span> <span class="badge badge-phoenix fs-11 badge-phoenix-success">{{ _("Available") }}</span>
{% elif car.status == "reserved" %} {% elif car.status == "reserved" %}
<span class="badge badge-phoenix fs-10 badge-phoenix-warning text-uppercase px-3 py-2">{{ _("Reserved") }}</span> <span class="badge badge-phoenix fs-11 badge-phoenix-danger">{{ _("Reserved") }}</span>
{% elif car.status == "sold" %} {% elif car.status == "sold" %}
<span class="badge badge-phoenix fs-10 badge-phoenix-danger text-uppercase px-3 py-2">{{ _("Sold") }}</span> <span class="badge badge-phoenix fs-11 badge-phoenix-info">{{ _("Sold") }}</span>
{% elif car.status == "transfer" %} {% elif car.status == "transfer" %}
<span class="badge badge-phoenix fs-10 badge-phoenix-info text-uppercase px-3 py-2">{{ _("Transfer") }}</span> <span class="badge badge-phoenix fs-11 badge-phoenix-warning">{{ _("Transfer") }}</span>
{% endif %} {% endif %}
</div> </td>
<td class="align-middle product white-space-nowrap">
<!-- Ready Status --> {% if not car.ready %}
<div class="col-md-2"> <span class="text-danger"> {{ _("NO") }} </span>
<div class="d-flex align-items-center"> {%else%}
<span class="fs-10 fw-light me-2">{{ _("Inventory Ready") }}</span> <span class="text-success"> {{ _("YES") }} </span>
{% if car.ready %} {%endif%}
<span class="badge bg-success rounded-circle p-1 me-2"> </td>
<span class="visually-hidden">Ready</span> <td class="align-middle text-end white-space-nowrap pe-0 action">
</span>
<span class="text-success fw-bold">{{ _("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-bold">{{ _("No") }}</span>
{% endif %}
</div>
</div>
</div>
</div>
<!-- Action Menu -->
<div class="col-auto">
<div class="btn-reveal-trigger position-static"> <div class="btn-reveal-trigger position-static">
<button <button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10"
class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10"
type="button" type="button"
data-bs-toggle="dropdown" data-bs-toggle="dropdown"
data-boundary="window" data-boundary="window"
@ -264,98 +261,89 @@
<span class="fas fa-ellipsis-h fs-10"></span> <span class="fas fa-ellipsis-h fs-10"></span>
</button> </button>
<div class="dropdown-menu dropdown-menu-end py-2"> <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_detail' car.slug %}">{{ _("View") }}</a>
<a class="dropdown-item" href="{% url 'car_update' car.slug %}"> <span class="fas fa-edit me-2"></span>{{ _("Edit") }} </a> <a class="dropdown-item" href="#!">{{ _("Export") }}</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>
</div> </div>
</td>
</tr>
{% endfor %} {% endfor %}
</div> </tbody>
</table>
</div> </div>
<div class="d-flex justify-content-end mt-3"> <div class="d-flex justify-content-end mt-3">
<div class="d-flex"> <div class="d-flex">
{% if is_paginated %} {% include 'partials/pagination.html' %} {% endif %} {% if is_paginated %}
{% include 'partials/pagination.html' %}
{% endif %}
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% block customJS %} {% endblock %}
{% block customJS %}
<script> <script>
links = document.querySelectorAll(".nav-link"); links = document.querySelectorAll('.nav-link')
links.forEach((link) => { links.forEach(link => {
link.addEventListener("click", () => { link.addEventListener('click', () => {
links.forEach((link) => { links.forEach(link => {
link.classList.remove("active"); link.classList.remove('active')
}); })
link.classList.add("active"); link.classList.add('active')
}); })
}); })
function on_before_request() { function on_before_request() {
document.querySelector(".table").classList.toggle("on-before-request"); document.querySelector('.table').classList.toggle('on-before-request')
document.querySelector(".model-select").classList.add("on-after-request"); document.querySelector('.model-select').classList.add('on-after-request')
} }
function on_after_request() { function on_after_request() {
document.querySelector(".table").classList.remove("on-before-request"); document.querySelector('.table').classList.remove('on-before-request')
document.querySelector(".model-select").classList.remove("on-after-request"); document.querySelector('.model-select').classList.remove('on-after-request')
} }
function toggle_filter() { function toggle_filter(){
document.querySelector(".filter").classList.toggle("d-none"); document.querySelector('.filter').classList.toggle('d-none')
document.querySelector(".filter-icon").classList.toggle("fa-caret-down"); document.querySelector('.filter-icon').classList.toggle("fa-caret-down");
document.querySelector(".filter-icon").classList.toggle("fa-caret-up"); document.querySelector('.filter-icon').classList.toggle("fa-caret-up");
} }
function filter_before_request() { function filter_before_request(){
document.querySelector(".model-select").setAttribute("disabled", true); document.querySelector('.model-select').setAttribute('disabled', true)
document.querySelector(".year").setAttribute("disabled", true); document.querySelector('.year').setAttribute('disabled', true)
document.querySelector(".car_status").setAttribute("disabled", true); document.querySelector('.car_status').setAttribute('disabled', true)
} }
function filter_after_request() { function filter_after_request(){
document.querySelector(".model-select").removeAttribute("disabled"); document.querySelector('.model-select').removeAttribute('disabled')
document.querySelector(".year").removeAttribute("disabled"); document.querySelector('.year').removeAttribute('disabled')
document.querySelector(".car_status").removeAttribute("disabled"); document.querySelector('.car_status').removeAttribute('disabled')
} }
document.getElementById("select-all").addEventListener("change", function () { document.getElementById('select-all').addEventListener('change', function() {
const checkboxes = document.querySelectorAll('#project-list-table-body input[type="checkbox"]'); const checkboxes = document.querySelectorAll('#project-list-table-body input[type="checkbox"]');
if (this.checked) { if (this.checked) {
checkboxes.forEach((checkbox) => (checkbox.checked = true)); checkboxes.forEach(checkbox => checkbox.checked = true);
} else { } else {
checkboxes.forEach((checkbox) => (checkbox.checked = false)); checkboxes.forEach(checkbox => checkbox.checked = false);
} }
updateFormVisibility(); updateFormVisibility();
}); });
const cbox = document.querySelectorAll(".car-checkbox"); const cbox = document.querySelectorAll('.car-checkbox');
cbox.forEach((checkbox) => { cbox.forEach(checkbox => {
checkbox.addEventListener("change", function () { checkbox.addEventListener('change', function() {
updateFormVisibility(); updateFormVisibility();
}); });
}); });
function updateFormVisibility() { function updateFormVisibility() {
const form = document.querySelector(".update-price-form"); const form = document.querySelector('.update-price-form');
const checkedCount = document.querySelectorAll(".car-checkbox:checked").length; const checkedCount = document.querySelectorAll('.car-checkbox:checked').length;
const submitButton = form.querySelector('button[type="submit"]'); const submitButton = form.querySelector('button[type="submit"]');
if (checkedCount > 0) { if (checkedCount > 0) {
form.classList.remove("d-none"); form.classList.remove('d-none');
submitButton.textContent = `Update Cost Price (${checkedCount})`; submitButton.textContent = `Update Cost Price (${checkedCount})`;
} else { } else {
form.classList.add("d-none"); form.classList.add('d-none');
} }
} }
</script> </script>
{% endblock customJS %} {% endblock customJS %}
</div>

View File

@ -1,90 +1,64 @@
{% load i18n static %} {% load i18n static %}
<div class="d-flex justify-content-between align-items-center mt-4">
<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"> <nav aria-label="Page navigation">
<ul class="pagination flex items-center justify-center space-x-2 py-4 text-sm"> <ul class="pagination mb-0">
{# First Page Link #} {# First Page Link #}
{% if page_obj.has_previous %} {% if page_obj.has_previous %}
<li class="page-item rounded-md overflow-hidden"> <li class="page-item">
<a class="page-link px-3 py-2 border border-gray-300 bg-white text-blue-600 hover:bg-gray-100 transition-colors duration-200" href="?page=1{% if q %}&q={{q}}{% endif %}" aria-label="{% trans 'First' %}"> <a class="page-link" href="?page=1{% if q %}&q={{q}}{% endif %}">
<span class="fas fa-angle-double-left" aria-hidden="true"></span> <span class="fas fa-angle-double-{% if LANGUAGE_CODE == 'ar' %}right{% else %}left{% endif %}"> </span>
{% if LANGUAGE_CODE == 'ar' %}الأول{% else %}First{% endif %}
</a> </a>
</li> </li>
{% else %} {% else %}
<li class="page-item disabled rounded-md overflow-hidden"> <li class="page-item">
<span class="page-link px-3 py-2 border border-gray-200 bg-gray-50 text-gray-400 cursor-not-allowed"> <span class="page-link">
<span class="fas fa-angle-double-left" aria-hidden="true"></span> <span class="fas fa-chevron-{% if LANGUAGE_CODE == 'ar' %}right{% else %}left{% endif %}"> </span>
{% if LANGUAGE_CODE == 'ar' %}الأول{% else %}First{% endif %}
</span> </span>
</li> </li>
{% endif %} {% endif %}
{# Previous Page Link #} {# Previous Page Link #}
{% if page_obj.has_previous %} {% if page_obj.has_previous %}
<li class="page-item rounded-md overflow-hidden"> <li class="page-item">
<a class="page-link px-3 py-2 border border-gray-300 bg-white text-blue-600 hover:bg-gray-100 transition-colors duration-200" href="?page={{ page_obj.previous_page_number }}{% if q %}&q={{q}}{% endif %}" aria-label="{% trans 'Previous' %}"> <a class="page-link" href="?page={{ page_obj.previous_page_number }}{% if q %}&q={{q}}{% endif %}">
<span class="fas fa-chevron-left" aria-hidden="true"></span> <span class="fas fa-chevron-{% if LANGUAGE_CODE == 'ar' %}right{% else %}left{% endif %}"></span>
<span class="">{% trans 'Previous' %}</span>
</a> </a>
</li> </li>
{% else %}
<li class="page-item disabled rounded-md overflow-hidden">
<span class="page-link px-3 py-2 border border-gray-200 bg-gray-50 text-gray-400 cursor-not-allowed">
<span class="fas fa-chevron-left" aria-hidden="true"></span>
<span class="">{% trans 'Previous' %}</span>
</span>
</li>
{% endif %} {% endif %}
{# Page Numbers #} {# Page Numbers #}
{% for num in page_obj.paginator.page_range %} {% for num in page_obj.paginator.page_range %}
{% if num == 1 or num == page_obj.paginator.num_pages or num >= page_obj.number|add:-2 and num <= page_obj.number|add:2 %} {% if num == 1 or num == page_obj.paginator.num_pages or num >= page_obj.number|add:-2 and num <= page_obj.number|add:2 %}
<li class="page-item rounded-md overflow-hidden {% if num == page_obj.number %}bg-blue-600 text-white shadow-md{% else %}bg-white text-blue-600 hover:bg-gray-100{% endif %}"> <li class="page-item {% if num == page_obj.number %}active{% endif %}">
<a class="page-link block px-3 py-2 border {% if num == page_obj.number %}border-blue-600{% else %}border-gray-300{% endif %} transition-colors duration-200" <a class="page-link" {% if num == page_obj.number %}aria-current="page"{% endif %}
href="?page={{ num }}{% if q %}&q={{q}}{% endif %}"> href="?page={{ num }}{% if q %}&q={{q}}{% endif %}">
{{ num }} {{ num }}
</a> </a>
</li> </li>
{% elif num == page_obj.number|add:-3 or num == page_obj.number|add:3 %}
<li class="page-item disabled rounded-md overflow-hidden">
<span class="page-link px-3 py-2 border border-gray-300 bg-white text-gray-600 cursor-default">...</span>
</li>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{# Next Page Link #} {# Next Page Link #}
{% if page_obj.has_next %} {% if page_obj.has_next %}
<li class="page-item rounded-md overflow-hidden"> <li class="page-item">
<a class="page-link px-3 py-2 border border-gray-300 bg-white text-blue-600 hover:bg-gray-100 transition-colors duration-200" href="?page={{ page_obj.next_page_number }}{% if q %}&q={{q}}{% endif %}" aria-label="{% trans 'Next' %}"> <a class="page-link" href="?page={{ page_obj.next_page_number }}{% if q %}&q={{q}}{% endif %}">
<span class="fas fa-chevron-right" aria-hidden="true"></span> <span class="fas fa-chevron-{% if LANGUAGE_CODE == 'ar' %}left{% else %}right{% endif %}"></span>
<span class="">{% trans 'Next' %}</span>
</a> </a>
</li> </li>
{% else %}
<li class="page-item disabled rounded-md overflow-hidden">
<span class="page-link px-3 py-2 border border-gray-200 bg-gray-50 text-gray-400 cursor-not-allowed">
<span class="fas fa-chevron-right" aria-hidden="true"></span>
<span class="">{% trans 'Next' %}</span>
</span>
</li>
{% endif %} {% endif %}
{# Last Page Link #} {# Last Page Link #}
{% if page_obj.has_next %} {% if page_obj.has_next %}
<li class="page-item rounded-md overflow-hidden"> <li class="page-item">
<a class="page-link px-3 py-2 border border-gray-300 bg-white text-blue-600 hover:bg-gray-100 transition-colors duration-200" href="?page={{ page_obj.paginator.num_pages }}{% if q %}&q={{q}}{% endif %}" aria-label="{% trans 'Last' %}"> <a class="page-link" href="?page={{ page_obj.paginator.num_pages }}{% if q %}&q={{q}}{% endif %}">
<span class="fas fa-angle-double-right" aria-hidden="true"></span> <span class="fas fa-angle-double-{% if LANGUAGE_CODE == 'ar' %}left{% else %}right{% endif %}"></span>
{% if LANGUAGE_CODE == 'ar' %}الأخير{% else %}Last{% endif %}
</a> </a>
</li> </li>
{% else %}
<li class="page-item disabled rounded-md overflow-hidden">
<span class="page-link px-3 py-2 border border-gray-200 bg-gray-50 text-gray-400 cursor-not-allowed">
<span class="fas fa-angle-double-right" aria-hidden="true"></span>
{% if LANGUAGE_CODE == 'ar' %}الأخير{% else %}Last{% endif %}
</span>
</li>
{% endif %} {% endif %}
</ul> </ul>
</nav> </nav>
</div>