rebase with marwan update

This commit is contained in:
ismail 2025-07-23 17:29:32 +03:00
parent 7a1b15bb97
commit fa111b159f
16 changed files with 224 additions and 149 deletions

View File

@ -660,7 +660,7 @@ class Car(Base):
remarks = models.TextField(blank=True, null=True, verbose_name=_("Remarks"))
mileage = models.IntegerField(blank=True, null=True, verbose_name=_("Mileage"))
receiving_date = models.DateTimeField(verbose_name=_("Receiving Date"))
sold_date=models.DateTimeField(verbose_name=_("Sold Date"))
sold_date=models.DateTimeField(verbose_name=_("Sold Date"),null=True,blank=True)
hash = models.CharField(
max_length=64, blank=True, null=True, verbose_name=_("Hash")
)
@ -3361,9 +3361,9 @@ class ExtraInfo(models.Model):
)
# qs = qs.select_related("customer","estimate","invoice")
data = SaleOrder.objects.filter(pk__in=[x.content_object.sale_orders.select_related("customer","estimate","invoice").first().pk for x in qs if x.content_object.sale_orders.first()])
return data
# return [
# x.content_object.sale_orders.select_related(
# "customer", "estimate", "invoice"

View File

@ -1251,7 +1251,7 @@ urlpatterns = [
name="po-action-mark-as-void",
),
# reports
# reports
path(
"<slug:dealer_slug>/purchase-report/",
views.purchase_report_view,

View File

@ -1494,7 +1494,7 @@ class CarFinanceCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateVi
form_class = forms.CarFinanceForm
template_name = "inventory/car_finance_form.html"
permission_required = ["inventory.add_carfinance"]
def dispatch(self, request, *args, **kwargs):
self.car = get_object_or_404(models.Car, slug=self.kwargs["slug"])
return super().dispatch(request, *args, **kwargs)
@ -4320,8 +4320,8 @@ def sales_list_view(request, dealer_slug):
item transactions specific to the user's entity.
:rtype: HttpResponse
"""
dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
staff = getattr(request.user.staffmember, "staff", None)
qs = []
try:
@ -4459,9 +4459,9 @@ class EstimateListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
if search_query:
print("inside")
queryset = queryset.filter(
Q(estimate_number__icontains=search_query)
Q(estimate_number__icontains=search_query)
).distinct()
).distinct()
return queryset
@ -6104,6 +6104,7 @@ def update_lead_actions(request, dealer_slug):
current_action = request.POST.get("current_action")
next_action = request.POST.get("next_action")
next_action_date = request.POST.get("next_action_date", None)
lead = models.Lead.objects.get(id=lead_id)
if not all([lead_id, current_action, next_action]):
# Log for missing required fields
@ -6111,12 +6112,17 @@ def update_lead_actions(request, dealer_slug):
f"User {user_username} submitted incomplete data to update lead actions "
f"for dealer '{dealer_slug}'. Missing fields: lead_id='{lead_id}', current_action='{current_action}', next_action='{next_action}'."
)
return JsonResponse(
{"success": False, "message": "All fields are required"}, status=400
messages.error(
request,
_("All fields are required")
)
return redirect("lead_detail", dealer_slug=dealer_slug, slug=lead.slug)
# return JsonResponse(
# {"success": False, "message": "All fields are required"}, status=400
# )
# Get the lead
lead = models.Lead.objects.get(id=lead_id)
# Update lead fields
@ -6146,9 +6152,14 @@ def update_lead_actions(request, dealer_slug):
f"submitted invalid date format ('{next_action_date}') "
f"for Lead ID: {lead.pk}. Error: {ve}"
)
return JsonResponse(
{"success": False, "message": "Invalid date format"}, status=400
messages.error(
request,
_("Invalid date format")
)
return redirect("lead_detail", dealer_slug=dealer_slug, slug=lead.slug)
# return JsonResponse(
# {"success": False, "message": "Invalid date format"}, status=400
# )
# Save the lead
lead.save()
# --- Logging for successful update (main try block success) ---
@ -6156,9 +6167,14 @@ def update_lead_actions(request, dealer_slug):
f"User {user_username} successfully updated Lead ID: {lead.pk} ('{lead.slug}'). "
f"New Status: '{lead.status}', Next Action: '{lead.next_action}', Next Action Date: '{lead.next_action_date}'."
)
return JsonResponse(
{"success": True, "message": "Actions updated successfully"}
messages.success(
request,
_("Actions updated successfully")
)
return redirect("lead_detail", dealer_slug=dealer_slug, slug=lead.slug)
# return JsonResponse(
# {"success": True, "message": "Actions updated successfully"}
# )
except models.Lead.DoesNotExist:
# --- Logging for Lead not found ---
@ -6166,7 +6182,12 @@ def update_lead_actions(request, dealer_slug):
f"User {user_username} attempted to update non-existent Lead with ID: '{lead_id}' "
f"for dealer '{dealer_slug}'. Returning 404."
)
return JsonResponse({"success": False, "message": "Lead not found"}, status=404)
messages.error(
request,
_("Lead not found")
)
return redirect("lead_detail", dealer_slug=dealer_slug, slug=lead.slug)
# return JsonResponse({"success": False, "message": "Lead not found"}, status=404)
except Exception as e:
involved_lead_id = request.POST.get("lead_id", "N/A")
logger.error(
@ -6174,7 +6195,12 @@ def update_lead_actions(request, dealer_slug):
f"for dealer '{dealer_slug}'. Error: {e}",
exc_info=True, # CRUCIAL: Includes the full traceback
)
return JsonResponse({"success": False, "message": str(e)}, status=500)
messages.error(
request,
_("An error occurred while updating lead actions")
)
return redirect("lead_detail", dealer_slug=dealer_slug, slug=lead.slug)
# return JsonResponse({"success": False, "message": str(e)}, status=500)
class LeadUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
@ -6558,7 +6584,7 @@ def lead_transfer(request, dealer_slug, slug):
messages.success(request, _("Lead transferred successfully"))
else:
messages.error(request, f"Invalid form data: {str(form.errors)}")
return redirect("lead_list", dealer_slug=dealer.slug)
return redirect("lead_detail", dealer_slug=dealer.slug ,slug=lead.slug)
@login_required
@ -10399,7 +10425,7 @@ def upload_cars(request, dealer_slug, pk=None):
form = forms.CSVUploadForm()
form.fields["vendor"].queryset = dealer.vendors.all()
print(request)
return render(
request,
"csv_upload.html",
@ -10451,16 +10477,16 @@ def purchase_report_view(request,dealer_slug):
pos = request.entity.get_purchase_orders()
data = []
total_po_amount=0
total_po_cars=0
total_po_cars=0
for po in pos:
items = [{"total":x.total_amount,"q":x.quantity} for x in po.get_itemtxs_data()[0].all()]
po_amount=0
po_quantity=0
for item in items:
po_amount+=item["total"]
po_quantity+=item["q"]
total_po_amount+=po_amount
total_po_cars+=po_quantity
bills=po.get_po_bill_queryset()
@ -10468,7 +10494,7 @@ def purchase_report_view(request,dealer_slug):
vendors_str = ", ".join(sorted(list(vendors))) if vendors else "N/A"
data.append({"po_number":po.po_number,"po_created":po.created,"po_status":po.po_status,"po_fulfilled_date":po.date_fulfilled,"po_amount":po_amount,
"po_quantity":po_quantity,"vendors_str":vendors_str})
current_time = timezone.now().strftime("%Y-%m-%d %H:%M:%S")
context={
"dealer":request.entity.name,
@ -10479,23 +10505,23 @@ def purchase_report_view(request,dealer_slug):
"current_time":current_time
}
return render(request,'ledger/reports/purchase_report.html',context)
def purchase_report_csv_export(request,dealer_slug):
response = HttpResponse(content_type='text/csv')
current_time = timezone.now().strftime("%Y-%m-%d_%H%M%S")
filename = f"purchase_report_{dealer_slug}_{current_time}.csv"
response['Content-Disposition'] = f'attachment; filename="{filename}"'
writer = csv.writer(response)
header = [
'PO Number',
'Created Date',
@ -10507,7 +10533,7 @@ def purchase_report_csv_export(request,dealer_slug):
]
writer.writerow(header)
pos = request.entity.get_purchase_orders()
for po in pos:
po_amount = 0
po_quantity = 0
@ -10516,10 +10542,10 @@ def purchase_report_csv_export(request,dealer_slug):
for item in items:
po_amount += item["total"]
po_quantity += item["q"]
bills = po.get_po_bill_queryset()
vendors = set([bill.vendor.vendor_name for bill in bills ])
vendors_str = ", ".join(sorted(list(vendors))) if vendors else "N/A"
vendors_str = ", ".join(sorted(list(vendors))) if vendors else "N/A"
writer.writerow([
@ -10527,7 +10553,7 @@ def purchase_report_csv_export(request,dealer_slug):
po.created.strftime("%Y-%m-%d %H:%M:%S") if po.created else '',
po.get_po_status_display(),
po.date_fulfilled.strftime("%Y-%m-%d") if po.date_fulfilled else '',
f"{po_amount:.2f}",
f"{po_amount:.2f}",
po_quantity,
vendors_str
])
@ -10540,13 +10566,13 @@ def car_sale_report_view(request,dealer_slug):
current_time = timezone.now().strftime("%Y-%m-%d %H:%M:%S")
context={'cars_sold':cars_sold,'current_time':current_time }
return render(request,'ledger/reports/car_sale_report.html',context)
def car_sale_report_csv_export(request,dealer_slug):
response = HttpResponse(content_type='text/csv')
current_time = timezone.now().strftime("%Y-%m-%d %H:%M:%S")
filename = f"sales_report_{dealer_slug}_{current_time}.csv"
response['Content-Disposition'] = f'attachment; filename="{filename}"'
@ -10555,7 +10581,7 @@ def car_sale_report_csv_export(request,dealer_slug):
header=[
'Make',
'VIN',
'VIN',
'Model',
'Year',
'Serie',
@ -10572,16 +10598,16 @@ def car_sale_report_csv_export(request,dealer_slug):
'Invoice Number',
]
writer.writerow(header)
dealer=get_object_or_404(models.Dealer,slug=dealer_slug)
cars_sold=models.Car.objects.filter(dealer=dealer,status='sold')
for car in cars_sold:
writer.writerow([
car.vin,
car.vin,
car.id_car_make.name,
car.id_car_model.name,
car.year,
car.id_car_serie.name,
car.id_car_serie.name,
car.id_car_trim.name,
car.mileage,
car.stock_type,
@ -10595,5 +10621,4 @@ def car_sale_report_csv_export(request,dealer_slug):
car.item_model.invoicemodel_set.first().invoice_number
])
return response
return response

View File

@ -132,3 +132,45 @@ html[dir="rtl"] .form-icon-container .form-control {
to { transform: rotate(360deg); }
}
#spinner {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 10;
}
#spinner-bg {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(255, 255, 255, 0.7);
opacity: 0;
transition: opacity 500ms ease-in;
z-index: 5;
}
#spinner-bg.htmx-request {
opacity: .8;
}
/* .fade-me-in.htmx-added {
opacity: 0;
}
.fade-me-in {
opacity: .9;
transition: opacity 300ms ease-out;
} */
#main_content.fade-me-in:not(.modal):not(.modal *) {
opacity: 1;
transition: opacity 300ms ease-out;
}
#main_content.fade-me-in.htmx-added:not(.modal):not(.modal *) {
opacity: 0;
}

1
static/spinner.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200'><rect fill='#09577F' stroke='#09577F' stroke-width='15' width='30' height='30' x='25' y='85'><animate attributeName='opacity' calcMode='spline' dur='2' values='1;0;1;' keySplines='.5 0 .5 1;.5 0 .5 1' repeatCount='indefinite' begin='-.4'></animate></rect><rect fill='#09577F' stroke='#09577F' stroke-width='15' width='30' height='30' x='85' y='85'><animate attributeName='opacity' calcMode='spline' dur='2' values='1;0;1;' keySplines='.5 0 .5 1;.5 0 .5 1' repeatCount='indefinite' begin='-.2'></animate></rect><rect fill='#09577F' stroke='#09577F' stroke-width='15' width='30' height='30' x='145' y='85'><animate attributeName='opacity' calcMode='spline' dur='2' values='1;0;1;' keySplines='.5 0 .5 1;.5 0 .5 1' repeatCount='indefinite' begin='0'></animate></rect></svg>

View File

@ -13,7 +13,7 @@
<p class="text-body-tertiary">{{ _("Are you sure you want to sign out?") }}</p>
</div>
<div class="d-grid">
<form method="post" action="{% url 'account_logout' %}">
<form hx-boost="false" method="post" action="{% url 'account_logout' %}">
{% csrf_token %}
{{ redirect_field }}
<div class="d-grid gap-2 mt-3">

View File

@ -69,7 +69,7 @@
<script src="{% static 'js/main.js' %}"></script>
<script src="{% static 'js/jquery.min.js' %}"></script>
{% comment %} <script src="{% static 'js/echarts.js' %}"></script> {% endcomment %}
{% block customCSS %}{% endblock %}
{% comment %} {% block customCSS %}{% endblock %} {% endcomment %}
</head>
<body hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'>
{% include "toast-alert.html" %}
@ -81,10 +81,20 @@
{% include "plans/expiration_messages.html" %}
{% block period_navigation %}
{% endblock period_navigation %}
<div id="main_content" hx-boost="true" hx-target="#main_content" hx-select="#main_content" hx-swap="outerHTML" hx-select-oob="#toast-container" hx-history-elt>
{% block content %}
{% endblock content %}
<script src="{% static 'vendors/popper/popper.min.js' %}"></script>
<div id="main_content" class="fade-me-in" hx-boost="true" hx-target="#main_content" hx-select="#main_content" hx-swap="outerHTML transition:false" hx-select-oob="#toast-container" hx-history-elt>
<div id="spinner" class="htmx-indicator spinner-bg">
<img src="{% static 'spinner.svg' %}" width="100" height="100" alt="">
</div>
{% block customCSS %}{% endblock %}
{% block content %}{% endblock content %}
{% block customJS %}{% endblock %}
{% comment %} <script src="{% static 'vendors/feather-icons/feather.min.js' %}"></script>
<script src="{% static 'vendors/fontawesome/all.min.js' %}"></script>
<script src="{% static 'vendors/popper/popper.min.js' %}"></script>
<script src="{% static 'vendors/bootstrap/bootstrap.min.js' %}"></script>
<script src="{% static 'js/phoenix.js' %}"></script> {% endcomment %}
</div>
{% block body %}
{% endblock body %}
@ -136,7 +146,16 @@
let datePickers = document.querySelectorAll("[id^='djl-datepicker']")
datePickers.forEach(dp => djLedger.getCalendar(dp.attributes.id.value, dateNavigationUrl))
{% endif %}
/*document.body.addEventListener('htmx:configRequest', function(evt) {
evt.detail.indicators = [
...(evt.detail.indicators || []),
document.getElementById('global-indicator')
];
});*/
</script>
{% block customJS %}{% endblock %}
{% comment %} {% block customJS %}{% endblock %} {% endcomment %}
</body>
</html>

View File

@ -1,16 +1,16 @@
{% load i18n crispy_forms_tags %}
<div class="modal fade" id="emailModal" tabindex="-1" aria-labelledby="emailModalLabel" aria-hidden="true">
<div class="modal-dialog modal-xl">
<div class="modal-content">
<div class="modal-header justify-content-between align-items-start gap-5 px-4 pt-4 pb-3 border-0">
<h4 class="modal-title" id="emailModalLabel">{% trans 'Send Email' %}</h4>
<button class="btn p-0 text-body-quaternary fs-6" data-bs-dismiss="modal" aria-label="Close">
<span class="fas fa-times"></span>
</button>
</div>
<div id="emailModalBody" class="modal-body">
<h1>hi</h1>
</div>
</div>
</div>
</div>
<div class="modal-dialog modal-xl">
<div class="modal-content">
<div class="modal-header justify-content-between align-items-start gap-5 px-4 pt-4 pb-3 border-0">
<h4 class="modal-title" id="emailModalLabel">{% trans 'Send Email' %}</h4>
<button class="btn p-0 text-body-quaternary fs-6" data-bs-dismiss="modal" aria-label="Close">
<span class="fas fa-times"></span>
</button>
</div>
<div id="emailModalBody" class="modal-body">
<h1>hi</h1>
</div>
</div>
</div>
</div>

View File

@ -16,6 +16,13 @@
</div>
<div class="modal-body">
<form action="{% url 'add_note' request.dealer.slug content_type slug %}"
hx-select="#notesTable"
hx-target="#notesTable"
hx-on::after-request="{
resetSubmitButton(document.querySelector('.add_note_form button[type=submit]'));
$('#noteModal').modal('hide');
}"
hx-swap="outerHTML"
method="post"
class="add_note_form">
{% csrf_token %}
@ -33,5 +40,6 @@
document.querySelector('#id_note').value = note
let form = document.querySelector('.add_note_form')
form.action = url
}
</script>

View File

@ -23,6 +23,12 @@
</div>
<div class="modal-body">
<form action="{% url 'add_task' request.dealer.slug content_type slug %}"
hx-select=".taskTable"
hx-target=".taskTable"
hx-on::after-request="{
resetSubmitButton(document.querySelector('.add_task_form button[type=submit]'));
$('#taskModal').modal('hide');
}"
method="post"
class="add_task_form">
{% csrf_token %}

View File

@ -28,6 +28,7 @@
border-bottom: 28px solid transparent;
border-left: 20px solid #dee2e6;
}
</style>
{% endblock customCSS %}
{% block content %}
@ -68,7 +69,7 @@
<p>{{ lead.email|capfirst }}</p>
</div>
<div class="col-6 col-sm-auto flex-1">
<h5 class="text-body-highlight mb-0 text-end">
<h5 id="leadStatus" class="text-body-highlight mb-0 text-end">
{{ _("Status") }}
{% if lead.status == "new" %}
<span class="badge badge-phoenix badge-phoenix-primary"><span class="badge-label">{{ _("New") }}</span><span class="fa fa-bell ms-1"></span></span>
@ -103,7 +104,7 @@
</div>
<div class="card mb-2">
<div class="card-body">
<div class="row align-items-center g-3 text-center text-xxl-start">
<div id="assignedTo" class="row align-items-center g-3 text-center text-xxl-start">
<div class="col-6 col-sm-auto d-flex flex-column align-items-center text-center">
<h5 class="fw-bolder mb-2 text-body-highlight">{{ _("Assigned To") }}</h5>
<div class="d-flex align-items-center">
@ -219,7 +220,7 @@
</div>
</div>
<div class="col-md-7 col-lg-7 col-xl-8">
<div class="d-flex w-100 gap-5">
<div id="currentStage" class="d-flex w-100 gap-5">
<div class="kanban-header bg-success w-50 text-white fw-bold">
<i class="fa-solid fa-circle-check me-2"></i>{{ lead.status|capfirst }}
<br>
@ -303,6 +304,11 @@
<div class="modal-content">
<form class="modal-content"
action="{% url 'lead_transfer' request.dealer.slug lead.slug %}"
hx-select-oob="#assignedTo:outerHTML,#toast-container:outerHTML"
hx-swap="none"
hx-on::after-request="{
resetSubmitButton(document.querySelector('#exampleModal button[type=submit]'));
$('#exampleModal').modal('hide');}"
method="post">
{% csrf_token %}
<div class="modal-header">
@ -471,7 +477,7 @@
<th class="align-middle pe-0 text-end" scope="col" style="width:10%;"></th>
</tr>
</thead>
<tbody>
<tbody id="notesTable">
{% for note in notes %}
<tr class="hover-actions-trigger btn-reveal-trigger position-static">
<td class="align-middle text-start fw-bold text-body-tertiary ps-1">{{ note.note }}</td>
@ -793,7 +799,7 @@
style="min-width:100px">Completed</th>
</tr>
</thead>
<tbody class="list" id="all-tasks-table-body">
<tbody class="list taskTable" id="all-tasks-table-body">
{% for task in schedules %}
{% include "partials/task.html" %}
{% endfor %}
@ -862,7 +868,9 @@
{% endif %}
function openActionModal(leadId, currentAction, nextAction, nextActionDate) {
const modal = new bootstrap.Modal(document.getElementById('actionTrackingModal'));
const modal = new bootstrap.Modal(document.getElementById('actionTrackingModal'));
document.getElementById('actionTrackingForm').setAttribute('hx-boost', 'false');
document.getElementById('leadId').value = leadId;
document.getElementById('currentAction').value = currentAction;
document.getElementById('nextAction').value = nextAction;
@ -870,7 +878,7 @@
modal.show();
}
document.getElementById('actionTrackingForm').addEventListener('submit', function(e) {
/*document.getElementById('actionTrackingForm').addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
@ -951,7 +959,7 @@
}
});
});
});
});*/
// Helper function for notifications
function notify(tag, msg) {
@ -961,5 +969,25 @@
});
}
</script>
{% endblock customJS %}
// Close modal after successful form submission
document.body.addEventListener('htmx:afterSwap', function(evt) {
if (evt.detail.target.id === 'main_content') {
var modal = bootstrap.Modal.getInstance(document.getElementById('exampleModal'));
if (modal) {
modal.hide();
}
}
});
// Cleanup modal backdrop if needed
document.body.addEventListener('htmx:beforeSwap', function(evt) {
if (evt.detail.target.id === 'main_content') {
var backdrops = document.querySelectorAll('.modal-backdrop');
backdrops.forEach(function(backdrop) {
backdrop.remove();
});
}
});
</script>
{% endblock customJS %}

View File

@ -239,10 +239,6 @@
class="dropdown-item text-success-dark">{% trans "Edit" %}</a>
{% endif %}
{% if perms.inventory.change_lead %}
<button class="dropdown-item text-primary"
onclick="openActionModal('{{ lead.pk }}', '{{ lead.action }}', '{{ lead.next_action }}', '{{ lead.next_action_date|date:"Y-m-d\TH:i" }}')">
{% trans "Update Actions" %}
</button>
{% endif %}
{% if not lead.opportunity %}
{% if perms.inventory.add_opportunity %}
@ -335,69 +331,7 @@
}
});
fetch("{% url 'update_lead_actions' request.dealer.slug %}", {
method: 'POST',
body: formData,
headers: {
'X-CSRFToken': '{{ csrf_token }}'
}
})
.then(response => response.json())
.then(data => {
Swal.close();
if (data.success) {
// Success notification
Swal.fire({
toast: true,
icon: 'success',
position: "top-end",
text: data.message || 'Actions updated successfully',
showConfirmButton: false,
timer: 2000,
timerProgressBar: false,
didOpen: (toast) => {
toast.onmouseenter = Swal.stopTimer;
toast.onmouseleave = Swal.resumeTimer;
}
}).then(() => {
location.reload(); // Refresh after user clicks OK
});
} else {
// Error notification
Swal.fire({
toast: true,
icon: 'error',
position: "top-end",
text: data.message || 'Failed to update actions',
showConfirmButton: false,
timer: 2000,
timerProgressBar: false,
didOpen: (toast) => {
toast.onmouseenter = Swal.stopTimer;
toast.onmouseleave = Swal.resumeTimer;
}
});
}
})
.catch(error => {
Swal.close();
console.error('Error:', error);
Swal.fire({
toast: true,
icon: 'error',
position: "top-end",
text: 'An unexpected error occurred',
showConfirmButton: false,
timer: 2000,
timerProgressBar: false,
didOpen: (toast) => {
toast.onmouseenter = Swal.stopTimer;
toast.onmouseleave = Swal.resumeTimer;
}
});
});
});
// Helper function for notifications
function notify(tag, msg) {
Toast.fire({

View File

@ -12,7 +12,15 @@
data-bs-dismiss="modal"
aria-label="Close"></button>
</div>
<form id="actionTrackingForm" method="post">
<form id="actionTrackingForm"
action="{% url 'update_lead_actions' lead.dealer.slug %}"
hx-select-oob="#currentStage:outerHTML,#leadStatus:outerHTML,#toast-container:outerHTML"
hx-swap="none"
hx-on::after-request="{
resetSubmitButton(document.querySelector('#actionTrackingForm button[type=submit]'));
$('#actionTrackingModal').modal('hide');
}"
method="post">
<div class="modal-body">
{% csrf_token %}
<input type="hidden" id="leadId" name="lead_id">

View File

@ -3,7 +3,7 @@
<nav class="navbar navbar-vertical navbar-expand-lg ">
<div class="collapse navbar-collapse" id="navbarVerticalCollapse">
<div class="navbar-vertical-content d-flex flex-column">
<ul class="navbar-nav flex-column" id="navbarVerticalNav" hx-boost="true" hx-target="#main_content" hx-select="#main_content" hx-swap="outerHTML" hx-select-oob="#toast-container">
<ul class="navbar-nav flex-column" id="navbarVerticalNav" hx-boost="true" hx-target="#main_content" hx-select="#main_content" hx-swap="outerHTML" hx-select-oob="#toast-container" hx-indicator="#spinner">
<li class="nav-item">
<p class="navbar-vertical-label text-primary fs-8 text-truncate">{{request.dealer|default:"Apps"}}</p>
<hr class="navbar-vertical-line" />
@ -366,7 +366,7 @@
<i class="fas fa-car"></i><span class="nav-link-text">{% trans 'Car Sale Report'|capfirst %}</span>
</div>
</a>
</li>
</ul>
</div>
@ -375,11 +375,11 @@
</li>
</ul>
{# --- Support & Contact Section (New) --- #}
<div class="mt-auto bg-info-subtle">
<div class="mt-auto bg-info-subtle">
<ul class="navbar-nav flex-column">
<li class="nav-item">
<a class="nav-link" href="#">
<a class="nav-link" href="#">
<div class="d-flex align-items-center">
<span class="nav-link-icon"><span class="fas fa-headphones"></span></span>
<span class="nav-link-text">{% trans 'Haikal Support'|capfirst %}</span>
@ -387,7 +387,7 @@
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">
<a class="nav-link" href="#">
<div class="d-flex align-items-center">
<span class="nav-link-icon"><span class="fas fa-phone"></span></span>
<span class="nav-link-text">{% trans 'Haikal Contact'|capfirst %}</span>
@ -396,7 +396,7 @@
</li>
<li class="nav-item">
<a class="nav-link" href="#">
<a class="nav-link" href="#">
<div class="d-flex align-items-center">
<span class="nav-link-icon"><span class="fas fa-robot"></span></span>
<span class="nav-link-text">{% trans 'Haikal Bot'|capfirst %}</span>

View File

@ -34,7 +34,7 @@
{% endif %}
<!---->
<div class="row justify-content-center mt-5 mb-3
{% if not vendor_exists %}disabled{% endif %}">
{% if not vendor_exists %}disabled{% endif %}" hx-boost="false">
<div class="col-lg-8 col-md-10">
<div class="card shadow-sm border-0 rounded-3">
<div class="card-header bg-gray-200 py-3 border-0 rounded-top-3">

View File

@ -43,6 +43,10 @@
let deleteMessage = this.getAttribute("data-message");
confirmDeleteBtn.setAttribute("href", deleteUrl);
confirmDeleteBtn.setAttribute("hx-boost", "true");
confirmDeleteBtn.setAttribute("hx-select-oob", "#notesTable:outerHTML,#toast-container:outerHTML");
confirmDeleteBtn.setAttribute("hx-swap", "none");
confirmDeleteBtn.setAttribute("hx-on::after-request", "$('#deleteModal').modal('hide');");
deleteModalMessage.innerHTML = deleteMessage;
});
});