update on the lead & opportunity

This commit is contained in:
ismail 2025-05-15 19:29:22 +03:00
parent cca37be3b3
commit 2ee9a86720
223 changed files with 15974 additions and 15114 deletions

10
.prettierrc Normal file
View File

@ -0,0 +1,10 @@
{
"printWidth": 80,
"tabWidth": 4,
"useTabs": false,
"semi": true,
"singleQuote": true,
"trailingComma": "es5",
"bracketSpacing": true,
"arrowParens": "always"
}

View File

@ -50,7 +50,8 @@ from .models import (
CarMake, CarMake,
Customer, Customer,
Organization, Organization,
DealerSettings DealerSettings,
Tasks
) )
from django_ledger import models as ledger_models from django_ledger import models as ledger_models
from django.forms import ( from django.forms import (
@ -1120,6 +1121,7 @@ class ActivityForm(forms.ModelForm):
associated with the form and the fields it comprises. associated with the form and the fields it comprises.
:type Meta: type :type Meta: type
""" """
activity_type = forms.ChoiceField(choices=[("call", "Call"), ("email", "Email"), ("meeting", "Meeting")])
class Meta: class Meta:
model = Activity model = Activity
fields = ["activity_type", "notes"] fields = ["activity_type", "notes"]
@ -1140,9 +1142,34 @@ class OpportunityForm(forms.ModelForm):
:ivar Meta.fields: List of fields from the model included in the form. :ivar Meta.fields: List of fields from the model included in the form.
:type Meta.fields: list :type Meta.fields: list
""" """
closing_date = forms.DateField(
label=_("Expected Closing Date"),
widget=forms.DateInput(attrs={"type": "date"})
)
probability = forms.IntegerField(
label=_("Probability (%)"),
widget=forms.NumberInput(attrs={
'type': 'range',
'min': '0',
'max': '100',
'step': '1',
'class': 'form-range',
'oninput': 'this.nextElementSibling.value = this.value'
}),
initial=50 # Default value
)
class Meta: class Meta:
model = Opportunity model = Opportunity
fields = ["customer", "car", "stage", "probability", "staff", "closing_date"] fields = ["lead", "car", "stage", "probability", "expected_revenue", "closing_date"]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Add a visible number input to display the current value
self.fields['probability'].widget.attrs['class'] = 'd-none' # Hide the default input
if self.instance and self.instance.pk:
self.fields['probability'].initial = self.instance.probability
class InvoiceModelCreateForm(InvoiceModelCreateFormBase): class InvoiceModelCreateForm(InvoiceModelCreateFormBase):
@ -1684,3 +1711,33 @@ class PaymentPlanForm(forms.Form):
self.fields['first_name'].initial = user.first_name self.fields['first_name'].initial = user.first_name
self.fields['last_name'].initial = user.last_name self.fields['last_name'].initial = user.last_name
self.fields['email'].initial = user.email self.fields['email'].initial = user.email
# class ActivityHistoryForm(forms.Form):
# activity_type = forms.ChoiceField(
# choices=[
# ('note', 'Note'),
# ('call', 'Call'),
# ('email', 'Email'),
# ('meeting', 'Meeting'),],
# widget=forms.Select(attrs={
# 'class': 'form-control',
# 'id': 'activity-type'
# }),
# label=_('Activity Type')
# )
# description = forms.CharField(
# widget=forms.Textarea(attrs={
# 'class': 'form-control',
# 'id': 'activity-description'
# }),
# label=_('Description')
# )
class StaffTaskForm(forms.ModelForm):
class Meta:
model = Tasks
fields = ['title','due_date' ,'description']
widgets = {
'due_date': forms.DateTimeInput(attrs={'type': 'date'}),
}

View File

@ -0,0 +1,44 @@
# Generated by Django 5.1.7 on 2025-05-13 15:19
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('contenttypes', '0002_remove_content_type_name'),
('inventory', '0017_alter_activity_activity_type'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.RemoveField(
model_name='opportunity',
name='closed',
),
migrations.RemoveField(
model_name='opportunity',
name='status',
),
migrations.CreateModel(
name='Tasks',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('object_id', models.UUIDField()),
('title', models.CharField(max_length=255, verbose_name='Title')),
('description', models.TextField(blank=True, null=True, verbose_name='Description')),
('due_date', models.DateField(verbose_name='Due Date')),
('created', models.DateTimeField(auto_now_add=True, verbose_name='Created')),
('updated', models.DateTimeField(auto_now=True, verbose_name='Updated')),
('assigned_to', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='tasks_assigned', to=settings.AUTH_USER_MODEL)),
('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype')),
('created_by', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='tasks_created', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'Task',
'verbose_name_plural': 'Tasks',
},
),
]

View File

@ -0,0 +1,20 @@
# Generated by Django 5.1.7 on 2025-05-13 16:22
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0018_remove_opportunity_closed_remove_opportunity_status_and_more'),
]
operations = [
migrations.AddField(
model_name='tasks',
name='dealer',
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, related_name='tasks', to='inventory.dealer'),
preserve_default=False,
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 5.1.7 on 2025-05-13 16:57
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0019_tasks_dealer'),
]
operations = [
migrations.AddField(
model_name='tasks',
name='completed',
field=models.BooleanField(default=False, verbose_name='Completed'),
),
]

View File

@ -0,0 +1,28 @@
# Generated by Django 5.1.7 on 2025-05-14 10:29
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0020_tasks_completed'),
]
operations = [
migrations.AlterField(
model_name='lead',
name='status',
field=models.CharField(choices=[('new', 'New'), ('follow_up', 'Follow-up'), ('negotiation', 'Negotiation'), ('won', 'Won'), ('lost', 'Lost'), ('closed', 'Closed')], db_index=True, default='new', max_length=50, verbose_name='Status'),
),
migrations.AlterField(
model_name='leadstatushistory',
name='new_status',
field=models.CharField(choices=[('new', 'New'), ('follow_up', 'Follow-up'), ('negotiation', 'Negotiation'), ('won', 'Won'), ('lost', 'Lost'), ('closed', 'Closed')], max_length=50, verbose_name='New Status'),
),
migrations.AlterField(
model_name='leadstatushistory',
name='old_status',
field=models.CharField(choices=[('new', 'New'), ('follow_up', 'Follow-up'), ('negotiation', 'Negotiation'), ('won', 'Won'), ('lost', 'Lost'), ('closed', 'Closed')], max_length=50, verbose_name='Old Status'),
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 5.1.7 on 2025-05-14 10:41
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0021_alter_lead_status_alter_leadstatushistory_new_status_and_more'),
]
operations = [
migrations.AddField(
model_name='opportunity',
name='expected_revenue',
field=models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='Expected Revenue'),
preserve_default=False,
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 5.1.7 on 2025-05-14 10:58
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0022_opportunity_expected_revenue'),
]
operations = [
migrations.AlterField(
model_name='opportunity',
name='stage',
field=models.CharField(choices=[('discovery', 'Discovery'), ('proposal', 'Proposal'), ('negotiation', 'Negotiation'), ('closed_won', 'Closed Won'), ('closed_lost', 'Closed Lost')], max_length=20, verbose_name='Stage'),
),
]

View File

@ -0,0 +1,20 @@
# Generated by Django 5.1.7 on 2025-05-14 10:59
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('django_ledger', '0021_alter_bankaccountmodel_account_model_and_more'),
('inventory', '0023_alter_opportunity_stage'),
]
operations = [
migrations.AlterField(
model_name='opportunity',
name='customer',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='opportunities', to='django_ledger.customermodel'),
),
]

View File

@ -973,9 +973,9 @@ class Channel(models.TextChoices):
class Status(models.TextChoices): class Status(models.TextChoices):
NEW = "new", _("New") NEW = "new", _("New")
FOLLOW_UP = "follow_up", _("Needs Follow-up") FOLLOW_UP = "follow_up", _("Follow-up")
NEGOTIATION = "negotiation", _("Under Negotiation") NEGOTIATION = "negotiation", _("Negotiation")
WON = "won", _("Converted") WON = "won", _("Won")
LOST = "lost", _("Lost") LOST = "lost", _("Lost")
CLOSED = "closed", _("Closed") CLOSED = "closed", _("Closed")
@ -1020,7 +1020,7 @@ class ActionChoices(models.TextChoices):
class Stage(models.TextChoices): class Stage(models.TextChoices):
PROSPECT = "prospect", _("Prospect") DISCOVERY = "discovery", _("Discovery")
PROPOSAL = "proposal", _("Proposal") PROPOSAL = "proposal", _("Proposal")
NEGOTIATION = "negotiation", _("Negotiation") NEGOTIATION = "negotiation", _("Negotiation")
CLOSED_WON = "closed_won", _("Closed Won") CLOSED_WON = "closed_won", _("Closed Won")
@ -1515,7 +1515,7 @@ class Opportunity(models.Model):
Dealer, on_delete=models.CASCADE, related_name="opportunities" Dealer, on_delete=models.CASCADE, related_name="opportunities"
) )
customer = models.ForeignKey( customer = models.ForeignKey(
CustomerModel, on_delete=models.CASCADE, related_name="opportunities" CustomerModel, on_delete=models.CASCADE, related_name="opportunities",null=True,blank=True
) )
car = models.ForeignKey( car = models.ForeignKey(
Car, on_delete=models.SET_NULL, null=True, blank=True, verbose_name=_("Car") Car, on_delete=models.SET_NULL, null=True, blank=True, verbose_name=_("Car")
@ -1523,12 +1523,6 @@ class Opportunity(models.Model):
stage = models.CharField( stage = models.CharField(
max_length=20, choices=Stage.choices, verbose_name=_("Stage") max_length=20, choices=Stage.choices, verbose_name=_("Stage")
) )
status = models.CharField(
max_length=20,
choices=Status.choices,
verbose_name=_("Status"),
default=Status.NEW,
)
staff = models.ForeignKey( staff = models.ForeignKey(
Staff, Staff,
on_delete=models.SET_NULL, on_delete=models.SET_NULL,
@ -1538,10 +1532,12 @@ class Opportunity(models.Model):
) )
lead = models.OneToOneField("Lead",related_name="opportunity", on_delete=models.CASCADE,null=True,blank=True) lead = models.OneToOneField("Lead",related_name="opportunity", on_delete=models.CASCADE,null=True,blank=True)
probability = models.PositiveIntegerField(validators=[validate_probability]) probability = models.PositiveIntegerField(validators=[validate_probability])
expected_revenue = models.DecimalField(
max_digits=10, decimal_places=2, verbose_name=_("Expected Revenue")
)
closing_date = models.DateField(verbose_name=_("Closing Date"),null=True,blank=True) closing_date = models.DateField(verbose_name=_("Closing Date"),null=True,blank=True)
created = models.DateTimeField(auto_now_add=True, verbose_name=_("Created")) created = models.DateTimeField(auto_now_add=True, verbose_name=_("Created"))
updated = models.DateTimeField(auto_now=True, verbose_name=_("Updated")) updated = models.DateTimeField(auto_now=True, verbose_name=_("Updated"))
closed = models.BooleanField(default=False, verbose_name=_("Closed"))
estimate = models.OneToOneField(EstimateModel, related_name="opportunity",on_delete=models.SET_NULL,null=True,blank=True) estimate = models.OneToOneField(EstimateModel, related_name="opportunity",on_delete=models.SET_NULL,null=True,blank=True)
class Meta: class Meta:
verbose_name = _("Opportunity") verbose_name = _("Opportunity")
@ -1569,6 +1565,31 @@ class Notes(models.Model):
def __str__(self): def __str__(self):
return f"Note by {self.created_by.first_name} on {self.content_object}" return f"Note by {self.created_by.first_name} on {self.content_object}"
class Tasks(models.Model):
dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name="tasks")
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.UUIDField()
content_object = GenericForeignKey("content_type", "object_id")
title = models.CharField(max_length=255, verbose_name=_("Title"))
description = models.TextField(verbose_name=_("Description"),null=True,blank=True)
due_date = models.DateField(verbose_name=_("Due Date"))
completed = models.BooleanField(default=False, verbose_name=_("Completed"))
assigned_to = models.ForeignKey(
User, on_delete=models.DO_NOTHING, related_name="tasks_assigned",null=True,blank=True
)
created_by = models.ForeignKey(
User, on_delete=models.DO_NOTHING, related_name="tasks_created"
)
created = models.DateTimeField(auto_now_add=True, verbose_name=_("Created"))
updated = models.DateTimeField(auto_now=True, verbose_name=_("Updated"))
class Meta:
verbose_name = _("Task")
verbose_name_plural = _("Tasks")
def __str__(self):
return f"Task by {self.created_by.email} on {self.content_object}"
class Email(models.Model): class Email(models.Model):
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.UUIDField() object_id = models.UUIDField()

View File

@ -117,8 +117,18 @@ urlpatterns = [
path('crm/leads/<int:pk>/update-note/', views.update_note, name='update_note_to_lead'), path('crm/leads/<int:pk>/update-note/', views.update_note, name='update_note_to_lead'),
path("crm/leads/<int:pk>/delete-note/", views.delete_note, name="delete_note_to_lead"), path("crm/leads/<int:pk>/delete-note/", views.delete_note, name="delete_note_to_lead"),
path( path(
"crm/leads/<int:pk>/add-activity/", "crm/<int:pk>/update-task/",
views.add_activity_to_lead, views.update_task,
name="update_task",
),
path(
"crm/<str:content_type>/<int:pk>/add-task/",
views.add_task,
name="add_task",
),
path(
"crm/<str:content_type>/<int:pk>/add-activity/",
views.add_activity,
name="add_activity", name="add_activity",
), ),
path( path(

View File

@ -1362,6 +1362,6 @@ def handle_payment(request,order):
return transaction_url return transaction_url
# def get_user_quota(user): # def get_user_quota(user):
# return user.dealer.quota # return user.dealer.quota

View File

@ -8,6 +8,7 @@ import numpy as np
# from rich import print # from rich import print
from random import randint from random import randint
from decimal import Decimal from decimal import Decimal
from django.apps import apps
from datetime import timedelta from datetime import timedelta
from calendar import month_name from calendar import month_name
from pyzbar.pyzbar import decode from pyzbar.pyzbar import decode
@ -24,7 +25,7 @@ from django.conf import settings
from django.db import transaction from django.db import transaction
from django.db.models import Func from django.db.models import Func
from django.contrib import messages from django.contrib import messages
from django.http import JsonResponse, HttpResponseForbidden from django.http import Http404, JsonResponse, HttpResponseForbidden
from django.forms import HiddenInput, ValidationError from django.forms import HiddenInput, ValidationError
from django.shortcuts import HttpResponse from django.shortcuts import HttpResponse
from django.db.models import Sum, F, Count from django.db.models import Sum, F, Count
@ -4580,10 +4581,15 @@ class LeadDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
context["activities"] = models.Activity.objects.filter( context["activities"] = models.Activity.objects.filter(
content_type__model="lead", object_id=self.object.id content_type__model="lead", object_id=self.object.id
) )
context["tasks"] = models.Tasks.objects.filter(
content_type__model="lead", object_id=self.object.id
)
context["status_history"] = models.LeadStatusHistory.objects.filter( context["status_history"] = models.LeadStatusHistory.objects.filter(
lead=self.object lead=self.object
) )
context["transfer_form"] = forms.LeadTransferForm() context["transfer_form"] = forms.LeadTransferForm()
context["activity_form"] = forms.ActivityForm()
context["staff_task_form"] = forms.StaffTaskForm()
return context return context
@ -4673,10 +4679,10 @@ def lead_create(request):
def lead_tracking(request): def lead_tracking(request):
dealer = get_user_type(request) dealer = get_user_type(request)
new = models.Lead.objects.filter(dealer=dealer) new = models.Lead.objects.filter(dealer=dealer, status="new")
follow_up = models.Lead.objects.filter(dealer=dealer, next_action__in=["call", "meeting"]) follow_up = models.Lead.objects.filter(dealer=dealer, next_action__in=["call", "meeting"])
won = models.Lead.objects.filter(dealer=dealer, status="won") won = models.Lead.objects.filter(dealer=dealer, status="won")
lose = models.Lead.objects.filter(dealer=dealer, status="lose") lose = models.Lead.objects.filter(dealer=dealer, status="lost")
negotiation = models.Lead.objects.filter(dealer=dealer, status="negotiation") negotiation = models.Lead.objects.filter(dealer=dealer, status="negotiation")
context = {"new": new,"follow_up": follow_up,"won": won,"lose": lose,"negotiation": negotiation} context = {"new": new,"follow_up": follow_up,"won": won,"lose": lose,"negotiation": negotiation}
return render(request, "crm/leads/lead_tracking.html", context) return render(request, "crm/leads/lead_tracking.html", context)
@ -4687,23 +4693,23 @@ def update_lead_actions(request):
lead_id = request.POST.get('lead_id') lead_id = request.POST.get('lead_id')
current_action = request.POST.get('current_action') current_action = request.POST.get('current_action')
next_action = request.POST.get('next_action') next_action = request.POST.get('next_action')
next_action_date = request.POST.get('next_action_date') next_action_date = request.POST.get('next_action_date',None)
action_notes = request.POST.get('action_notes', '') action_notes = request.POST.get('action_notes', '')
# Validate required fields # Validate required fields
if not all([lead_id, current_action, next_action, next_action_date]): if not all([lead_id, current_action, next_action]):
return JsonResponse({'success': False, 'message': 'All fields are required'}, status=400) return JsonResponse({'success': False, 'message': 'All fields are required'}, status=400)
# Get the lead # Get the lead
lead = models.Lead.objects.get(id=lead_id) lead = models.Lead.objects.get(id=lead_id)
# Update lead fields # Update lead fields
lead.action = current_action lead.status = current_action
lead.next_action = next_action lead.next_action = next_action
lead.next_action_date = next_action_date
# Parse the datetime string # Parse the datetime string
try: try:
if next_action_date:
lead.next_action_date = next_action_date
next_action_datetime = datetime.strptime(next_action_date, '%Y-%m-%dT%H:%M') next_action_datetime = datetime.strptime(next_action_date, '%Y-%m-%dT%H:%M')
lead.next_action_date = timezone.make_aware(next_action_datetime) lead.next_action_date = timezone.make_aware(next_action_datetime)
except ValueError: except ValueError:
@ -5060,10 +5066,6 @@ def send_lead_email(request, pk, email_pk=None):
response["HX-Redirect"] = reverse("lead_detail", args=[lead.pk]) response["HX-Redirect"] = reverse("lead_detail", args=[lead.pk])
return response return response
lead.status = models.Status.CONTACTED
lead.save()
if request.method == "POST": if request.method == "POST":
email_pk = request.POST.get("email_pk") email_pk = request.POST.get("email_pk")
if email_pk not in [None, "None", ""]: if email_pk not in [None, "None", ""]:
@ -5138,11 +5140,16 @@ def add_activity_to_lead(request, pk):
:return: An HTTP response that either renders the form or redirects to the lead detail page :return: An HTTP response that either renders the form or redirects to the lead detail page
""" """
lead = get_object_or_404(models.Lead, pk=pk) lead = get_object_or_404(models.Lead, pk=pk)
dealer = get_user_type(request)
if request.method == "POST": if request.method == "POST":
form = forms.ActivityForm(request.POST) form = forms.ActivityForm(request.POST)
if form.is_valid(): if form.is_valid():
activity = form.save(commit=False) activity = form.save(commit=False)
print(activity)
activity.content_object = lead activity.content_object = lead
activity.dealer = dealer
activity.activity_type = form.cleaned_data["activity_type"]
activity.notes = form.cleaned_data["notes"]
activity.created_by = request.user activity.created_by = request.user
activity.save() activity.save()
return redirect("lead_detail", pk=pk) return redirect("lead_detail", pk=pk)
@ -5151,7 +5158,7 @@ def add_activity_to_lead(request, pk):
return render(request, "crm/add_activity.html", {"form": form, "lead": lead}) return render(request, "crm/add_activity.html", {"form": form, "lead": lead})
class OpportunityCreateView(CreateView, LoginRequiredMixin): class OpportunityCreateView(CreateView,SuccessMessageMixin, LoginRequiredMixin):
""" """
Handles the creation of Opportunity instances through a form while enforcing Handles the creation of Opportunity instances through a form while enforcing
specific user access control and initial data population. This view ensures specific user access control and initial data population. This view ensures
@ -5173,30 +5180,33 @@ class OpportunityCreateView(CreateView, LoginRequiredMixin):
model = models.Opportunity model = models.Opportunity
form_class = forms.OpportunityForm form_class = forms.OpportunityForm
template_name = "crm/opportunities/opportunity_form.html" template_name = "crm/opportunities/opportunity_form.html"
success_message = "Opportunity created successfully."
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
dealer = get_user_type(self.request) dealer = get_user_type(self.request)
return context return context
def get_initial(self): # def get_initial(self):
initial = super().get_initial() # initial = super().get_initial()
if self.kwargs.get("pk", None): # if self.kwargs.get("pk", None):
lead = models.Lead.objects.get(pk=self.kwargs.get("pk")) # lead = models.Lead.objects.get(pk=self.kwargs.get("pk"))
initial["customer"] = lead.customer # initial["customer"] = lead.customer
return initial # return initial
def form_valid(self, form): def form_valid(self, form):
dealer = get_user_type(self.request) dealer = get_user_type(self.request)
form.instance.dealer = dealer form.instance.dealer = dealer
form.instance.customer = form.instance.lead.customer
form.instance.staff = form.instance.lead.staff
return super().form_valid(form) return super().form_valid(form)
def get_success_url(self): def get_success_url(self):
return reverse_lazy("opportunity_detail", kwargs={"pk": self.object.pk}) return reverse_lazy("opportunity_detail", kwargs={"pk": self.object.pk})
class OpportunityUpdateView(LoginRequiredMixin, UpdateView): class OpportunityUpdateView(LoginRequiredMixin,SuccessMessageMixin, UpdateView):
""" """
Handles the update functionality for Opportunity objects. Handles the update functionality for Opportunity objects.
@ -5221,6 +5231,7 @@ class OpportunityUpdateView(LoginRequiredMixin, UpdateView):
model = models.Opportunity model = models.Opportunity
form_class = forms.OpportunityForm form_class = forms.OpportunityForm
template_name = "crm/opportunities/opportunity_form.html" template_name = "crm/opportunities/opportunity_form.html"
success_message = "Opportunity updated successfully."
def get_success_url(self): def get_success_url(self):
return reverse_lazy("opportunity_detail", kwargs={"pk": self.object.pk}) return reverse_lazy("opportunity_detail", kwargs={"pk": self.object.pk})
@ -5252,7 +5263,6 @@ class OpportunityDetailView(LoginRequiredMixin, DetailView):
url = reverse("opportunity_update_status", args=[self.object.pk]) url = reverse("opportunity_update_status", args=[self.object.pk])
form.fields["status"].widget.attrs["hx-get"] = url form.fields["status"].widget.attrs["hx-get"] = url
form.fields["stage"].widget.attrs["hx-get"] = url form.fields["stage"].widget.attrs["hx-get"] = url
form.fields["status"].initial = self.object.status
form.fields["stage"].initial = self.object.stage form.fields["stage"].initial = self.object.stage
context["status_form"] = form context["status_form"] = form
context["notes"] = models.Notes.objects.filter( context["notes"] = models.Notes.objects.filter(
@ -5272,25 +5282,6 @@ class OpportunityDetailView(LoginRequiredMixin, DetailView):
class OpportunityListView(LoginRequiredMixin, ListView): class OpportunityListView(LoginRequiredMixin, ListView):
"""
View for displaying a paginated list of opportunities.
This class-based view inherits from `LoginRequiredMixin` and `ListView` to
provide a view rendering a list of `Opportunity` objects associated with
the current dealer. It ensures the user is authenticated before providing
access to the opportunity list and adds filtering based on the dealer
associated with the request.
:ivar model: The model used to retrieve opportunities.
:type model: models.Opportunity
:ivar template_name: The template used to render the opportunities list.
:type template_name: str
:ivar context_object_name: The context variable name for the list of
opportunities in the template.
:type context_object_name: str
:ivar paginate_by: The number of opportunities displayed per page.
:type paginate_by: int
"""
model = models.Opportunity model = models.Opportunity
template_name = "crm/opportunities/opportunity_list.html" template_name = "crm/opportunities/opportunity_list.html"
context_object_name = "opportunities" context_object_name = "opportunities"
@ -5298,9 +5289,38 @@ class OpportunityListView(LoginRequiredMixin, ListView):
def get_queryset(self): def get_queryset(self):
dealer = get_user_type(self.request) dealer = get_user_type(self.request)
return models.Opportunity.objects.filter(dealer=dealer).all() queryset = models.Opportunity.objects.filter(dealer=dealer)
# Search filter
search = self.request.GET.get('search')
if search:
queryset = queryset.filter(
Q(customer__customer_name__icontains=search) |
Q(customer__email__icontains=search))
# Stage filter
stage = self.request.GET.get('stage')
if stage:
queryset = queryset.filter(stage=stage)
# Sorting
sort = self.request.GET.get('sort', 'newest')
if sort == 'newest':
queryset = queryset.order_by('-created')
elif sort == 'highest':
queryset = queryset.order_by('-expected_revenue')
elif sort == 'closing':
queryset = queryset.order_by('closing_date')
return queryset
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['stage_choices'] = models.Stage.choices
return context
def get_template_names(self):
return self.template_name
@login_required @login_required
def delete_opportunity(request, pk): def delete_opportunity(request, pk):
""" """
@ -7706,3 +7726,78 @@ def mark_all_notifications_as_read(request):
def notifications_history(request): def notifications_history(request):
models.Notification.objects.filter(user=request.user, is_read=False).update(read=True) models.Notification.objects.filter(user=request.user, is_read=False).update(read=True)
return JsonResponse({'status': 'success'}) return JsonResponse({'status': 'success'})
# def activity_create(request,pk):
# lead = get_object_or_404(models.Lead, pk=pk)
# form = forms.ActivityHistoryForm()
# dealer = get_user_type(request)
# if request.method == "POST":
# form = forms.ActivityHistoryForm(request.POST)
# if form.is_valid():
# models.Activity.objects.create(
# dealer=dealer,
# activity_type=form.cleaned_data['activity_type'],
# notes=form.cleaned_data['description'],
# created_by=request.user,
# content_object=lead
# )
# return render(request, 'activity_history.html')
def add_activity(request,content_type,pk):
try:
model = apps.get_model(f'inventory.{content_type}')
except LookupError:
raise Http404("Model not found")
obj = get_object_or_404(model, pk=pk)
dealer = get_user_type(request)
if request.method == "POST":
form = forms.ActivityForm(request.POST)
if form.is_valid():
activity = form.save(commit=False)
activity.dealer = dealer
activity.content_object = obj
activity.created_by = request.user
activity.notes = form.cleaned_data['notes']
activity.activity_type = form.cleaned_data['activity_type']
activity.save()
messages.success(request, _("Activity added successfully"))
else:
messages.error(request, _("Activity form is not valid"))
return redirect(f"{content_type}_detail", pk=pk)
def add_task(request,content_type,pk):
try:
model = apps.get_model(f'inventory.{content_type}')
except LookupError:
raise Http404("Model not found")
obj = get_object_or_404(model, pk=pk)
dealer = get_user_type(request)
if request.method == "POST":
form = forms.StaffTaskForm(request.POST)
if form.is_valid():
task = form.save(commit=False)
task.dealer = dealer
task.content_object = obj
task.assigned_to = request.user
task.created_by = request.user
task.due_date = form.cleaned_data['due_date']
task.save()
messages.success(request, _("Task added successfully"))
else:
print(form.errors)
messages.error(request, _("Task form is not valid"))
return redirect(f"{content_type}_detail", pk=pk)
def update_task(request,pk):
task = get_object_or_404(models.Tasks, pk=pk)
if request.method == "POST":
task.completed = False if task.completed else True
task.save()
messages.success(request, _("Task updated successfully"))
else:
messages.error(request, _("Task form is not valid"))
response = HttpResponse()
response['HX-Refresh'] = 'true'
return response

View File

@ -8,7 +8,7 @@
{% endblock head_title %} {% endblock head_title %}
{% block content %} {% block content %}
<div class="row "> <div class="row ">
<div class="row flex-center min-vh-50"> <div class="row flex-center min-vh-50">
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3"> <div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3">
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}"> <a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}">
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block"> <div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">
@ -44,6 +44,6 @@
{% csrf_token %} {% csrf_token %}
</form> </form>
</div> </div>
</div> </div>
</div> </div>
{% endblock content %} {% endblock content %}

View File

@ -6,7 +6,7 @@
{% endblock head_title %} {% endblock head_title %}
{% block content %} {% block content %}
<div class="row "> <div class="row ">
<div class="row flex-center min-vh-50"> <div class="row flex-center min-vh-50">
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3"> <div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3">
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}"> <a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}">
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block"> <div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">
@ -30,9 +30,9 @@
<div class="fs-9 fw-bold form-group mb-3 list-group"> <div class="fs-9 fw-bold form-group mb-3 list-group">
{% for radio in emailaddress_radios %} {% for radio in emailaddress_radios %}
{% with emailaddress=radio.emailaddress %} {% with emailaddress=radio.emailaddress %}
<label for="{{ radio.id }}"> <label for="{{ radio.id }}">
<input type="radio" name="email" checked="{{ radio.checked }}" value="{{ emailaddress.email }}" id="{{ radio.id }}" class="form-check-input mb-3" /> <input type="radio" name="email" checked="{{ radio.checked }}" value="{{ emailaddress.email }}" id="{{ radio.id }}" class="form-check-input mb-3" />
{{ emailaddress.email }} {{ emailaddress.email }}
{% if emailaddress.verified %} {% if emailaddress.verified %}
<span class="badge badge-phoenix badge-phoenix-success verified">{% translate "Verified" %}</span> <span class="badge badge-phoenix badge-phoenix-success verified">{% translate "Verified" %}</span>
{% else %} {% else %}
@ -42,9 +42,9 @@
<span class="badge badge-phoenix badge-phoenix-primary email">{% translate "Primary" %}</span> <span class="badge badge-phoenix badge-phoenix-primary email">{% translate "Primary" %}</span>
{% endif %} {% endif %}
{% endwith %} {% endwith %}
</label> </label>
{% endfor %} {% endfor %}
</div> </div>
<div class="mt-2 mb-6"> <div class="mt-2 mb-6">
<button type="submit" name="action_primary" class="btn btn-sm btn-primary">{% trans 'Make Primary' %}</button> <button type="submit" name="action_primary" class="btn btn-sm btn-primary">{% trans 'Make Primary' %}</button>
<button type="submit" name="action_send" class="btn btn-sm btn-secondary">{% trans 'Re-send Verification' %}</button> <button type="submit" name="action_send" class="btn btn-sm btn-secondary">{% trans 'Re-send Verification' %}</button>
@ -72,7 +72,7 @@
{% endif %} {% endif %}
<script> <script>
(function() { (function() {
var message = "{% trans 'Do you really want to remove the selected email address?' %}"; var message = "{% trans 'Do you really want to remove the selected email address?' %}";
var actions = document.getElementsByName('action_remove'); var actions = document.getElementsByName('action_remove');
if (actions.length) { if (actions.length) {
@ -82,9 +82,9 @@
} }
}); });
} }
})(); })();
</script> </script>
</div> </div>
</div> </div>
</div> </div>
{% endblock content %} {% endblock content %}

View File

@ -7,7 +7,7 @@
{% endblock head_title %} {% endblock head_title %}
{% block content %} {% block content %}
<div class="row "> <div class="row ">
<div class="row flex-center min-vh-50"> <div class="row flex-center min-vh-50">
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3"> <div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3">
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}"> <a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}">
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block"> <div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">
@ -48,6 +48,6 @@
</p> </p>
{% endif %} {% endif %}
</div> </div>
</div> </div>
</div> </div>
{% endblock content %} {% endblock content %}

View File

@ -8,7 +8,7 @@
{% block content %} {% block content %}
<section class="main my-2"> <section class="main my-2">
<div class="row flex-center "> <div class="row flex-center ">
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3"> <div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3">
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}"> <a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}">
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block"> <div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">

View File

@ -2,7 +2,7 @@
{% load i18n static %} {% load i18n static %}
{% block content %} {% block content %}
<div class="row"> <div class="row">
<div class="row flex-center min-vh-50 py-5"> <div class="row flex-center min-vh-50 py-5">
<div class="col-sm-10 col-md-8 col-lg-5 col-xxl-4"> <div class="col-sm-10 col-md-8 col-lg-5 col-xxl-4">
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}"> <a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}">
@ -34,5 +34,5 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -5,8 +5,8 @@
{% trans "Change Password" %} {% trans "Change Password" %}
{% endblock head_title %} {% endblock head_title %}
{% block content %} {% block content %}
<div class="row "> <div class="row ">
<div class="row flex-center min-vh-50"> <div class="row flex-center min-vh-50">
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3"> <div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3">
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}"> <a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}">
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block"> <div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">
@ -29,6 +29,6 @@
</div> </div>
</form> </form>
</div> </div>
</div> </div>
</div> </div>
{% endblock content %} {% endblock content %}

View File

@ -5,7 +5,7 @@
{% trans "Password Reset" %} {% trans "Password Reset" %}
{% endblock head_title %} {% endblock head_title %}
{% block content %} {% block content %}
<div class="row "> <div class="row ">
<div class="row flex-center min-vh-50"> <div class="row flex-center min-vh-50">
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3"> <div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3">
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}"> <a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}">
@ -37,5 +37,5 @@
</p> </p>
</div> </div>
</div> </div>
</div> </div>
{% endblock content %} {% endblock content %}

View File

@ -7,7 +7,7 @@
{% endblock head_title %} {% endblock head_title %}
{% block content %} {% block content %}
<div class="row "> <div class="row ">
<div class="row flex-center min-vh-50"> <div class="row flex-center min-vh-50">
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3"> <div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3">
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}"> <a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}">
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block"> <div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">
@ -28,6 +28,6 @@
{% blocktrans %}We have sent you an email. If you have not received it please check your spam folder. Otherwise contact us if you do not receive it in a few minutes.{% endblocktrans %} {% blocktrans %}We have sent you an email. If you have not received it please check your spam folder. Otherwise contact us if you do not receive it in a few minutes.{% endblocktrans %}
</p> </p>
</div> </div>
</div> </div>
</div> </div>
{% endblock content %} {% endblock content %}

View File

@ -7,7 +7,7 @@
{% endblock head_title %} {% endblock head_title %}
{% block content %} {% block content %}
<div class="row "> <div class="row ">
<div class="row flex-center min-vh-50"> <div class="row flex-center min-vh-50">
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3"> <div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3">
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}"> <a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}">
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block"> <div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">
@ -37,10 +37,10 @@
{% csrf_token %} {% csrf_token %}
{{ redirect_field }} {{ redirect_field }}
{{ form|crispy }} {{ form|crispy }}
<button type="submit" class="btn btn-primary btn-sm w-100">{% trans 'Change Password' %}</button> <button type="submit" class="btn btn-primary btn-sm w-100">{% trans 'Change Password' %}</button>
</form> </form>
{% endif %} {% endif %}
</div> </div>
</div> </div>
</div> </div>
{% endblock content %} {% endblock content %}

View File

@ -6,7 +6,7 @@
{% endblock head_title %} {% endblock head_title %}
{% block content %} {% block content %}
<div class="row "> <div class="row ">
<div class="row flex-center min-vh-50"> <div class="row flex-center min-vh-50">
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3"> <div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3">
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}"> <a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}">
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block"> <div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">
@ -23,6 +23,6 @@
</div> </div>
</div> </div>
</div> </div>
{% endblock content %} {% endblock content %}

View File

@ -19,7 +19,7 @@
<p class="text-body-tertiary fs-9">{% trans 'Create your account today' %}</p> <p class="text-body-tertiary fs-9">{% trans 'Create your account today' %}</p>
</div> </div>
<div class="card theme-wizard" data-theme-wizard="data-theme-wizard"> <div class="card theme-wizard" data-theme-wizard="data-theme-wizard">
<div class="card-header pt-3 pb-2 "> <div class="card-header pt-3 pb-2 ">
<ul class="nav justify-content-between nav-wizard nav-wizard-success" role="tablist"> <ul class="nav justify-content-between nav-wizard nav-wizard-success" role="tablist">
<li class="nav-item" role="presentation"><a class="nav-link active fw-semibold" href="#bootstrap-wizard-validation-tab1" data-bs-toggle="tab" data-wizard-step="1" aria-selected="true" role="tab"> <li class="nav-item" role="presentation"><a class="nav-link active fw-semibold" href="#bootstrap-wizard-validation-tab1" data-bs-toggle="tab" data-wizard-step="1" aria-selected="true" role="tab">
@ -77,7 +77,7 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</section> </section>
@ -85,9 +85,9 @@
{% include 'footer.html' %} {% include 'footer.html' %}
</section> </section>
<script src="{% static 'js/phoenix.js' %}"></script> <script src="{% static 'js/phoenix.js' %}"></script>
{% endblock content %} {% endblock content %}
{% block customJS %} {% block customJS %}
<script src="https://unpkg.com/just-validate@latest/dist/just-validate.production.min.js"></script> <script src="https://unpkg.com/just-validate@latest/dist/just-validate.production.min.js"></script>
<script> <script>
const validator = new JustValidate('#wizardValidationForm1', { const validator = new JustValidate('#wizardValidationForm1', {
@ -283,4 +283,4 @@
} }
</script> </script>
{% endblock customJS %} {% endblock customJS %}

View File

@ -5,7 +5,7 @@
{% block title %}{{ _("Sign Up") }}{% endblock title %} {% block title %}{{ _("Sign Up") }}{% endblock title %}
{% block content %} {% block content %}
<div class="row"> <div class="row">
<div class="row min-vh-100 text-center"> <div class="row min-vh-100 text-center">
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3"> <div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3">
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}"> <a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}">
@ -34,7 +34,7 @@
{% if SOCIALACCOUNT_ENABLED %} {% if SOCIALACCOUNT_ENABLED %}
{% include "socialaccount/snippets/login.html" with page_layout="entrance" %} {% include "socialaccount/snippets/login.html" with page_layout="entrance" %}
{% endif %} {% endif %}
<!-- Sign Up Form --> <!-- Sign Up Form -->
{% if not SOCIALACCOUNT_ONLY %} {% if not SOCIALACCOUNT_ONLY %}

View File

@ -21,13 +21,13 @@
{% url 'account_email' as email_url %} {% url 'account_email' as email_url %}
<p> <p>
{% blocktrans %}This part of the site requires us to verify that {% blocktrans %}This part of the site requires us to verify that
you are who you claim to be. For this purpose, we require that you you are who you claim to be. For this purpose, we require that you
verify ownership of your email address. {% endblocktrans %} verify ownership of your email address. {% endblocktrans %}
</p> </p>
<p> <p>
{% blocktrans %}We have sent an email to you for {% blocktrans %}We have sent an email to you for
verification. Please click on the link inside that email. If you do not see the verification email in your main inbox, check your spam folder. Otherwise verification. Please click on the link inside that email. If you do not see the verification email in your main inbox, check your spam folder. Otherwise
contact us if you do not receive it within a few minutes.{% endblocktrans %} contact us if you do not receive it within a few minutes.{% endblocktrans %}
</p> </p>
<p> <p>
{% blocktrans %}<strong>Note:</strong> you can still <a href="{{ email_url }}">change your email address</a>.{% endblocktrans %} {% blocktrans %}<strong>Note:</strong> you can still <a href="{{ email_url }}">change your email address</a>.{% endblocktrans %}

View File

@ -6,7 +6,7 @@
{% block description %}{{ page_description }}{% endblock %} {% block description %}{{ page_description }}{% endblock %}
{% block content %} {% block content %}
<div class="container py-5"> <div class="container py-5">
<div class="card bg-body"> <div class="card bg-body">
<div class="card-header "> <div class="card-header ">
<h4 class="mb-0">{{ page_title }}</h4> <h4 class="mb-0">{{ page_title }}</h4>
@ -88,7 +88,7 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}
{% block extra_js %} {% block extra_js %}

View File

@ -111,7 +111,7 @@
<button type="submit" class="btn btn-sm btn-phoenix-primary">{{ btn_text }}</button> <button type="submit" class="btn btn-sm btn-phoenix-primary">{{ btn_text }}</button>
{% else %} {% else %}
{% if request.user.is_superuser and service.id %} {% if request.user.is_superuser and service.id %}
{% translate "Are you sure you want to delete this service?" as d_modal_message %} {% translate "Are you sure you want to delete this service?" as d_modal_message %}
<div class="service-btn-container"> <div class="service-btn-container">
<a href="{% url 'appointment:update_service' service_id=service.id %}" <a href="{% url 'appointment:update_service' service_id=service.id %}"
class="btn btn-sm btn-phoenix-primary"> class="btn btn-sm btn-phoenix-primary">

View File

@ -9,7 +9,7 @@
{% trans 'Service List' %}. {% trans 'Service List' %}.
{% endblock %} {% endblock %}
{% block body %} {% block body %}
{% translate "Confirm Deletion" as modal_title %} {% translate "Confirm Deletion" as modal_title %}
{% translate "Delete" as delete_btn_modal %} {% translate "Delete" as delete_btn_modal %}
<div class="row"> <div class="row">
<div class="col-6"> <div class="col-6">
@ -62,7 +62,7 @@
</tbody> </tbody>
</table> </table>
</div> </div>
{% include 'modal/confirm_modal.html' %} {% include 'modal/confirm_modal.html' %}
</div> </div>
{% endblock %} {% endblock %}

View File

@ -5,7 +5,7 @@
{% endblock %} {% endblock %}
{% block title %} {% block title %}
{{ _("Staff Members List")}} {{ _("Staff Members List")}}
{% endblock %} {% endblock %}
{% block description %} {% block description %}
{% trans 'List of all staff members' %}. {% trans 'List of all staff members' %}.

View File

@ -36,7 +36,7 @@
<!-- ===============================================--> <!-- ===============================================-->
<link href="{% static 'vendors/mapbox-gl/mapbox-gl.css' %}" rel="stylesheet"> <link href="{% static 'vendors/mapbox-gl/mapbox-gl.css' %}" rel="stylesheet">
<link href="{% static 'vendors/swiper/swiper-bundle.min.css' %}" rel="stylesheet"> <link href="{% static 'vendors/swiper/swiper-bundle.min.css' %}" rel="stylesheet">
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin=""> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
@ -60,9 +60,9 @@
<div class="content"> <div class="content">
{% block content %} {% block content %}
<!-- Main content goes here --> <!-- Main content goes here -->
{% endblock %} {% endblock %}
</div> </div>
@ -73,7 +73,7 @@
<!-- ===============================================--> <!-- ===============================================-->
<!-- End of Main Content--> <!-- End of Main Content-->
<!-- ===============================================--> <!-- ===============================================-->
<script> <script>

View File

@ -6,7 +6,7 @@
data-bs-theme="" data-bs-theme=""
data-navigation-type="default" data-navigation-type="default"
data-navbar-horizontal-shape="default"> data-navbar-horizontal-shape="default">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
@ -16,7 +16,7 @@
{% endblock %} {% endblock %}
{% block description %} {% block description %}
{% endblock %} {% endblock %}
</title> </title>
<link rel="apple-touch-icon" sizes="180x180" href="{% static 'images/favicons/apple-touch-icon.png' %}"> <link rel="apple-touch-icon" sizes="180x180" href="{% static 'images/favicons/apple-touch-icon.png' %}">
<link rel="icon" type="image/png" sizes="32x32" href="{% static 'images/favicons/favicon-32x32.png' %}"> <link rel="icon" type="image/png" sizes="32x32" href="{% static 'images/favicons/favicon-32x32.png' %}">
@ -39,7 +39,7 @@
<link href="{% static 'vendors/flatpickr/flatpickr.min.css' %}" rel="stylesheet"> <link href="{% static 'vendors/flatpickr/flatpickr.min.css' %}" rel="stylesheet">
<link href="{% static 'css/custom.css' %}" rel="stylesheet"> <link href="{% static 'css/custom.css' %}" rel="stylesheet">
<link rel="stylesheet" href="https://unicons.iconscout.com/release/v4.0.8/css/line.css"> <link rel="stylesheet" href="https://unicons.iconscout.com/release/v4.0.8/css/line.css">
{% if LANGUAGE_CODE == 'ar' %} {% if LANGUAGE_CODE == 'ar' %}
<link href="{% static 'css/theme-rtl.min.css' %}" type="text/css" rel="stylesheet" id="style-rtl"> <link href="{% static 'css/theme-rtl.min.css' %}" type="text/css" rel="stylesheet" id="style-rtl">
<link href="{% static 'css/user-rtl.min.css' %}" type="text/css" rel="stylesheet" id="user-style-rtl"> <link href="{% static 'css/user-rtl.min.css' %}" type="text/css" rel="stylesheet" id="user-style-rtl">
@ -47,9 +47,9 @@
<link href="{% static 'css/theme.min.css' %}" type="text/css" rel="stylesheet" id="style-default"> <link href="{% static 'css/theme.min.css' %}" type="text/css" rel="stylesheet" id="style-default">
<link href="{% static 'css/user.min.css' %}" type="text/css" rel="stylesheet" id="user-style-default"> <link href="{% static 'css/user.min.css' %}" type="text/css" rel="stylesheet" id="user-style-default">
{% endif %} {% endif %}
<script src="{% static 'js/main.js' %}"></script> <script src="{% static 'js/main.js' %}"></script>
<script src="{% static 'js/jquery.min.js' %}"></script> <script src="{% static 'js/jquery.min.js' %}"></script>
<script src="{% static 'js/echarts.js' %}"></script> <script src="{% static 'js/echarts.js' %}"></script>
<!--<style> <!--<style>
.btn{ .btn{
@ -59,18 +59,18 @@
padding-bottom: 4px; padding-bottom: 4px;
} }
</style>--> </style>-->
{% block customCSS %} {% block customCSS %}
{% endblock %} {% endblock %}
</head> </head>
<body hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'> <body hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'>
{% include "toast-alert.html" %} {% include "toast-alert.html" %}
<main class="main" id="top"> <main class="main" id="top">
{% include 'header.html' %} {% include 'header.html' %}
<div class="content"> <div class="content">
{% include "plans/expiration_messages.html" %} {% include "plans/expiration_messages.html" %}
{% block period_navigation %} {% block period_navigation %}
{% endblock period_navigation %} {% endblock period_navigation %}
@ -80,9 +80,9 @@
{% block body %} {% block body %}
{% endblock body%} {% endblock body%}
<div class="my-3"></div> <div class="my-3"></div>
{% include 'footer.html' %} {% include 'footer.html' %}
</div> </div>
</main> </main>
<script src="{% static 'js/djetler.bundle.js' %}"></script> <script src="{% static 'js/djetler.bundle.js' %}"></script>
<script src="{% static 'js/js-utils.js' %}"></script> <script src="{% static 'js/js-utils.js' %}"></script>
@ -114,7 +114,7 @@
<script src="{% static 'vendors/swiper/swiper-bundle.min.js' %}"></script> <script src="{% static 'vendors/swiper/swiper-bundle.min.js' %}"></script>
<script src="{% static 'vendors/flatpickr/flatpickr.min.js' %}"></script> <script src="{% static 'vendors/flatpickr/flatpickr.min.js' %}"></script>
<script> <script>
{% if entity_slug %} {% if entity_slug %}
let entitySlug = "{{ view.kwargs.entity_slug }}" let entitySlug = "{{ view.kwargs.entity_slug }}"
{% endif %} {% endif %}

View File

@ -40,4 +40,4 @@
</div> </div>
</div> </div>
<button class="btn btn-support-chat p-0 border border-translucent"><span class="fs-8 btn-text text-primary text-nowrap">Chat demo</span><span class="ping-icon-wrapper mt-n4 ms-n6 mt-sm-0 ms-sm-2 position-absolute position-sm-relative"><span class="ping-icon-bg"></span><span class="fa-solid fa-circle ping-icon"></span></span><span class="fa-solid fa-headset text-primary fs-8 d-sm-none"></span><span class="fa-solid fa-chevron-down text-primary fs-7"></span></button> <button class="btn btn-support-chat p-0 border border-translucent"><span class="fs-8 btn-text text-primary text-nowrap">Chat demo</span><span class="ping-icon-wrapper mt-n4 ms-n6 mt-sm-0 ms-sm-2 position-absolute position-sm-relative"><span class="ping-icon-bg"></span><span class="fa-solid fa-circle ping-icon"></span></span><span class="fa-solid fa-headset text-primary fs-8 d-sm-none"></span><span class="fa-solid fa-chevron-down text-primary fs-7"></span></button>
</div> </div>

View File

@ -0,0 +1,30 @@
{% load static i18n crispy_forms_tags %}
<!-- activity Modal -->
<div class="modal fade" id="activityModal" tabindex="-1" aria-labelledby="activityModalLabel" aria-hidden="true">
<div class="modal-dialog modal-md">
<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="noteModalLabel">{% trans 'Activity' %}</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 class="modal-body">
<form action="{% url 'add_activity' content_type=content_type pk=pk %}" method="post" class="add_activity_form">
{% csrf_token %}
<div class="mb-2 form-group">
<select class="form-select" name="activity_type" id="activity_type">
<option value="call">{% trans 'Call' %}</option>
<option value="email">{% trans 'Email' %}</option>
<option value="meeting">{% trans 'Meeting' %}</option>
</select>
</div>
<div class="mb-3 form-group">
<textarea class="form-control" name="notes" id="notes" rows="6"></textarea>
</div>
<button type="submit" class="btn btn-success w-100">{% trans 'Save' %}</button>
</form>
</div>
</div>
</div>
</div>

View File

@ -2,10 +2,10 @@
{% load i18n static crispy_forms_filters %} {% load i18n static crispy_forms_filters %}
{% block content %} {% block content %}
<h1>Add Activity to {{ lead.first_name }} {{ lead.last_name }}</h1> <h1>Add Activity to {{ lead.first_name }} {{ lead.last_name }}</h1>
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %}
{{ form|crispy }} {{ form|crispy }}
<button class="btn btn-phoenix-primary" type="submit">Add Activity</button> <button class="btn btn-phoenix-primary" type="submit">Add Activity</button>
</form> </form>
{% endblock %} {% endblock %}

View File

@ -1,9 +1,9 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% load static %} {% load static %}
{% block content %} {% block content %}
<div class="row"> <div class="row">
<div class="table-responsive border-translucent"> <div class="table-responsive border-translucent">
<table class="table table-sm fs-9"> <table class="table table-sm fs-9">
<thead> <thead>
<tr> <tr>
<th>Customer</th> <th>Customer</th>
@ -32,7 +32,7 @@
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,10 +1,10 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Title</title> <title>Title</title>
</head> </head>
<body> <body>
</body> </body>
</html> </html>

View File

@ -1,18 +1,97 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% load i18n static %} {% load i18n static humanize %}
{% block content %}
{% load crispy_forms_tags %} {% load crispy_forms_tags %}
{% block customCSS %} {% block customCSS %}
<style> <style>
.main-tab li:last-child { .main-tab li:last-child {
margin-left: auto; margin-left: auto;
} }
</style> .completed-task {
{% endblock customCSS %} text-decoration: line-through;
opacity: 0.7;
}
.kanban-header {
position: relative;
background-color:rgb(237, 241, 245);
font-weight: 600;
padding: 0.5rem 1rem;
margin-bottom: 1rem;
color: #333;
clip-path: polygon(0 0, calc(100% - 15px) 0, 100% 50%, calc(100% - 15px) 100%, 0 100%);
box-shadow: 0 1px 2px rgba(0,0,0,0.1);
}
.kanban-header::after {
content: "";
position: absolute;
right: -20px;
top: 0;
width: 0;
height: 0;
border-top: 28px solid transparent;
border-bottom: 28px solid transparent;
border-left: 20px solid #dee2e6;
}
</style>
{% endblock customCSS %}
{% block content %}
<div class="row g-3">
<div class="col-12">
<div class="modal fade" id="actionTrackingModal" tabindex="-1" aria-labelledby="actionTrackingModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="actionTrackingModalLabel">{{ _("Update Lead Actions") }}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form id="actionTrackingForm" method="post">
<div class="modal-body">
{% csrf_token %}
<input type="hidden" id="leadId" name="lead_id">
<div class="mb-3">
<label for="currentAction" class="form-label">{{ _("Current Action") }}</label>
<select class="form-select" id="currentAction" name="current_action" required>
<option value="">{{ _("Select Action") }}</option>
<option value="follow_up">{{ _("Follow Up") }}</option>
<option value="negotiation">{{ _("Negotiation") }}</option>
<option value="won">{{ _("Won") }}</option>
<option value="lost">{{ _("Lost") }}</option>
<option value="closed">{{ _("Closed") }}</option>
</select>
</div>
<div class="mb-3">
<label for="nextAction" class="form-label">{{ _("Next Action") }}</label>
<select class="form-select" id="nextAction" name="next_action" required>
<option value="">{{ _("Select Next Action") }}</option>
<option value="no_action">{{ _("No Action") }}</option>
<option value="call">{{ _("Call") }}</option>
<option value="meeting">{{ _("Meeting") }}</option>
<option value="email">{{ _("Email") }}</option>
</select>
</div>
<div class="mb-3">
<label for="nextActionDate" class="form-label">{{ _("Next Action Date") }}</label>
<input type="datetime-local" class="form-control" id="nextActionDate" name="next_action_date">
</div>
<div class="mb-3">
<label for="actionNotes" class="form-label">{{ _("Notes") }}</label>
<textarea class="form-control" id="actionNotes" name="action_notes" rows="3"></textarea>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ _("Close") }}</button>
<button type="submit" class="btn btn-primary">{{ _("Save Changes") }}</button>
</div>
</form>
</div>
</div>
</div>
<div class="row g-3">
<div class="col-12">
<div class="row align-items-center justify-content-between g-3 mb-3"> <div class="row align-items-center justify-content-between g-3 mb-3">
<div class="col-12 col-md-auto"> <div class="col-12 col-md-auto">
<h4 class="mb-0">{{ _("Lead Details")}}</h4> <h4 class="mb-0">{{ _("Lead Details")}}</h4>
@ -25,10 +104,10 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="row g-0 g-md-4 g-xl-6"> <div class="row g-0 g-md-4 g-xl-6">
<div class="col-md-5 col-lg-5 col-xl-4"> <div class="col-md-5 col-lg-5 col-xl-4">
<div class="sticky-leads-sidebar"> <div class="sticky-leads-sidebar">
<div class="lead-details" data-breakpoint="md"> <div class="lead-details" data-breakpoint="md">
<div class="d-flex justify-content-between align-items-center mb-2 d-md-none"> <div class="d-flex justify-content-between align-items-center mb-2 d-md-none">
@ -99,7 +178,7 @@
<div class="d-flex align-items-center mb-1"><span class="me-2 uil uil-clock"></span> <div class="d-flex align-items-center mb-1"><span class="me-2 uil uil-clock"></span>
<h5 class="text-body-highlight mb-0">{{ _("Created")}}</h5> <h5 class="text-body-highlight mb-0">{{ _("Created")}}</h5>
</div> </div>
<p class="mb-0 text-body-secondary">{{ lead.created|date }}</p> <p class="mb-0 text-body-secondary">{{ lead.created|naturalday|capfirst }}</p>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<div class="d-flex align-items-center mb-1"><span class="me-2 uil uil-file-check-alt"></span> <div class="d-flex align-items-center mb-1"><span class="me-2 uil uil-file-check-alt"></span>
@ -130,14 +209,24 @@
</div> </div>
<div class="d-lg-none top-0"></div> <div class="d-lg-none top-0"></div>
</div> </div>
</div> </div>
<div class="col-md-7 col-lg-7 col-xl-8"> <div class="col-md-7 col-lg-7 col-xl-8">
<ul class="nav main-tab nav-underline fs-9 deal-details scrollbar flex-nowrap w-100 pb-1 mb-6 justify-content-end" id="myTab" role="tablist" style="overflow-y: hidden;"> <div 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> &nbsp; <small>{% trans "Current Stage" %}</small></div>
<div class="kanban-header bg-secondary w-50 text-white fw-bold"><i class="fa-solid fa-circle-info me-2"></i>{{lead.next_action|capfirst}} <br> &nbsp; <small>{% trans "Next Action" %}</small></div>
</div>
<ul class="nav main-tab nav-underline fs-9 deal-details scrollbar flex-nowrap w-100 pb-1 mb-6 justify-content-end mt-5" id="myTab" role="tablist" style="overflow-y: hidden;">
<li class="nav-item text-nowrap me-2" role="presentation"><a class="nav-link active" id="activity-tab" data-bs-toggle="tab" href="#tab-activity" role="tab" aria-controls="tab-activity" aria-selected="false" tabindex="-1"> <span class="fa-solid fa-chart-line me-2 tab-icon-color fs-8"></span>{{ _("Activity") }}</a></li> <li class="nav-item text-nowrap me-2" role="presentation"><a class="nav-link active" id="activity-tab" data-bs-toggle="tab" href="#tab-activity" role="tab" aria-controls="tab-activity" aria-selected="false" tabindex="-1"> <span class="fa-solid fa-chart-line me-2 tab-icon-color fs-8"></span>{{ _("Activity") }}</a></li>
<li class="nav-item text-nowrap me-2" role="presentation"><a class="nav-link" id="notes-tab" data-bs-toggle="tab" href="#tab-notes" role="tab" aria-controls="tab-notes" aria-selected="false" tabindex="-1"> <span class="fa-solid fa-clipboard me-2 tab-icon-color fs-8"></span>{{ _("Notes") }}</a></li> <li class="nav-item text-nowrap me-2" role="presentation"><a class="nav-link" id="notes-tab" data-bs-toggle="tab" href="#tab-notes" role="tab" aria-controls="tab-notes" aria-selected="false" tabindex="-1"> <span class="fa-solid fa-clipboard me-2 tab-icon-color fs-8"></span>{{ _("Notes") }}</a></li>
<li class="nav-item text-nowrap me-2" role="presentation"><a class="nav-link" id="emails-tab" data-bs-toggle="tab" href="#tab-emails" role="tab" aria-controls="tab-emails" aria-selected="true"> <span class="fa-solid fa-envelope me-2 tab-icon-color fs-8"></span>{{ _("Emails") }}</a></li> <li class="nav-item text-nowrap me-2" role="presentation"><a class="nav-link" id="emails-tab" data-bs-toggle="tab" href="#tab-emails" role="tab" aria-controls="tab-emails" aria-selected="true"> <span class="fa-solid fa-envelope me-2 tab-icon-color fs-8"></span>{{ _("Emails") }}</a></li>
<li class="nav-item text-nowrap me-2" role="presentation"><a class="nav-link" id="tasks-tab" data-bs-toggle="tab" href="#tab-tasks" role="tab" aria-controls="tab-tasks" aria-selected="true"> <span class="fa-solid fa-envelope me-2 tab-icon-color fs-8"></span>{{ _("Tasks") }}</a></li>
<li class="nav-item text-nowrap ml-auto" role="presentation"> <li class="nav-item text-nowrap ml-auto" role="presentation">
<button class="btn btn-primary" type="button" data-bs-toggle="modal" data-bs-target="#exampleModal">Reassign Lead</button> <button class="btn btn-info btn-sm" type="button" data-bs-toggle="modal" data-bs-target="#exampleModal"> <i class="fa-solid fa-user-plus me-2"></i> Create Opportunity</button>
<button class="btn btn-primary btn-sm" type="button" data-bs-toggle="modal" data-bs-target="#exampleModal"> <i class="fa-solid fa-user-plus me-2"></i> Reassign Lead</button>
<button class="btn btn-primary btn-sm" onclick="openActionModal('{{ lead.id }}', '{{ lead.action }}', '{{ lead.next_action }}', '{{ lead.next_action_date|date:"Y-m-d\TH:i" }}')">
<i class="fa-solid fa-user-plus me-2"></i>
{% trans "Update Actions" %}
</button>
<div class="modal fade" id="exampleModal" tabindex="-1" aria-hidden="true"> <div class="modal fade" id="exampleModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content"> <div class="modal-content">
@ -162,8 +251,9 @@
</ul> </ul>
<div class="tab-content" id="myTabContent"> <div class="tab-content" id="myTabContent">
<div class="tab-pane fade active show" id="tab-activity" role="tabpanel" aria-labelledby="activity-tab"> <div class="tab-pane fade active show" id="tab-activity" role="tabpanel" aria-labelledby="activity-tab">
<div class="mb-1"> <div class="mb-1 d-flex justify-content-between align-items-center">
<h3 class="mb-4" id="scrollspyTask">{{ _("Activities") }} <span class="fw-light fs-7">({{ activities.count}})</span></h3> <h3 class="mb-4" id="scrollspyTask">{{ _("Activities") }} <span class="fw-light fs-7">({{ activities.count}})</span></h3>
<button class="btn btn-phoenix-primary btn-sm" type="button" data-bs-toggle="modal" data-bs-target="#activityModal"><span class="fas fa-plus me-1"></span>{{ _("Add Activity") }}</button>
</div> </div>
<div class="row justify-content-between align-items-md-center hover-actions-trigger btn-reveal-trigger border-translucent py-3 gx-0 border-top"> <div class="row justify-content-between align-items-md-center hover-actions-trigger btn-reveal-trigger border-translucent py-3 gx-0 border-top">
<div class="col-12 col-lg-auto"> <div class="col-12 col-lg-auto">
@ -196,9 +286,9 @@
<div class="d-flex mb-2"> <div class="d-flex mb-2">
<h6 class="lh-sm mb-0 me-2 text-body-secondary timeline-item-title">{{ activity.activity_type|capfirst }}</h6> <h6 class="lh-sm mb-0 me-2 text-body-secondary timeline-item-title">{{ activity.activity_type|capfirst }}</h6>
</div> </div>
<p class="text-body-quaternary fs-9 mb-0 text-nowrap timeline-time"><span class="fa-regular fa-clock me-1"></span>{{ activity.created }}</p> <p class="text-body-quaternary fs-9 mb-0 text-nowrap timeline-time"><span class="fa-regular fa-clock me-1"></span>{{ activity.created|naturalday|capfirst }}</p>
</div> </div>
<h6 class="fs-10 fw-normal mb-3">{{ _("by") }} <a class="fw-semibold" href="#!">{{ activity.created_by }}</a></h6> <h6 class="fs-10 fw-normal mb-3">{{ _("created by") }} <a class="fw-semibold" href="#!">{{ activity.created_by }}</a></h6>
<p class="fs-9 text-body-secondary w-sm-60 mb-5">{{ activity.notes }}</p> <p class="fs-9 text-body-secondary w-sm-60 mb-5">{{ activity.notes }}</p>
</div> </div>
</div> </div>
@ -209,15 +299,14 @@
</div> </div>
</div> </div>
<div class="tab-pane fade" id="tab-notes" role="tabpanel" aria-labelledby="notes-tab"> <div class="tab-pane fade" id="tab-notes" role="tabpanel" aria-labelledby="notes-tab">
<div class="mb-1"> <div class="mb-1 d-flex align-items-center justify-content-between">
<h3 class="mb-4" id="scrollspyNotes">{{ _("Notes") }}</h3> <h3 class="mb-4" id="scrollspyNotes">{{ _("Notes") }}</h3>
</div> <a id="addBtn" href="#" class="btn btn-sm btn-phoenix-primary mb-3 btn-sm" data-url="{% url 'add_note_to_lead' lead.pk %}" data-bs-toggle="modal" data-bs-target="#noteModal" data-note-title="{{ _("Add") }}<i class='fa fa-plus-circle text-success ms-2'></i>">
<div class="d-flex align-items-center justify-content-start">
<a id="addBtn" href="#" class="btn btn-sm btn-phoenix-primary mb-3" data-url="{% url 'add_note_to_lead' lead.pk %}" data-bs-toggle="modal" data-bs-target="#noteModal" data-note-title="{{ _("Add") }}<i class='fa fa-plus-circle text-success ms-2'></i>">
<span class="fas fa-plus me-1"></span> <span class="fas fa-plus me-1"></span>
{% trans 'Add Note' %} {% trans 'Add Note' %}
</a> </a>
</div> </div>
<div class="border-top border-bottom border-translucent" id="leadDetailsTable"> <div class="border-top border-bottom border-translucent" id="leadDetailsTable">
<div class="table-responsive scrollbar mx-n1 px-1"> <div class="table-responsive scrollbar mx-n1 px-1">
<table class="table fs-9 mb-0"> <table class="table fs-9 mb-0">
@ -239,7 +328,7 @@
{% else %} {% else %}
<td class="align-middle white-space-nowrap text-start white-space-nowrap">{{ note.created_by.dealer.get_local_name|default:note.created_by.dealer.name }}</td> <td class="align-middle white-space-nowrap text-start white-space-nowrap">{{ note.created_by.dealer.get_local_name|default:note.created_by.dealer.name }}</td>
{% endif %} {% endif %}
<td class="align-middle text-body-tertiary text-start white-space-nowrap">{{ note.created }}</td> <td class="align-middle text-body-tertiary text-start white-space-nowrap">{{ note.created|naturalday|capfirst }}</td>
<td class="align-middle text-end white-space-nowrap pe-0 action py-2"> <td class="align-middle text-end white-space-nowrap pe-0 action py-2">
{% if note.created_by == request.user %} {% if note.created_by == request.user %}
<a id="updateBtn" href="#" class="btn btn-sm btn-phoenix-primary me-2" data-url="{% url 'update_note_to_lead' note.pk %}" data-bs-toggle="modal" data-bs-target="#noteModal" data-note-title="{{ _("Update") }}<i class='fas fa-pen-square text-primary ms-2'></i>"> <a id="updateBtn" href="#" class="btn btn-sm btn-phoenix-primary me-2" data-url="{% url 'update_note_to_lead' note.pk %}" data-bs-toggle="modal" data-bs-target="#noteModal" data-note-title="{{ _("Update") }}<i class='fas fa-pen-square text-primary ms-2'></i>">
@ -261,8 +350,14 @@
</div> </div>
</div> </div>
<div class="tab-pane fade" id="tab-emails" role="tabpanel" aria-labelledby="emails-tab"> <div class="tab-pane fade" id="tab-emails" role="tabpanel" aria-labelledby="emails-tab">
<div class="mb-1"> <div class="mb-1 d-flex justify-content-between align-items-center">
<h3 class="mb-0" id="scrollspyEmails">{{ _("Emails") }}</h3> <h3 class="mb-0" id="scrollspyEmails">{{ _("Emails") }}</h3>
<a href="{% url 'send_lead_email' lead.pk %}">
<button type="button" class="btn btn-sm btn-phoenix-primary">
<span class="fas fa-plus me-1"></span>
{% trans 'Send Email' %}
</button>
</a>
</div> </div>
<div> <div>
<div class="scrollbar"> <div class="scrollbar">
@ -302,7 +397,7 @@
<div class="fs-10 d-block">{{email.to_email}}</div> <div class="fs-10 d-block">{{email.to_email}}</div>
</td> </td>
<td class="sent align-middle white-space-nowrap text-start fw-bold text-body-tertiary py-2">{{email.from_email}}</td> <td class="sent align-middle white-space-nowrap text-start fw-bold text-body-tertiary py-2">{{email.from_email}}</td>
<td class="date align-middle white-space-nowrap text-body py-2">{{email.created}}</td> <td class="date align-middle white-space-nowrap text-body py-2">{{email.created|naturalday}}</td>
<td class="align-middle white-space-nowrap ps-3"><a class="text-body" href=""><span class="fa-solid fa-phone text-primary me-2"></span>Call</a></td> <td class="align-middle white-space-nowrap ps-3"><a class="text-body" href=""><span class="fa-solid fa-phone text-primary me-2"></span>Call</a></td>
<td class="status align-middle fw-semibold text-end py-2"><span class="badge badge-phoenix fs-10 badge-phoenix-success">sent</span></td> <td class="status align-middle fw-semibold text-end py-2"><span class="badge badge-phoenix fs-10 badge-phoenix-success">sent</span></td>
</tr> </tr>
@ -375,13 +470,73 @@
</div> </div>
</div> </div>
</div> </div>
{% comment %} {% endcomment %}
<div class="tab-pane fade" id="tab-tasks" role="tabpanel" aria-labelledby="tasks-tab">
<div class="mb-1 d-flex justify-content-between align-items-center">
<h3 class="mb-0" id="scrollspyEmails">{{ _("Tasks") }}</h3>
<button class="btn btn-phoenix-primary btn-sm" type="button" data-bs-toggle="modal" data-bs-target="#taskModal"><span class="fas fa-plus me-1"></span>{{ _("Add Task") }}</button>
</div>
<div>
<div class="border-top border-bottom border-translucent" id="allEmailsTable" data-list='{"valueNames":["subject","sent","date","source","status"],"page":7,"pagination":true}'>
<div class="table-responsive scrollbar mx-n1 px-1">
<table class="table fs-9 mb-0">
<thead>
<tr>
<th class="white-space-nowrap fs-9 align-middle ps-0" style="width:26px;">
<div class="form-check mb-0 fs-8">
<input class="form-check-input" type="checkbox" data-bulk-select='{"body":"all-email-table-body"}' />
</div>
</th>
<th class="sort white-space-nowrap align-middle pe-3 ps-0 text-uppercase" scope="col" data-sort="subject" style="width:31%; min-width:350px">Title</th>
<th class="sort align-middle pe-3 text-uppercase" scope="col" data-sort="sent" style="width:15%; min-width:130px">Assigned to</th>
<th class="sort align-middle text-start text-uppercase" scope="col" data-sort="date" style="min-width:165px">Due Date</th>
<th class="sort align-middle text-start text-uppercase" scope="col" data-sort="date" style="min-width:165px">Completed</th>
</tr>
</thead>
<tbody class="list" id="all-email-table-body">
{% for task in tasks %}
<tr class="hover-actions-trigger btn-reveal-trigger position-static {% if task.completed %}completed-task{% endif %}">
<td class="fs-9 align-middle px-0 py-3">
<div class="form-check mb-0 fs-8">
<input class="form-check-input" type="checkbox" hx-post="{% url 'update_task' task.pk %}" hx-trigger="change" hx-swap="none" />
</div>
</td>
<td class="subject order align-middle white-space-nowrap py-2 ps-0"><a class="fw-semibold text-primary" href="">{{task.title}}</a>
<div class="fs-10 d-block">{{task.description}}</div>
</td>
<td class="sent align-middle white-space-nowrap text-start fw-bold text-body-tertiary py-2">{{task.assigned_to}}</td>
<td class="date align-middle white-space-nowrap text-body py-2">{{task.created|naturalday|capfirst}}</td>
<td class="date align-middle white-space-nowrap text-body py-2">
{% if task.completed %}
<span class="badge badge-phoenix fs-10 badge-phoenix-success"><i class="fa-solid fa-check"></i></span>
{% else %}
<span class="badge badge-phoenix fs-10 badge-phoenix-warning"><i class="fa-solid fa-xmark"></i></span>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="row align-items-center justify-content-between py-2 pe-0 fs-9">
<div class="col-auto d-flex">
<p class="mb-0 d-none d-sm-block me-3 fw-semibold text-body" data-list-info="data-list-info"></p><a class="fw-semibold" href="" data-list-view="*">View all<span class="fas fa-angle-right ms-1" data-fa-transform="down-1"></span></a><a class="fw-semibold d-none" href="" data-list-view="less">View Less<span class="fas fa-angle-right ms-1" data-fa-transform="down-1"></span></a>
</div>
<div class="col-auto d-flex">
<button class="page-link" data-list-pagination="prev"><span class="fas fa-chevron-left"></span></button>
<ul class="mb-0 pagination"></ul>
<button class="page-link pe-0" data-list-pagination="next"><span class="fas fa-chevron-right"></span></button>
</div>
</div>
</div>
</div>
</div> </div>
</div>
</div>
{% include 'modal/delete_modal.html' %} {% include 'modal/delete_modal.html' %}
<!-- add update Modal --> <!-- add update Modal -->
<div class="modal fade" id="noteModal" tabindex="-1" aria-labelledby="noteModalLabel" aria-hidden="true"> <div class="modal fade" id="noteModal" tabindex="-1" aria-labelledby="noteModalLabel" aria-hidden="true">
<div class="modal-dialog modal-sm"> <div class="modal-dialog modal-md">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header justify-content-between align-items-start gap-5 px-4 pt-4 pb-3 border-0"> <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="noteModalLabel">{% trans 'Notes' %}</h4> <h4 class="modal-title" id="noteModalLabel">{% trans 'Notes' %}</h4>
@ -394,9 +549,36 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<script>
document.addEventListener("DOMContentLoaded", function () { <!-- activity Modal -->
{% include "components/activity_modal.html" with content_type="lead" pk=lead.pk %}
<!-- task Modal -->
<div class="modal fade" id="taskModal" tabindex="-1" aria-labelledby="taskModalLabel" aria-hidden="true">
<div class="modal-dialog modal-md">
<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="noteModalLabel">{% trans 'Task' %}</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 class="modal-body">
<form action="{% url 'add_task' 'lead' lead.pk %}" method="post" class="add_task_form">
{% csrf_token %}
{{ staff_task_form|crispy }}
<button type="submit" class="btn btn-success w-100">{% trans 'Save' %}</button>
</form>
</div>
</div>
</div>
</div>
{% endblock content %}
{% block customJS %}
<script>
document.addEventListener("DOMContentLoaded", function () {
const noteModal = document.getElementById("noteModal"); const noteModal = document.getElementById("noteModal");
const modalTitle = document.getElementById("noteModalLabel"); const modalTitle = document.getElementById("noteModalLabel");
@ -418,6 +600,128 @@ document.addEventListener("DOMContentLoaded", function () {
console.error("Error loading form:", error); console.error("Error loading form:", error);
}); });
}); });
}); });
</script>
{% endblock %} let Toast = Swal.mixin({
toast: true,
position: "top-end",
showConfirmButton: false,
timer: 3000,
timerProgressBar: true,
didOpen: (toast) => {
toast.onmouseenter = Swal.stopTimer;
toast.onmouseleave = Swal.resumeTimer;
}
});
// Display Django messages
{% if messages %}
{% for message in messages %}
Toast.fire({
icon: "{{ message.tags }}",
titleText: "{{ message|safe }}"
});
{% endfor %}
{% endif %}
function openActionModal(leadId, currentAction, nextAction, nextActionDate) {
const modal = new bootstrap.Modal(document.getElementById('actionTrackingModal'));
document.getElementById('leadId').value = leadId;
document.getElementById('currentAction').value = currentAction;
document.getElementById('nextAction').value = nextAction;
document.getElementById('nextActionDate').value = nextActionDate;
modal.show();
}
document.getElementById('actionTrackingForm').addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
// Show loading indicator
Swal.fire({
toast: true,
icon: 'info',
text: 'Please wait...',
allowOutsideClick: false,
position: "top-end",
showConfirmButton: false,
timer: 2000,
timerProgressBar: false,
didOpen: (toast) => {
toast.onmouseenter = Swal.stopTimer;
toast.onmouseleave = Swal.resumeTimer;
}
});
fetch("{% url 'update_lead_actions' %}", {
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({
icon: tag,
titleText: msg
});
}
</script>
{% endblock customJS %}

View File

@ -2,7 +2,7 @@
{% load i18n static crispy_forms_filters %} {% load i18n static crispy_forms_filters %}
{% block content %} {% block content %}
<div class="container-fluid"> <div class="container-fluid">
<h1>{% if object %}{{ _("Update") }}{% else %}{{ _("Create") }}{% endif %}</h1> <h1>{% if object %}{{ _("Update") }}{% else %}{{ _("Create") }}{% endif %}</h1>
<div class="row mb-3"> <div class="row mb-3">
<div class="col-sm-6 col-md-8"> <div class="col-sm-6 col-md-8">
@ -18,5 +18,5 @@
</form> </form>
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,9 +1,9 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% load i18n static %} {% load i18n static humanize %}
{% block title %}{{ _('Leads')|capfirst }}{% endblock title %} {% block title %}{{ _('Leads')|capfirst }}{% endblock title %}
{% block content %} {% block content %}
<div class="row g-3"> <div class="row g-3">
<h2 class="mb-4">{{ _("Leads")|capfirst }}</h2> <h2 class="mb-4">{{ _("Leads")|capfirst }}</h2>
<!-- Action Tracking Modal --> <!-- Action Tracking Modal -->
<div class="modal fade" id="actionTrackingModal" tabindex="-1" aria-labelledby="actionTrackingModalLabel" aria-hidden="true"> <div class="modal fade" id="actionTrackingModal" tabindex="-1" aria-labelledby="actionTrackingModalLabel" aria-hidden="true">
@ -112,19 +112,7 @@
<th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 10%;"> <th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 10%;">
<div class="d-inline-flex flex-center"> <div class="d-inline-flex flex-center">
<div class="d-flex align-items-center bg-info-subtle rounded me-2"><span class="text-info-dark" data-feather="database"></span></div> <div class="d-flex align-items-center bg-info-subtle rounded me-2"><span class="text-info-dark" data-feather="database"></span></div>
<span>{{ _("Current Action")|capfirst }}</span> <span>{{ _("Action")|capfirst }}</span>
</div>
</th>
<th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 10%;">
<div class="d-inline-flex flex-center">
<div class="d-flex align-items-center bg-info-subtle rounded me-2"><span class="text-info-dark" data-feather="database"></span></div>
<span>{{ _("Next Action")|capfirst }}</span>
</div>
</th>
<th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 10%;">
<div class="d-inline-flex flex-center">
<div class="d-flex align-items-center bg-info-subtle rounded me-2"><span class="text-info-dark" data-feather="database"></span></div>
<span>{{ _("Next Action Date")|capfirst }}</span>
</div> </div>
</th> </th>
<th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 10%;"> <th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 10%;">
@ -133,32 +121,15 @@
<span>{{ _("Assigned To")|capfirst }}</span> <span>{{ _("Assigned To")|capfirst }}</span>
</div> </div>
</th> </th>
<th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 10%;">
<div class="d-inline-flex flex-center">
<div class="d-flex align-items-center bg-info-subtle rounded me-2"><span class="text-info-dark" data-feather="database"></span></div>
<span>{{ _("Source")|capfirst }}</span>
</div>
</th>
<th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 10%;"> <th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 10%;">
<div class="d-inline-flex flex-center"> <div class="d-inline-flex flex-center">
<div class="d-flex align-items-center bg-warning-subtle rounded me-2"><span class="text-warning-dark" data-feather="grid"></span></div> <div class="d-flex align-items-center bg-warning-subtle rounded me-2"><span class="text-warning-dark" data-feather="grid"></span></div>
<span>{{ _("Channel")|capfirst }}</span> <span>{{ _("Opportunity")|capfirst }}</span>
</div>
</th>
<th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 10%;">
<div class="d-inline-flex flex-center">
<div class="d-flex align-items-center bg-warning-subtle rounded me-2"><span class="text-warning-dark" data-feather="grid"></span></div>
<span>{{ _("Stage")|capfirst }}</span>
</div>
</th>
<th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 10%;">
<div class="d-inline-flex flex-center">
<div class="d-flex align-items-center bg-warning-subtle rounded me-2"><span class="text-warning-dark" data-feather="grid"></span></div>
<span>{{ _("Is Opportunity")|capfirst }}</span>
</div> </div>
</th> </th>
<th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 15%;"> <th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 15%;">
{{ _("Create date") }} {{ _("Action") }}
</th> </th>
<th class="text-end white-space-nowrap align-middle" scope="col"></th> <th class="text-end white-space-nowrap align-middle" scope="col"></th>
</tr> </tr>
@ -230,15 +201,15 @@
{% if schedule.scheduled_type == "call" %} {% if schedule.scheduled_type == "call" %}
<a href="{% url 'appointment:get_user_appointments' %}"> <a href="{% url 'appointment:get_user_appointments' %}">
<span class="badge badge-phoenix badge-phoenix-primary text-primary {% if schedule.schedule_past_date %}badge-phoenix-danger text-danger{% endif %} fw-semibold"><span class="text-primary {% if schedule.schedule_past_date %}text-danger{% endif %}" data-feather="phone"></span> <span class="badge badge-phoenix badge-phoenix-primary text-primary {% if schedule.schedule_past_date %}badge-phoenix-danger text-danger{% endif %} fw-semibold"><span class="text-primary {% if schedule.schedule_past_date %}text-danger{% endif %}" data-feather="phone"></span>
{{ schedule.scheduled_at }}</span></a> {{ schedule.scheduled_at|naturalday|capfirst }}</span></a>
{% elif schedule.scheduled_type == "meeting" %} {% elif schedule.scheduled_type == "meeting" %}
<a href="{% url 'appointment:get_user_appointments' %}"> <a href="{% url 'appointment:get_user_appointments' %}">
<span class="badge badge-phoenix badge-phoenix-success text-success fw-semibold"><span class="text-success" data-feather="calendar"></span> <span class="badge badge-phoenix badge-phoenix-success text-success fw-semibold"><span class="text-success" data-feather="calendar"></span>
{{ schedule.scheduled_at }}</span></a> {{ schedule.scheduled_at|naturalday|capfirst }}</span></a>
{% elif schedule.scheduled_type == "email" %} {% elif schedule.scheduled_type == "email" %}
<a href="{% url 'appointment:get_user_appointments' %}"> <a href="{% url 'appointment:get_user_appointments' %}">
<span class="badge badge-phoenix badge-phoenix-warning text-warning fw-semibold"><span class="text-warning" data-feather="email"></span> <span class="badge badge-phoenix badge-phoenix-warning text-warning fw-semibold"><span class="text-warning" data-feather="email"></span>
{{ schedule.scheduled_at }}</span></a> {{ schedule.scheduled_at|naturalday|capfirst }}</span></a>
{% endif %} {% endif %}
</td> </td>
<td> <td>
@ -255,12 +226,8 @@
</div> </div>
</td> </td>
<td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">{{ lead.get_status|upper }}</td> <td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">{{ lead.get_status|upper }}</td>
<td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">{% if lead.next_action %}{{ lead.next_action|upper }}{% endif %}</td>
<td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">{% if lead.next_action %}{{ lead.next_action_date|upper }}{% endif %}</td>
<td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">{{ lead.staff|upper }}</td> <td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">{{ lead.staff|upper }}</td>
<td class="align-middle white-space-nowrap fw-semibold text-body-highlight">{{ lead.source|upper }}</td> {% comment %} <td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">
<td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">{{ lead.channel|upper }}</td>
<td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">
{% if lead.opportunity.stage == "prospect" %} {% if lead.opportunity.stage == "prospect" %}
<span class="badge text-bg-primary">{{ lead.opportunity.stage|upper }}</span> <span class="badge text-bg-primary">{{ lead.opportunity.stage|upper }}</span>
{% elif lead.opportunity.stage == "proposal" %} {% elif lead.opportunity.stage == "proposal" %}
@ -272,14 +239,12 @@
{% elif lead.opportunity.stage == "closed_lost" %} {% elif lead.opportunity.stage == "closed_lost" %}
<span class="badge text-bg-danger">{{ lead.opportunity.stage|upper }}</span> <span class="badge text-bg-danger">{{ lead.opportunity.stage|upper }}</span>
{% endif %} {% endif %}
</td> </td> {% endcomment %}
<td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight"> <td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">
{% if lead.opportunity %} {% if lead.opportunity %}
<a href="{% url 'opportunity_detail' lead.opportunity.id %}"> <a href="{% url 'opportunity_detail' lead.opportunity.id %}">
<span class="badge badge-phoenix badge-phoenix-success">View Details <i class="fa-solid fa-arrow-up-right-from-square"></i></span> <span class="badge badge-phoenix badge-phoenix-success">Opportunity {{ lead.opportunity.lead}} <i class="fa-solid fa-arrow-up-right-from-square"></i></span>
</a> </a>
{% else %}
<span class="badge badge-phoenix badge-phoenix-danger">{{ _("No") }}</span>
{% endif %} {% endif %}
</td> </td>
<td class="align-middle white-space-nowrap text-end"> <td class="align-middle white-space-nowrap text-end">
@ -363,13 +328,13 @@
{% endif %} {% endif %}
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}
{% block customJS %} {% block customJS %}
<script> <script>
// Initialize SweetAlert Toast for general messages // Initialize SweetAlert Toast for general messages
let Toast = Swal.mixin({ let Toast = Swal.mixin({
toast: true, toast: true,

View File

@ -5,7 +5,7 @@
{% block title %}{{ _("Leads") }}{% endblock title %} {% block title %}{{ _("Leads") }}{% endblock title %}
{% block content %} {% block content %}
<div class="card email-content"> <div class="card email-content">
<h5 class="card-header">Send Mail</h5> <h5 class="card-header">Send Mail</h5>
<div class="card-body"> <div class="card-body">
<form class="d-flex flex-column h-100" action="{% url 'send_lead_email' lead.pk %}" method="post"> <form class="d-flex flex-column h-100" action="{% url 'send_lead_email' lead.pk %}" method="post">
@ -34,7 +34,7 @@
</form> </form>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
{% endblock content %} {% endblock content %}

View File

@ -3,7 +3,7 @@
{% block title %}{{ _('Leads')|capfirst }}{% endblock title %} {% block title %}{{ _('Leads')|capfirst }}{% endblock title %}
{% block customCSS %} {% block customCSS %}
<style> <style>
.kanban-column { .kanban-column {
background-color: #f8f9fa; background-color: #f8f9fa;
border-radius: 8px; border-radius: 8px;
@ -42,7 +42,23 @@
.lead-card small { .lead-card small {
color: #6c757d; color: #6c757d;
} }
</style> .bg-success-soft {
background-color: rgba(17, 240, 66, 0.1) !important;
opacity: .8;
}
.bg-danger-soft {
background-color: rgba(230, 50, 68, 0.1) !important;
opacity: .8;
}
.bg-info-soft {
background-color: rgba(41, 197, 245, 0.1) !important;
opacity: .8;
}
.bg-negotiation-soft {
background-color: rgba(113, 206, 206, 0.1) !important;
opacity: .8;
}
</style>
{% endblock customCSS %} {% endblock customCSS %}
{% block content %} {% block content %}
<div class="container-fluid my-4"> <div class="container-fluid my-4">
@ -51,7 +67,7 @@
</div> </div>
<div class="row g-3"> <div class="row g-3">
<!-- Column Template --> <!-- New Lead -->
<div class="col-md"> <div class="col-md">
<div class="kanban-column"> <div class="kanban-column">
<div class="kanban-header">New Leads ({{new|length}})</div> <div class="kanban-header">New Leads ({{new|length}})</div>
@ -83,38 +99,6 @@
</div> </div>
</div> </div>
<!-- Under Review -->
<div class="col-md">
<div class="kanban-column">
<div class="kanban-header">Won ({{won|length}})</div>
{% for lead in won %}
<a href="{% url 'lead_detail' lead.id %}">
<div class="lead-card">
<strong>{{lead.full_name|capfirst}}</strong><br>
<small>{{lead.email}}</small><br>
<small>{{lead.phone_number}}</small>
</div>
</a>
{% endfor %}
</div>
</div>
<!-- Demo -->
<div class="col-md">
<div class="kanban-column">
<div class="kanban-header">Lose ({{lose|length}})</div>
{% for lead in lose %}
<a href="{% url 'lead_detail' lead.id %}">
<div class="lead-card">
<strong>{{lead.full_name|capfirst}}</strong><br>
<small>{{lead.email}}</small><br>
<small>{{lead.phone_number}}</small>
</div>
</a>
{% endfor %}
</div>
</div>
<!-- Negotiation --> <!-- Negotiation -->
<div class="col-md"> <div class="col-md">
<div class="kanban-column"> <div class="kanban-column">
@ -130,6 +114,39 @@
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
<!-- Won -->
<div class="col-md">
<div class="kanban-column">
<div class="kanban-header">Won ({{won|length}})</div>
{% for lead in won %}
<a href="{% url 'lead_detail' lead.id %}">
<div class="lead-card">
<strong>{{lead.full_name|capfirst}}</strong><br>
<small>{{lead.email}}</small><br>
<small>{{lead.phone_number}}</small>
</div>
</a>
{% endfor %}
</div>
</div>
<!-- Lose -->
<div class="col-md">
<div class="kanban-column">
<div class="kanban-header">Lose ({{lose|length}})</div>
{% for lead in lose %}
<a href="{% url 'lead_detail' lead.id %}">
<div class="lead-card">
<strong>{{lead.full_name|capfirst}}</strong><br>
<small>{{lead.email}}</small><br>
<small>{{lead.phone_number}}</small>
</div>
</a>
{% endfor %}
</div>
</div>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -20,9 +20,9 @@
color: #aaa; color: #aaa;
} }
</style> </style>
{% endblock customCSS %} {% endblock customCSS %}
{% block content %} {% block content %}
<div class="container-fluid"> <div class="container-fluid">
<!-- Welcome Row --> <!-- Welcome Row -->
<div class="d-flex justify-content-between align-items-center mb-3"> <div class="d-flex justify-content-between align-items-center mb-3">

View File

@ -2,8 +2,8 @@
{% load i18n static crispy_forms_filters %} {% load i18n static crispy_forms_filters %}
{% block content %} {% block content %}
<h3>{% if object %}{{ _("Update") }}{% else %}{{ _("Create") }}{% endif %}</h3> <h3>{% if object %}{{ _("Update") }}{% else %}{{ _("Create") }}{% endif %}</h3>
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %}
{{ form|crispy }} {{ form|crispy }}
<button <button
@ -17,5 +17,5 @@
<a href="{% url 'lead_list' %}" class="btn btn-phoenix-secondary"> <a href="{% url 'lead_list' %}" class="btn btn-phoenix-secondary">
{{ _("Cancel") }} {{ _("Cancel") }}
</a> </a>
</form> </form>
{% endblock %} {% endblock %}

View File

@ -2,16 +2,16 @@
{% if form.instance.pk %} {% if form.instance.pk %}
<form method="post" action="{% url 'update_note_to_lead' note.pk %}" enctype="multipart/form-data"> <form method="post" action="{% url 'update_note_to_lead' note.pk %}" enctype="multipart/form-data">
{% else %} {% else %}
<form method="post" action="{% url 'add_note_to_lead' lead.pk %}" enctype="multipart/form-data"> <form method="post" action="{% url 'add_note_to_lead' lead.pk %}" enctype="multipart/form-data">
{% endif %} {% endif %}
{% csrf_token %} {% csrf_token %}
{{ form|crispy }} {{ form|crispy }}
{% if form.instance.pk %} {% if form.instance.pk %}
<button type="submit" class="btn btn-sm btn-primary w-100">{{ _("Update") }}</button> <button type="submit" class="btn btn-sm btn-primary w-100">{{ _("Update") }}</button>
{% else %} {% else %}
<button type="submit" class="btn btn-sm btn-success w-100">{{ _("Add") }}</button> <button type="submit" class="btn btn-sm btn-success w-100">{{ _("Add") }}</button>
{% endif %} {% endif %}
</form> </form>

View File

@ -31,4 +31,4 @@
<div class="my-2 text-center fw-bold fs-10 text-body-tertiary text-opactity-85"><a class="fw-bolder" href="{% url 'notifications_history' %}">Notification history</a></div> <div class="my-2 text-center fw-bold fs-10 text-body-tertiary text-opactity-85"><a class="fw-bolder" href="{% url 'notifications_history' %}">Notification history</a></div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -2,10 +2,10 @@
{% block content %} {% block content %}
<div class="content"> <div class="content">
<h2 class="mb-5">{{ _("Notifications") }}</h2> <h2 class="mb-5">{{ _("Notifications") }}</h2>
{% if notifications %} {% if notifications %}
<div class="mx-n4 mx-lg-n6 mb-5 border-bottom"> <div class="mx-n4 mx-lg-n6 mb-5 border-bottom">
{% for notification in notifications %} {% for notification in notifications %}
<div class="d-flex align-items-center justify-content-between py-3 px-lg-6 px-4 notification-card border-top"> <div class="d-flex align-items-center justify-content-between py-3 px-lg-6 px-4 notification-card border-top">
@ -27,7 +27,7 @@
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
<div class="pagination"> <div class="pagination">
<span class="step-links"> <span class="step-links">
{% if notifications.has_previous %} {% if notifications.has_previous %}
@ -45,9 +45,9 @@
{% endif %} {% endif %}
</span> </span>
</div> </div>
{% else %} {% else %}
<p>No notifications found.</p> <p>No notifications found.</p>
{% endif %} {% endif %}

View File

@ -1,11 +1,11 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% block content %} {% block content %}
<h1>Delete Opportunity</h1> <h1>Delete Opportunity</h1>
<p>Are you sure you want to delete "{{ object.deal_name }}"?</p> <p>Are you sure you want to delete "{{ object.deal_name }}"?</p>
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %}
<button type="submit">Yes, delete</button> <button type="submit">Yes, delete</button>
<a href="{% url 'opportunity_list' %}">Cancel</a> <a href="{% url 'opportunity_list' %}">Cancel</a>
</form> </form>
{% endblock %} {% endblock %}

View File

@ -1,5 +1,5 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% load i18n static %} {% load i18n static humanize %}
{% block content %} {% block content %}
<div class="row align-items-center justify-content-between g-3 mb-4"> <div class="row align-items-center justify-content-between g-3 mb-4">
@ -18,7 +18,8 @@
<a class="dropdown-item" href="{% url 'estimate_create_from_opportunity' opportunity.pk %}">{{ _("Create Quotation")}}</a> <a class="dropdown-item" href="{% url 'estimate_create_from_opportunity' opportunity.pk %}">{{ _("Create Quotation")}}</a>
{% endif %} {% endif %}
</li> </li>
<li><a class="dropdown-item text-danger" href="">Delete Lead</a></li> <li><a class="dropdown-item" href="{% url 'update_opportunity' opportunity.pk %}">Update Opportunity</a></li>
<li><a class="dropdown-item text-danger" href="">Delete Opportunity</a></li>
</ul> </ul>
</div> </div>
</div> </div>
@ -169,9 +170,9 @@
<p class="fw-bold mb-0">{{ _("Estimated Revenue") }}</p> <p class="fw-bold mb-0">{{ _("Estimated Revenue") }}</p>
</div> </div>
</td> </td>
<td class="py-2 d-none d-sm-block pe-sm-2">:{{opportunity.estimate.get_revenue_estimate}}</td> <td class="py-2 d-none d-sm-block pe-sm-2">:</td>
<td class="py-2"> <td class="py-2">
<p class="ps-6 ps-sm-0 fw-semibold mb-0">{{ opportunity.car.finances.revenue }}</p> <p class="ps-6 ps-sm-0 fw-semibold mb-0"><span class="currency">{{CURRENCY}}</span>{{ opportunity.expected_revenue }}</p>
</td> </td>
</tr> </tr>
</table> </table>
@ -296,7 +297,7 @@
</div> </div>
</div> </div>
<div class="col-auto"> <div class="col-auto">
<button class="btn btn-phoenix-primary px-6">Add Activity</button> <button class="btn btn-phoenix-primary btn-sm" type="button" data-bs-toggle="modal" data-bs-target="#activityModal"><span class="fas fa-plus me-1"></span>{{ _("Add Activity") }}</button>
</div> </div>
</div> </div>
{% for activity in activities %} {% for activity in activities %}
@ -307,7 +308,7 @@
<span class="fa-solid fa-phone text-warning fs-8"></span> <span class="fa-solid fa-phone text-warning fs-8"></span>
{% elif activity.activity_type == "email" %} {% elif activity.activity_type == "email" %}
<span class="fa-solid fa-envelope text-info-light fs-8"></span> <span class="fa-solid fa-envelope text-info-light fs-8"></span>
{% elif activity.activity_type == "visit" %} {% elif activity.activity_type == "meeting" %}
<span class="fa-solid fa-users text-danger fs-8"></span> <span class="fa-solid fa-users text-danger fs-8"></span>
{% elif activity.activity_type == "whatsapp" %} {% elif activity.activity_type == "whatsapp" %}
<span class="fab fa-whatsapp text-success-dark fs-7"></span> <span class="fab fa-whatsapp text-success-dark fs-7"></span>
@ -319,7 +320,7 @@
<h5 class="text-body-highlight lh-sm"></h5> <h5 class="text-body-highlight lh-sm"></h5>
<p class="fs-9 mb-0">by<a class="ms-1" href="#!">{{activity.created_by}}</a></p> <p class="fs-9 mb-0">by<a class="ms-1" href="#!">{{activity.created_by}}</a></p>
</div> </div>
<div class="fs-9"><span class="fa-regular fa-calendar-days text-primary me-2"></span><span class="fw-semibold">{{activity.created}}</span></div> <div class="fs-9"><span class="fa-regular fa-calendar-days text-primary me-2"></span><span class="fw-semibold">{{activity.created|naturalday|capfirst}}</span></div>
</div> </div>
<p class="fs-9 mb-0"></p> <p class="fs-9 mb-0"></p>
</div> </div>
@ -552,4 +553,5 @@
</div> </div>
</div> </div>
</div> </div>
{% include "components/activity_modal.html" with content_type="opportunity" pk=opportunity.pk %}
{% endblock %} {% endblock %}

View File

@ -1,95 +1,203 @@
{% extends "base.html" %} <!-- Assuming you have a base template --> {% extends 'base.html' %}
{% load i18n %} <!-- Load the internationalization template tags --> {% load i18n static widget_tweaks custom_filters %}
{% block content %} {% block content %}
<div class="container-fluid">
<div class="row g-3 mb-4 align-items-center">
<div class="col">
<h2 class="mb-0">
{% if form.instance.pk %}
{% trans "Edit Opportunity" %}
{% else %}
{% trans "Create New Opportunity" %}
{% endif %}
</h2>
</div>
<div class="col-auto">
<a href="{% url 'opportunity_list' %}" class="btn btn-phoenix-secondary">
<span class="fas fa-arrow-left me-2"></span>{% trans "Back to list" %}
</a>
</div>
</div>
<div class="row g-3"> <div class="row g-3">
<div class="col-sm-6 col-md-8"> <div class="col-lg-8">
<h2>{% if form.instance.pk %}{{ _("Edit Opportunity") }}{% else %}{{ _("Add New Opportunity") }}{% endif %}</h2> <div class="card">
</div> <div class="card-body p-4 p-sm-5">
<div class="col-sm-6 col-md-8"> <form method="post" enctype="multipart/form-data">
<form class="row g-3" method="post" class="form" novalidate>
{% csrf_token %} {% csrf_token %}
<!-- Customer --> {% if form.non_field_errors %}
<div class="col-sm-6 col-md-4"> <div class="alert alert-danger">
<div class="form-floating"> {{ form.non_field_errors }}
<select class="form-control" id="{{ form.customer.id_for_label }}" name="{{ form.customer.name }}">
{% for value, label in form.customer.field.choices %}
<option value="{{ value }}" {% if form.customer.value == value %}selected{% endif %}>{{ label }}</option>
{% endfor %}
</select>
<label for="{{ form.customer.id_for_label }}">{{ _("Customer") }}</label>
</div> </div>
{{ form.customer.errors }} {% endif %}
<!-- Lead Field -->
<div class="mb-4">
<label class="form-label" for="{{ form.lead.id_for_label }}">
{{ form.lead.label }}
<span class="text-danger">*</span>
</label>
{{ form.lead|add_class:"form-control" }}
{% if form.lead.errors %}
<div class="invalid-feedback d-block">
{{ form.lead.errors }}
</div>
{% endif %}
</div> </div>
<!-- Car --> <!-- Car Field -->
<div class="col-sm-6 col-md-4"> <div class="mb-4">
<div class="form-floating"> <label class="form-label" for="{{ form.car.id_for_label }}">
<select class="form-control" id="{{ form.car.id_for_label }}" name="{{ form.car.name }}"> {{ form.car.label }}
{% for value, label in form.car.field.choices %} <span class="text-danger">*</span>
<option value="{{ value }}" {% if form.car.value == value %}selected{% endif %}>{{ label }}</option> </label>
{% endfor %} {{ form.car|add_class:"form-control" }}
</select> {% if form.car.errors %}
<label for="{{ form.car.id_for_label }}">{{ _("Car") }}</label> <div class="invalid-feedback d-block">
</div>
{{ form.car.errors }} {{ form.car.errors }}
</div> </div>
{% endif %}
<!-- Stage -->
<div class="col-sm-6 col-md-4">
<div class="form-floating">
<select class="form-control" id="{{ form.stage.id_for_label }}" name="{{ form.stage.name }}">
{% for value, label in form.stage.field.choices %}
<option value="{{ value }}" {% if form.stage.value == value %}selected{% endif %}>{{ label }}</option>
{% endfor %}
</select>
<label for="{{ form.stage.id_for_label }}">{{ _("Stage") }}</label>
</div> </div>
<!-- Stage Field -->
<div class="mb-4">
<label class="form-label" for="{{ form.stage.id_for_label }}">
{{ form.stage.label }}
<span class="text-danger">*</span>
</label>
{{ form.stage|add_class:"form-control" }}
{% if form.stage.errors %}
<div class="invalid-feedback d-block">
{{ form.stage.errors }} {{ form.stage.errors }}
</div> </div>
{% endif %}
<!-- Probability -->
<div class="col-sm-6 col-md-4">
<div class="form-floating">
<input type="number" class="form-control" id="{{ form.probability.id_for_label }}" name="{{ form.probability.name }}" value="{{ form.probability.value|default:'' }}" placeholder="{{ _('Enter probability') }}">
<label for="{{ form.probability.id_for_label }}">{{ _("Probability") }}</label>
</div> </div>
<!-- Probability Field -->
<div class="mb-4">
<label class="form-label" for="{{ form.probability.id_for_label }}">
{{ form.probability.label }}
<span class="text-danger">*</span>
</label>
<div class="d-flex align-items-center gap-3">
<input type="range"
name="{{ form.probability.name }}"
id="{{ form.probability.id_for_label }}"
min="0" max="100" step="1"
value="{{ form.probability.value|default:'50' }}"
class="form-control form-range"
oninput="updateProbabilityValue(this.value)">
<span id="probability-value" class="badge badge-phoenix fs-6 badge-phoenix-primary">
{{ form.probability.value|default:'50' }}%
</span>
</div>
{% if form.probability.errors %}
<div class="invalid-feedback d-block">
{{ form.probability.errors }} {{ form.probability.errors }}
</div> </div>
{% endif %}
<!-- Staff -->
<div class="col-sm-6 col-md-4">
<div class="form-floating">
<select class="form-control" id="{{ form.staff.id_for_label }}" name="{{ form.staff.name }}">
{% for value, label in form.staff.field.choices %}
<option value="{{ value }}" {% if form.staff.value == value %}selected{% endif %}>{{ label }}</option>
{% endfor %}
</select>
<label for="{{ form.staff.id_for_label }}">{{ _("Staff") }}</label>
</div>
{{ form.staff.errors }}
</div> </div>
<!-- closing date--> <!-- Expected Revenue -->
<div class="col-sm-6 col-md-4"> <div class="mb-4">
<div class="form-floating"> <label class="form-label" for="{{ form.expected_revenue.id_for_label }}">
<input type="date" class="form-control" id="{{ form.closing_date.id_for_label }}" name="{{ form.closing_date.name }}" value="{{ form.closing_date.value|date:'Y-m-d' }}"> {{ form.expected_revenue.label }}
<label for="{{ form.closing_date.id_for_label }}">{{ _("Closing Date")}}</label> </label>
<div class="input-group">
<span class="input-group-text"><span class="currency">{{CURRENCY}}</span></span>
{{ form.expected_revenue|add_class:"form-control" }}
</div>
{% if form.expected_revenue.errors %}
<div class="invalid-feedback d-block">
{{ form.expected_revenue.errors }}
</div>
{% endif %}
</div>
<!-- Closing Date -->
<div class="mb-5">
<label class="form-label" for="{{ form.closing_date.id_for_label }}">
{{ form.closing_date.label }}
</label>
<div class="input-group">
{{ form.closing_date|add_class:"form-control" }}
<span class="input-group-text"><span class="far fa-calendar"></span></span>
</div>
{% if form.closing_date.errors %}
<div class="invalid-feedback d-block">
{{ form.closing_date.errors }} {{ form.closing_date.errors }}
</div> </div>
{{ form.closing_date.errors }} {% endif %}
</div> </div>
<!-- Buttons --> <!-- Form Actions -->
<div class="row mt-4"> <div class="d-flex justify-content-end gap-3">
<div class="col-sm-12"> <button type="reset" class="btn btn-phoenix-danger px-4">
<button type="submit" class="btn btn-primary">{{ _("Save") }}</button> <span class="fas fa-redo me-2"></span>{% trans "Reset" %}
<a href="{% url 'opportunity_list' %}" class="btn btn-secondary">{{ _("Cancel") }}</a> </button>
<button type="submit" class="btn btn-phoenix-primary px-6">
{% if form.instance.pk %}
<span class="fas fa-save me-2"></span>{% trans "Update" %}
{% else %}
<span class="fas fa-plus me-2"></span>{% trans "Create" %}
{% endif %}
</button>
</div>
</form>
</div> </div>
</div> </div>
</form> </div>
<div class="col-lg-4">
<div class="card">
<div class="card-body p-4">
<h4 class="mb-3">{% trans "Opportunity Guidelines" %}</h4>
<ul class="nav flex-column gap-2 nav-guide">
<li class="nav-item">
<div class="d-flex align-items-center">
<span class="fas fa-circle text-primary fs-11 me-2"></span>
<span class="text-body-highlight">{% trans "Probability indicates conversion chance" %}</span>
</div>
</li>
<li class="nav-item">
<div class="d-flex align-items-center">
<span class="fas fa-circle text-warning fs-11 me-2"></span>
<span class="text-body-highlight">{% trans "Update stage as deal progresses" %}</span>
</div>
</li>
<li class="nav-item">
<div class="d-flex align-items-center">
<span class="fas fa-circle text-success fs-11 me-2"></span>
<span class="text-body-highlight">{% trans "Set realistic closing dates" %}</span>
</div>
</li>
</ul>
</div> </div>
</div> </div>
</div>
</div>
</div>
<script>
function updateProbabilityValue(value) {
const badge = document.getElementById('probability-value');
badge.textContent = value + '%';
// Update badge color based on value
if (value >= 75) {
badge.className = 'badge badge-phoenix fs-6 badge-phoenix-success';
} else if (value >= 50) {
badge.className = 'badge badge-phoenix fs-6 badge-phoenix-warning';
} else {
badge.className = 'badge badge-phoenix fs-6 badge-phoenix-danger';
}
}
// Initialize on load
document.addEventListener('DOMContentLoaded', function() {
const rangeInput = document.getElementById('{{ form.probability.id_for_label }}');
updateProbabilityValue(rangeInput.value);
});
</script>
{% endblock %} {% endblock %}

View File

@ -47,7 +47,7 @@
</div> </div>
<div class="d-flex"> <div class="d-flex">
<span class="me-2" data-feather="clock" style="stroke-width:2;"></span> <span class="me-2" data-feather="clock" style="stroke-width:2;"></span>
<p class="mb-0 fs-9 fw-semibold text-body-tertiary date">{{ opportunity.created|date }}<span class="text-body-quaternary"> . {{ opportunity.created|time}}</span></p> <p class="mb-0 fs-9 fw-semibold text-body-tertiary date">{{ opportunity.created|date }}<span class="text-body-quaternary"> . {{ opportunity.created|time}}</span></p>
</div> </div>
</div> </div>
@ -131,7 +131,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="modal fade" id="deleteModal" <div class="modal fade" id="deleteModal"
data-bs-backdrop="static" data-bs-backdrop="static"
data-bs-keyboard="false" data-bs-keyboard="false"
tabindex="-1" tabindex="-1"
@ -161,8 +161,8 @@
</div> </div>
</div> </div>
</div> </div>
<div class="modal fade" id="addOpportunityModal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="addOpportunityModalLabel" aria-hidden="true"> <div class="modal fade" id="addOpportunityModal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="addOpportunityModalLabel" aria-hidden="true">
<div class="modal-dialog modal-xl modal-dialog-centered"> <div class="modal-dialog modal-xl modal-dialog-centered">
<div class="modal-content bg-body-highlight p-6"> <div class="modal-content bg-body-highlight p-6">
<div class="modal-header justify-content-between border-0 p-0 mb-2"> <div class="modal-header justify-content-between border-0 p-0 mb-2">
@ -494,7 +494,7 @@
</div> </div>
</div> </div>
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>

View File

@ -1,134 +1,93 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% load i18n static %} {% load i18n static humanize %}
{% load custom_filters %}
{% block content %} {% block content %}
<div class="row g-3"> <div class="row g-3">
<h2 class="mb-5">{{ _("Opportunities") }}</h2> <div class="col-12">
<div class="d-xl-flex justify-content-between"> <h2 class="mb-3">{{ _("Opportunities") }}</h2>
<div class="mb-3"> </div>
<a class="btn btn-sm btn-phoenix-primary me-4" href="{% url 'opportunity_create' %}"><span class="fas fa-plus me-2"></span>{{ _("Add Opportunity") }}</a> <div class="col-12">
<div class="d-flex flex-column flex-md-row justify-content-between align-items-md-center gap-3 mb-4">
<!-- Filter Controls -->
<div class="d-flex flex-column flex-lg-row align-items-start align-items-lg-center gap-3 w-100" id="filter-container">
<!-- Search Input - Wider and properly aligned -->
<div class="position-relative flex-grow-1" style="min-width: 300px;">
<span class="fas fa-search position-absolute top-50 translate-middle-y ms-3 text-body-tertiary"></span>
<input
class="form-control ps-6"
type="text"
placeholder="{% trans 'Search opportunities...' %}"
name="search"
hx-get="{% url 'opportunity_list' %}"
hx-trigger="keyup changed delay:500ms"
hx-target="#opportunities-grid"
hx-select="#opportunities-grid"
hx-include="#filter-container select"
hx-swap="outerHTML"
style="width: 100%;"
>
</div>
<!-- Filter Dropdowns - Aligned in a row -->
<div class="d-flex flex-column flex-sm-row gap-3 w-100" style="max-width: 500px;">
<!-- Stage Filter -->
<div class="flex-grow-1">
<select
class="form-select"
name="stage"
hx-get="{% url 'opportunity_list' %}"
hx-trigger="change"
hx-target="#opportunities-grid"
hx-select="#opportunities-grid"
hx-swap="outerHTML"
hx-include="#filter-container input, #filter-container select"
>
<option value="">{% trans "All Stages" %}</option>
{% for value, label in stage_choices %}
<option value="{{ value }}" {% if request.GET.stage == value %}selected{% endif %}>
{{ label }}
</option>
{% endfor %}
</select>
</div>
<!-- Sort Filter -->
<div class="flex-grow-1">
<select
class="form-select"
name="sort"
hx-get="{% url 'opportunity_list' %}"
hx-trigger="change"
hx-target="#opportunities-grid"
hx-select="#opportunities-grid"
hx-swap="outerHTML"
hx-include="#filter-container input, #filter-container select"
>
<option value="newest" {% if request.GET.sort == 'newest' %}selected{% endif %}>
{% trans "Newest First" %}
</option>
<option value="highest" {% if request.GET.sort == 'highest' %}selected{% endif %}>
{% trans "Highest Value" %}
</option>
<option value="closing" {% if request.GET.sort == 'closing' %}selected{% endif %}>
{% trans "Earliest Close Date" %}
</option>
</select>
</div> </div>
</div> </div>
</div> </div>
<div>
<div class="px-4 px-lg-6 ">
<div class="deals-items-container">
<div class="deals scrollbar">
<div class="deals-col me-4">
<div class="w-100 min-vh-50"> <div class="d-flex justify-content-end">
<a class="btn btn-phoenix-primary btn-sm" href="{% url 'opportunity_create' %}">
{% for opportunity in opportunities %} <span class="fas fa-plus me-2"></span>{{ _("Add Opportunity") }}
<div class="card mb-3">
<div class="card-body">
<h5 class="mb-2 ms-4">{{ opportunity.car.id_car_make.get_local_name }} - {{ opportunity.car.id_car_model.get_local_name }} - {{ opportunity.car.year }}</h5>
<a class="dropdown-indicator-icon position-absolute text-body-tertiary text-end"
href="#collapseWidthDeals-{{ opportunity.pk }}"
role="button"
data-bs-toggle="collapse"
aria-expanded="false"
aria-controls="collapseWidthDeals-{{ opportunity.pk }}">
<span class="fa-solid fa-angle-down text-end"></span>
</a> </a>
<div class="d-flex align-items-center justify-content-between mb-3">
<div class="d-flex gap-3">
</div>
<div class="d-flex">
<span class="me-2" data-feather="clock" style="stroke-width:2;"></span>
<p class="mb-0 fs-9 fw-semibold text-body-tertiary date">{{ opportunity.created|date }}<span class="text-body-quaternary"> . {{ opportunity.created|time}}</span></p>
</div>
</div>
<div class="deals-items-head d-flex align-items-center mb-2">
<a class="text-primary fw-bold line-clamp-1 me-3 mb-0 fs-9" href="{% url 'opportunity_detail' opportunity.pk %}">{{ _("View") }}</a>
<p class="fs-10 mb-0 mt-1 d-none"><span class="me-1 text-body-quaternary" data-feather="grid" style="stroke-width:2; height: 12px; width: 12px"></span>{{ opportunity.get_stage_display }}</p>
<p class="ms-auto fs-9 text-body-emphasis fw-semibold mb-0 deals-revenue">{{ opportunity.car.finances.total }}</p>
</div>
<div class="deals-company-agent d-flex flex-between-center">
<div class="d-flex align-items-center"><span class="uil uil-user me-2"></span>
<p class="text-body-secondary fw-bold fs-10 mb-0">{{ opportunity.customer.get_full_name }}</p>
</div>
<div class="d-flex align-items-center"><span class="uil uil-headphones me-2"></span>
<p class="text-body-secondary fw-bold fs-10 mb-0">{{ opportunity.staff.name }}</p>
</div>
</div>
<div class="collapse" id="collapseWidthDeals-{{ opportunity.pk }}">
<div class="d-flex gap-2 mb-5"><span class="badge badge-phoenix fs-10 badge-phoenix-info">{{ opportunity.get_stage_display }}</span><span class="badge badge-phoenix fs-10 badge-phoenix-danger">{{ opportunity.get_status_display }}</span></div>
<table class="mb-4 w-100 table-stats table-stats">
<tr>
<th>{{ _("Details") }}</th>
<th>:</th>
<th></th>
</tr>
<tr>
<td class="py-1">
<div class="d-flex align-items-center"><span class="me-2 text-body-tertiary" data-feather="dollar-sign"></span>
<p class="fw-semibold fs-9 mb-0 text-body-tertiary">{{ _("Expected Revenue")}}</p>
</div>
</td>
<td class="d-none d-sm-block pe-sm-2">:</td>
<td class="py-1">
<p class="ps-6 ps-sm-0 fw-semibold fs-9 mb-0 mb-0 pb-3 pb-sm-0 text-body-emphasis">{{ opportunity.car.finances.total }}</p>
</td>
</tr>
<tr>
<td class="py-1">
<div class="d-flex align-items-center"><span class="me-2 text-body-tertiary" data-feather="user" style="width:16px; height:16px"></span>
<p class="fw-semibold fs-9 mb-0 text-body-tertiary">{{ _("Contact") }}</p>
</div>
</td>
<td class=" d-none d-sm-block pe-sm-2">:</td>
<td class="py-1">
<p class="fw-semibold fs-9 mb-0 mb-0 pb-3 pb-sm-0 text-body-emphasis d-flex align-items-center gap-2"><a href=""> <span class="fa-solid fa-square-phone text-body-tertiary"></span></a><a href=""> <span class="fa-solid fa-square-envelope text-body-tertiary"></span></a><a href=""> <span class="fab fa-whatsapp-square text-body-tertiary"></span></a></p>
</td>
</tr>
<tr>
<td class="py-1">
<div class="d-flex align-items-center"><span class="me-2 text-body-tertiary" data-feather="calendar" style="width:16px; height:16px"></span>
<p class="fw-semibold fs-9 mb-0 text-body-tertiary">{{ _("Closing Date")}}</p>
</div>
</td>
<td class=" d-none d-sm-block pe-sm-2">:</td>
<td class="py-1">
<p class="fw-semibold fs-9 mb-0 mb-0 pb-3 pb-sm-0 text-body-emphasis">{{ opportunity.closing_date }}</p>
</td>
</tr>
</table>
<p class="fs-9 mb-1 fw-bold"> {{ _("Probability") }}: %</p>
<div class="progress" style="height:16px">
{% if opportunity.probability >= 25 and opportunity.probability < 49 %}
<div class="progress-bar rounded-pill bg-danger-dark" role="progressbar" style="width: {{ opportunity.probability }}%" aria-valuenow="{{ opportunity.probability }}" aria-valuemin="0" aria-valuemax="100">
<span class="fw-bolder fs-9 text-sm-end me-1">{{ opportunity.probability }}</span>
</div>
{% elif opportunity.probability >= 50 and opportunity.probability <= 74 %}
<div class="progress-bar rounded-pill bg-warning-dark" role="progressbar" style="width: {{ opportunity.probability }}%" aria-valuenow="{{ opportunity.probability }}" aria-valuemin="0" aria-valuemax="100">
<span class="fw-bolder fs-9 text-sm-end me-1">{{ opportunity.probability }}</span>
</div>
{% elif opportunity.probability >= 75 and opportunity.probability <= 100 %}
<div class="progress-bar rounded-pill bg-success-dark" role="progressbar" style="width: {{ opportunity.probability }}%" aria-valuenow="{{ opportunity.probability }}" aria-valuemin="0" aria-valuemax="100">
<span class="fw-bolder fs-9 text-sm-end me-1">{{ opportunity.probability }}</span>
</div>
{% endif %}
</div> </div>
</div> </div>
</div> </div>
</div> </div>
{% endfor %} <div id="opportunities-grid" class="row g-4 px-2 px-lg-4 mt-1">
</div> {% include 'crm/opportunities/partials/opportunity_grid.html' %}
</div> </div>
</div>
</div>
</div>
</div>
{% endblock %} {% endblock %}

View File

@ -1,10 +1,10 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% block content %} {% block content %}
<h1>Logs for {{ opportunity.deal_name }}</h1> <h1>Logs for {{ opportunity.deal_name }}</h1>
<div class="table-list" id="opportunityTable"> <div class="table-list" id="opportunityTable">
</div> </div>
<table> <table>
<thead> <thead>
<tr> <tr>
<th>Action</th> <th>Action</th>
@ -31,5 +31,5 @@
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
{% endblock %} {% endblock %}

View File

@ -0,0 +1,109 @@
{% load i18n static humanize %}
{% load custom_filters %}
{% block customCSS %}
<style>
.bg-success-soft {
background-color: rgba(25, 135, 84, 0.1) !important;
opacity: .8;
}
.bg-danger-soft {
background-color: rgba(220, 53, 69, 0.1) !important;
opacity: .8;
}
</style>
{% endblock customCSS %}
{% for opportunity in opportunities %}
<div class="col-12 col-md-6 col-lg-4 col-xl-3">
<div class="card h-100
{% if opportunity.get_stage_display == 'Closed Won' %}bg-success-soft
{% elif opportunity.get_stage_display == 'Closed Lost' %}bg-danger-soft{% endif %}">
<div class="card-body">
<h5 class="mb-4">Opportunity for {{ opportunity.customer.customer_name }}</h5>
<div class="d-flex align-items-center justify-content-between mb-3">
<div class="d-flex gap-2">
{% if opportunity.get_stage_display == "Negotiation" %}
<span class="badge badge-phoenix fs-10 badge-phoenix-primary">{{ opportunity.get_stage_display }}</span>
{% elif opportunity.get_stage_display == "Discovery" %}
<span class="badge badge-phoenix fs-10 badge-phoenix-info">{{ opportunity.get_stage_display }}</span>
{% elif opportunity.get_stage_display == "Proposal" %}
<span class="badge badge-phoenix fs-10 badge-phoenix-warning">{{ opportunity.get_stage_display }}</span>
{% elif opportunity.get_stage_display == "Closed Won" %}
<span class="badge badge-phoenix fs-10 badge-phoenix-success">{{ opportunity.get_stage_display }}</span>
{% elif opportunity.get_stage_display == "Closed Lost" %}
<span class="badge badge-phoenix fs-10 badge-phoenix-danger">{{ opportunity.get_stage_display }}</span>
{% endif %}
<span class="badge badge-phoenix fs-10
{% if opportunity.get_stage_display == 'Won' %}badge-phoenix-success
{% elif opportunity.get_stage_display == 'Lost' %}badge-phoenix-danger{% endif %}">
{{ opportunity.get_status_display }}
</span>
</div>
<div class="d-flex align-items-center">
<i class="fa-regular fa-clock"></i>&nbsp;
<p class="mb-0 fs-9 fw-semibold text-body-tertiary">{{ opportunity.created|naturalday|capfirst }}</p>
</div>
</div>
<div class="deals-company-agent d-flex justify-content-between mb-3">
<div class="d-flex align-items-center">
<span class="uil uil-user me-2"></span>
<p class="text-body-secondary fw-bold fs-10 mb-0">{{ opportunity.staff.name }}</p>
</div>
</div>
<table class="mb-3 w-100">
<tr>
<td class="py-1">
<div class="d-flex align-items-center">
<span class="me-2 text-body-tertiary"><span class="currency">{{ CURRENCY }}</span></span>
<p class="fw-semibold fs-9 mb-0 text-body-tertiary">{{ _("Expected Revenue")}}</p>
</div>
</td>
<td class="text-end">
<p class="fw-semibold fs-9 mb-0 text-body-emphasis"><span class="currency">{{ CURRENCY }}</span>{{ opportunity.expected_revenue }}</p>
</td>
</tr>
<tr>
<td class="py-1">
<div class="d-flex align-items-center">
<i class="uil uil-calendar-alt"></i>&nbsp;
<p class="fw-semibold fs-9 mb-0 text-body-tertiary">{{ _("Closing Date")}}</p>
</div>
</td>
<td class="text-end">
<p class="fw-semibold fs-9 mb-0 text-body-emphasis">{{ opportunity.closing_date|naturalday|capfirst }}</p>
</td>
</tr>
</table>
<p class="fs-9 mb-1 fw-bold">{{ _("Probability") }}: {{ opportunity.probability }}%</p>
<div class="progress mb-3" style="height:16px">
{% if opportunity.probability >= 25 and opportunity.probability < 49 %}
<div class="progress-bar rounded-pill bg-danger-dark" role="progressbar" style="width: {{ opportunity.probability }}%" aria-valuenow="{{ opportunity.probability }}" aria-valuemin="0" aria-valuemax="100">
<span class="fw-bolder fs-9 text-sm-end me-1">{{ opportunity.probability }}</span>
</div>
{% elif opportunity.probability >= 50 and opportunity.probability <= 74 %}
<div class="progress-bar rounded-pill bg-warning-dark" role="progressbar" style="width: {{ opportunity.probability }}%" aria-valuenow="{{ opportunity.probability }}" aria-valuemin="0" aria-valuemax="100">
<span class="fw-bolder fs-9 text-sm-end me-1">{{ opportunity.probability }}</span>
</div>
{% elif opportunity.probability >= 75 and opportunity.probability <= 100 %}
<div class="progress-bar rounded-pill bg-success-dark" role="progressbar" style="width: {{ opportunity.probability }}%" aria-valuenow="{{ opportunity.probability }}" aria-valuemin="0" aria-valuemax="100">
<span class="fw-bolder fs-9 text-sm-end me-1">{{ opportunity.probability }}</span>
</div>
{% endif %}
</div>
<div class="d-flex gap-2">
<a class="btn btn-sm btn-phoenix-primary" href="{% url 'opportunity_detail' opportunity.pk %}">
{{ _("View Details") }} <i class="fa-solid fa-eye ms-2"></i>
</a>
<a class="btn btn-sm btn-phoenix-success" href="{% url 'update_opportunity' opportunity.pk %}">
{{ _("Update") }} <i class="fa-solid fa-pen ms-2"></i>
</a>
</div>
</div>
</div>
</div>
{% endfor %}

View File

@ -5,8 +5,8 @@
{% block content %} {% block content %}
<link rel="stylesheet" href="{% static 'flags/sprite.css' %}"> <link rel="stylesheet" href="{% static 'flags/sprite.css' %}">
<div class="row"> <div class="row">
<div class="row mb-3"> <div class="row mb-3">
<div class="col-sm-6 col-md-8"> <div class="col-sm-6 col-md-8">
<div class="d-sm-flex justify-content-between"> <div class="d-sm-flex justify-content-between">
@ -36,6 +36,6 @@
</form> </form>
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -4,9 +4,9 @@
{% block title %}{{ _("View Customer") }}{% endblock title %} {% block title %}{{ _("View Customer") }}{% endblock title %}
{% block content %} {% block content %}
{% include 'modal/delete_modal.html' %} {% include 'modal/delete_modal.html' %}
<div class="row"> <div class="row">
<div class="mb-9"> <div class="mb-9">
<div class="row align-items-center justify-content-between g-3 mb-4"> <div class="row align-items-center justify-content-between g-3 mb-4">
<div class="col-auto"> <div class="col-auto">
@ -142,7 +142,7 @@
</div> </div>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
{% for invoice in invoices %} {% for invoice in invoices %}
<tr class="hover-actions-trigger btn-reveal-trigger position-static"> <tr class="hover-actions-trigger btn-reveal-trigger position-static">
<td class="order align-middle white-space-nowrap ps-0"> <td class="order align-middle white-space-nowrap ps-0">
@ -170,7 +170,7 @@
</div> </div>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
@ -181,7 +181,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="modal fade" id="noteModal" tabindex="-1" aria-labelledby="noteModalLabel" aria-hidden="true"> <div class="modal fade" id="noteModal" tabindex="-1" aria-labelledby="noteModalLabel" aria-hidden="true">
<div class="modal-dialog modal-sm"> <div class="modal-dialog modal-sm">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header justify-content-between align-items-start gap-5 px-4 pt-4 pb-3 border-0"> <div class="modal-header justify-content-between align-items-start gap-5 px-4 pt-4 pb-3 border-0">
@ -195,10 +195,10 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<script> <script>
document.addEventListener("DOMContentLoaded", function () { document.addEventListener("DOMContentLoaded", function () {
const noteModal = document.getElementById("noteModal"); const noteModal = document.getElementById("noteModal");
const modalTitle = document.getElementById("noteModalLabel"); const modalTitle = document.getElementById("noteModalLabel");
@ -220,6 +220,6 @@ document.addEventListener("DOMContentLoaded", function () {
console.error("Error loading form:", error); console.error("Error loading form:", error);
}); });
}); });
}); });
</script> </script>
{% endblock %} {% endblock %}

View File

@ -9,7 +9,7 @@
<span class="fs-10 text-body-secondary me-1">{{ _("As of")}}</span>{% now "SHORT_DATETIME_FORMAT" %} <span class="fs-10 text-body-secondary me-1">{{ _("As of")}}</span>{% now "SHORT_DATETIME_FORMAT" %}
</span></p> </span></p>
</div> </div>
<div class="row justify-content-between mb-2"> <div class="row justify-content-between mb-2">
<div class="col-6 col-md-4 col-xxl-2 text-center border-translucent border-start-xxl border-end-xxl-0 border-bottom-xxl-0 border-end border-bottom pb-4 pb-xxl-0 "> <div class="col-6 col-md-4 col-xxl-2 text-center border-translucent border-start-xxl border-end-xxl-0 border-bottom-xxl-0 border-end border-bottom pb-4 pb-xxl-0 ">
<span class="uil fs-5 lh-1 uil-users-alt text-success"></span> <span class="uil fs-5 lh-1 uil-users-alt text-success"></span>
<a href="{% url 'user_list' %}"><h4 class="fs-6 pt-3">{{ staff }}</h4></a> <a href="{% url 'user_list' %}"><h4 class="fs-6 pt-3">{{ staff }}</h4></a>
@ -56,7 +56,7 @@
<div class="col-4 col-xl-12 col-xxl-4 border-end border-end-xl-0 border-end-xxl py-4 ps-4 ps-sm-5 ps-xl-0 ps-xxl-5"> <div class="col-4 col-xl-12 col-xxl-4 border-end border-end-xl-0 border-end-xxl py-4 ps-4 ps-sm-5 ps-xl-0 ps-xxl-5">
<h4 class="text-body mb-4">{% trans 'inventory value'|upper %}</h4> <h4 class="text-body mb-4">{% trans 'inventory value'|upper %}</h4>
<div class="d-md-flex flex-between-center"> <div class="d-md-flex flex-between-center">
<div class="d-md-flex align-items-center gap-2"> <div class="d-md-flex align-items-center gap-2">
<span class="fas fa-money-check-alt fs-5 text-success-light dark__text-opacity-75"></span> <span class="fas fa-money-check-alt fs-5 text-success-light dark__text-opacity-75"></span>
<div class="d-flex d-md-block gap-2 align-items-center mt-1 mt-md-0"> <div class="d-flex d-md-block gap-2 align-items-center mt-1 mt-md-0">
<p class="fs-9 mb-0 mb-md-2 text-body-tertiary text-nowrap"></p> <p class="fs-9 mb-0 mb-md-2 text-body-tertiary text-nowrap"></p>
@ -88,14 +88,14 @@
</div> </div>
</div> </div>
<div class="row justify-content-between"> <div class="row justify-content-between">
<div class="col-12 col-lg-12"> <div class="col-12 col-lg-12">
<div class="row"> <div class="row">
<div class="card mb-3"> <div class="card mb-3">
<div class="bg-holder" style="background-image:url({% static 'images/bg/38.png' %});background-position:left bottom;background-size:auto;"></div> <div class="bg-holder" style="background-image:url({% static 'images/bg/38.png' %});background-position:left bottom;background-size:auto;"></div>
<div class="card-body d-flex justify-content-between position-relative"> <div class="card-body d-flex justify-content-between position-relative">
<div class="col-sm-7 col-md-8 col-xxl-8 mb-md-3 mb-lg-0"> <div class="col-sm-7 col-md-8 col-xxl-8 mb-md-3 mb-lg-0">
<h3 class="mb-3">{{ _("Inventory by Status")}}</h3> <h3 class="mb-3">{{ _("Inventory by Status")}}</h3>
<div class="row g-0"> <div class="row g-0">
<div class="col-6 col-xl-4"> <div class="col-6 col-xl-4">
@ -154,9 +154,9 @@
</div> </div>
<script> <script>
document.addEventListener("DOMContentLoaded", function () { document.addEventListener("DOMContentLoaded", function () {
/* Car Chart By Make */ /* Car Chart By Make */
const { getColor, rgbaColor } = window.phoenix.utils; const { getColor, rgbaColor } = window.phoenix.utils;
const handleTooltipPosition = ([pos, , dom, , size]) => { const handleTooltipPosition = ([pos, , dom, , size]) => {
@ -300,6 +300,6 @@ document.addEventListener("DOMContentLoaded", function () {
}); });
</script> </script>
{% endblock %} {% endblock %}

View File

@ -2,7 +2,7 @@
{% block content %} {% block content %}
<div class="row justify-content-between"> <div class="row justify-content-between">
<div class="col-12 col-lg-6"> <div class="col-12 col-lg-6">
<div class="row g-2"> <div class="row g-2">
<h3 class="fs-4 fs-md-4 fs-xl-4 fw-black mb-4"> <h3 class="fs-4 fs-md-4 fs-xl-4 fw-black mb-4">
@ -12,7 +12,7 @@
<div class="bg-holder" style="background-image:url({% static 'images/bg/38.png' %});background-position:left bottom;background-size:auto;"></div> <div class="bg-holder" style="background-image:url({% static 'images/bg/38.png' %});background-position:left bottom;background-size:auto;"></div>
<div class="card-body d-flex justify-content-between position-relative"> <div class="card-body d-flex justify-content-between position-relative">
<div class="col-sm-7 col-md-8 col-xxl-8 mb-md-3 mb-lg-0"> <div class="col-sm-7 col-md-8 col-xxl-8 mb-md-3 mb-lg-0">
<h3 class="mb-3">{{ _("Inventory by Status")}}</h3> <h3 class="mb-3">{{ _("Inventory by Status")}}</h3>
<div class="row g-0"> <div class="row g-0">
<div class="col-6 col-xl-4"> <div class="col-6 col-xl-4">
@ -123,7 +123,7 @@
<div class="col-6 col-xl-12 col-xxl-6 border-bottom py-4 ps-4 ps-sm-5 ps-xl-0 ps-xxl-5"> <div class="col-6 col-xl-12 col-xxl-6 border-bottom py-4 ps-4 ps-sm-5 ps-xl-0 ps-xxl-5">
<h4 class="text-body mb-4">{% trans 'inventory value'|upper %}</h4> <h4 class="text-body mb-4">{% trans 'inventory value'|upper %}</h4>
<div class="d-md-flex flex-between-center"> <div class="d-md-flex flex-between-center">
<div class="d-md-flex align-items-center gap-2 order-sm-0 order-md-1 fa-2x align-items-center"> <div class="d-md-flex align-items-center gap-2 order-sm-0 order-md-1 fa-2x align-items-center">
<i class="fas fa-money-check-alt fs-4 text-success-light dark__text-opacity-75"></i> <i class="fas fa-money-check-alt fs-4 text-success-light dark__text-opacity-75"></i>
<div class="d-flex d-md-block gap-2 align-items-center mt-1 mt-md-0"> <div class="d-flex d-md-block gap-2 align-items-center mt-1 mt-md-0">
<p class="fs-9 mb-0 mb-md-2 text-body-tertiary text-nowrap"></p> <p class="fs-9 mb-0 mb-md-2 text-body-tertiary text-nowrap"></p>
@ -247,9 +247,9 @@
</div> </div>
<script> <script>
document.addEventListener("DOMContentLoaded", function () { document.addEventListener("DOMContentLoaded", function () {
/* Car Chart By Make */ /* Car Chart By Make */
const getColor = (name, dom = document.documentElement) => { const getColor = (name, dom = document.documentElement) => {
return getComputedStyle(dom).getPropertyValue(`--phoenix-${name}`).trim(); return getComputedStyle(dom).getPropertyValue(`--phoenix-${name}`).trim();
@ -400,6 +400,6 @@ document.addEventListener("DOMContentLoaded", function () {
}); });
</script> </script>
{% endblock %} {% endblock %}

View File

@ -1,7 +1,7 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% load i18n static %} {% load i18n static %}
{% block content %} {% block content %}
<div class="row"> <div class="row">
<div class="ol-auto pt-5 pb-9"> <div class="ol-auto pt-5 pb-9">
<div class="row-sm"> <div class="row-sm">
<div class="row d-flex-center"> <div class="row d-flex-center">
@ -33,8 +33,8 @@
</div> </div>
</div> </div>
{% if is_paginated %} {% if is_paginated %}
<nav aria-label="Page navigation"> <nav aria-label="Page navigation">
<ul class="pagination mb-0"> <ul class="pagination mb-0">
{% if page_obj.has_previous %} {% if page_obj.has_previous %}
<li class="page-item py-0"> <li class="page-item py-0">
@ -70,12 +70,12 @@
</li> </li>
{% endif %} {% endif %}
</ul> </ul>
</nav> </nav>
{% endif %} {% endif %}
</div> </div>
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,5 +1,5 @@
{% extends 'base.html' %} {% load i18n static custom_filters%} {% block content %} {% extends 'base.html' %} {% load i18n static custom_filters%} {% block content %}
<div class="container-fluid"> <div class="container-fluid">
<div class="row align-items-center justify-content-between g-3 mb-4"> <div class="row align-items-center justify-content-between g-3 mb-4">
<div class="col-auto"> <div class="col-auto">
<h2 class="mb-0">{% trans 'Profile' %}</h2> <h2 class="mb-0">{% trans 'Profile' %}</h2>
@ -172,7 +172,7 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -5,7 +5,7 @@
{% block title %}{{ _("Update Dealer Information") }}{% endblock title %} {% block title %}{{ _("Update Dealer Information") }}{% endblock title %}
{% block content %} {% block content %}
<div class="row my-5"> <div class="row my-5">
<div class="col-md-8"> <div class="col-md-8">
<!-- Form Header --> <!-- Form Header -->
@ -24,5 +24,5 @@
</form> </form>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,7 +1,7 @@
{% load i18n %} {% load i18n %}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% translate 'Appointment Request Notification' %}</title> <title>{% translate 'Appointment Request Notification' %}</title>
@ -47,9 +47,9 @@
color: #999; color: #999;
} }
</style> </style>
</head> </head>
<body> <body>
<div class="email-container"> <div class="email-container">
<h1>{% translate 'New Appointment Request' %}</h1> <h1>{% translate 'New Appointment Request' %}</h1>
<p>{% translate 'Dear Admin,' %}</p> <p>{% translate 'Dear Admin,' %}</p>
<p>{% translate 'You have received a new appointment request. Here are the details:' %}</p> <p>{% translate 'You have received a new appointment request. Here are the details:' %}</p>
@ -69,6 +69,6 @@
<div class="footer"> <div class="footer">
<p>{% translate 'This is an automated message. Please do not reply directly to this email.' %}</p> <p>{% translate 'This is an automated message. Please do not reply directly to this email.' %}</p>
</div> </div>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,7 +1,7 @@
{% load i18n %} {% load i18n %}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% translate 'Appointment Reminder' %}</title> <title>{% translate 'Appointment Reminder' %}</title>
@ -61,9 +61,9 @@
text-decoration: none; text-decoration: none;
} }
</style> </style>
</head> </head>
<body> <body>
<div class="email-container"> <div class="email-container">
<div class="email-header"> <div class="email-header">
<h2>{% translate 'Appointment Reminder' %}</h2> <h2>{% translate 'Appointment Reminder' %}</h2>
</div> </div>
@ -92,6 +92,6 @@
<div class="email-footer"> <div class="email-footer">
{% translate 'This is an automated message. Please do not reply directly to this email.' %} {% translate 'This is an automated message. Please do not reply directly to this email.' %}
</div> </div>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,7 +1,7 @@
{% load i18n %} {% load i18n %}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>{% trans "Appointment Reschedule Confirmation" %}</title> <title>{% trans "Appointment Reschedule Confirmation" %}</title>
<style> <style>
@ -33,10 +33,10 @@
text-decoration: none; text-decoration: none;
} }
</style> </style>
</head> </head>
<body> <body>
<!-- email_template.html --> <!-- email_template.html -->
<div class="email-container"> <div class="email-container">
<h2>{% trans "Appointment Reschedule" %}</h2> <h2>{% trans "Appointment Reschedule" %}</h2>
<div class="email-content"> <div class="email-content">
{% if is_confirmation %} {% if is_confirmation %}
@ -88,6 +88,6 @@
<div class="email-footer"> <div class="email-footer">
<p>{% trans "Thank you," %}<br>{{ company }}</p> <p>{% trans "Thank you," %}<br>{{ company }}</p>
</div> </div>
</div> </div>
</body> </body>
</html> </html>

View File

@ -2,7 +2,7 @@
{% load static %} {% load static %}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<title></title> <title></title>
<style type="text/css"> <style type="text/css">
/* CLIENT-SPECIFIC STYLES */ /* CLIENT-SPECIFIC STYLES */
@ -82,17 +82,17 @@
margin: 0 !important; margin: 0 !important;
} }
</style> </style>
</head> </head>
<body style="margin: 0 !important; padding: 0; !important background-color: #ffffff;" bgcolor="#ffffff"> <body style="margin: 0 !important; padding: 0; !important background-color: #ffffff;" bgcolor="#ffffff">
<!-- HIDDEN PRE-HEADER TEXT --> <!-- HIDDEN PRE-HEADER TEXT -->
<div style="display: none; font-size: 1px; color: #fefefe; line-height: 1px; font-family: Open Sans, Helvetica, Arial, sans-serif; max-height: 0; max-width: 0; opacity: 0; overflow: hidden;"> <div style="display: none; font-size: 1px; color: #fefefe; line-height: 1px; font-family: Open Sans, Helvetica, Arial, sans-serif; max-height: 0; max-width: 0; opacity: 0; overflow: hidden;">
{% if pre_header %} {% if pre_header %}
{{ pre_header }} {{ pre_header }}
{% endif %} {% endif %}
</div> </div>
<table border="0" cellpadding="0" cellspacing="0" width="100%"> <table border="0" cellpadding="0" cellspacing="0" width="100%">
<tr> <tr>
<td align="center" valign="top" width="100%" bgcolor="#3b4a69" <td align="center" valign="top" width="100%" bgcolor="#3b4a69"
style="background: #3b4a69 url('{% static 'img/email_hd_bg.jpg' %}'); background-size: cover; padding: 50px 15px;" style="background: #3b4a69 url('{% static 'img/email_hd_bg.jpg' %}'); background-size: cover; padding: 50px 15px;"
@ -284,7 +284,7 @@
<![endif]--> <![endif]-->
</td> </td>
</tr> </tr>
</table> </table>
</body> </body>
</html> </html>

View File

@ -2,8 +2,8 @@
<footer class="footer position-absolute fs-9"> <footer class="footer position-absolute fs-9">
<div class="row g-0 justify-content-between align-items-center h-100"> <div class="row g-0 justify-content-between align-items-center h-100">
<div class="col-12 col-sm-auto text-center"> <div class="col-12 col-sm-auto text-center">
<span class="text-body"> © 2025 {{ _("All right reserved")}}</span> <span class="text-body"> © 2025 {{ _("All right reserved")}}</span>
<span class="fw-bold">Haikal</span>&nbsp;|&nbsp;<span class="fw-bold">هيكل</span> <span class="fw-bold">Haikal</span>&nbsp;|&nbsp;<span class="fw-bold">هيكل</span>
</div> </div>
<div class="col-12 col-sm-auto text-center"> <div class="col-12 col-sm-auto text-center">

View File

@ -36,7 +36,7 @@
</div> </div>
</div> </div>
<div class="row my-5"> <div class="row my-5">
<div class="card rounded "> <div class="card rounded ">
<div class="card-header "> <div class="card-header ">
<p class="mb-0">{{ _("Group Details") }}</p> <p class="mb-0">{{ _("Group Details") }}</p>
@ -115,5 +115,5 @@
</a> </a>
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -6,8 +6,8 @@
{% block content %} {% block content %}
<div class="row"> <div class="row">
<div class="row"> <div class="row">
<div class="col-sm-9"> <div class="col-sm-9">
<div class="d-sm-flex justify-content-between"> <div class="d-sm-flex justify-content-between">
@ -41,5 +41,5 @@
</form> </form>
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -5,7 +5,7 @@
{% block title %}{% trans "Group" %}{% endblock title %} {% block title %}{% trans "Group" %}{% endblock title %}
{% block content %} {% block content %}
<section class=""> <section class="">
<div class="row"> <div class="row">
<div class="col-auto"> <div class="col-auto">
@ -16,7 +16,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="table-responsive scrollbar mx-n1 px-1"> <div class="table-responsive scrollbar mx-n1 px-1">
<table class="table table-hover table-responsive-sm fs-9 mb-0"> <table class="table table-hover table-responsive-sm fs-9 mb-0">
<thead> <thead>
@ -44,14 +44,14 @@
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
</div> </div>
<div class="d-flex justify-content-center"> <div class="d-flex justify-content-center">
{% if is_paginated %} {% if is_paginated %}
{% include 'partials/pagination.html' %} {% include 'partials/pagination.html' %}
{% endif %} {% endif %}
</div> </div>
</div> </div>
</section> </section>
{% endblock %} {% endblock %}

View File

@ -6,8 +6,8 @@
{% block content %} {% block content %}
<div class="row"> <div class="row">
<div class="row"> <div class="row">
<div class="col-sm-9"> <div class="col-sm-9">
<div class="d-sm-flex justify-content-between"> <div class="d-sm-flex justify-content-between">
@ -41,5 +41,5 @@
</form> </form>
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -4,19 +4,19 @@
{% block title %}{{ _("HaikalBot") }}{% endblock title %} {% block title %}{{ _("HaikalBot") }}{% endblock title %}
{% block content %} {% block content %}
<style> <style>
#chatbox { #chatbox {
border: 1px solid #ccc; border: 1px solid #ccc;
border-radius: 5px; border-radius: 5px;
padding: 10px; padding: 10px;
height: 200px; height: 200px;
overflow-y: scroll; overflow-y: scroll;
} }
</style> </style>
<div class="row p-2"> <div class="row p-2">
<div class="card shadow-sm rounded shadow"> <div class="card shadow-sm rounded shadow">
<div class="card-header bg-primary text-white"> <div class="card-header bg-primary text-white">
<h4 class="mb-0">{% trans 'HaikalBot' %}</h4> <h4 class="mb-0">{% trans 'HaikalBot' %}</h4>
@ -36,7 +36,7 @@
<!-- Script to send to api --> <!-- Script to send to api -->
<script> <script>
function getCookie(name) { function getCookie(name) {
let cookieValue = null; let cookieValue = null;
if (document.cookie && document.cookie !== '') { if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';'); const cookies = document.cookie.split(';');
@ -49,7 +49,7 @@ function getCookie(name) {
} }
} }
return cookieValue; return cookieValue;
} }
const csrfToken = getCookie('csrftoken'); const csrfToken = getCookie('csrftoken');
@ -81,9 +81,9 @@ function getCookie(name) {
} else { } else {
alert("An error occurred."); alert("An error occurred.");
} }
} }
</script> </script>
</div> </div>
{% endblock content %} {% endblock content %}

View File

@ -1,7 +1,7 @@
{% load i18n static %} {% load i18n static %}
{% if user.is_authenticated %} {% if user.is_authenticated %}
<nav class="navbar navbar-vertical navbar-expand-lg"> <nav class="navbar navbar-vertical navbar-expand-lg">
<div class="collapse navbar-collapse" id="navbarVerticalCollapse"> <div class="collapse navbar-collapse" id="navbarVerticalCollapse">
<div class="navbar-vertical-content"> <div class="navbar-vertical-content">
<ul class="navbar-nav flex-column" id="navbarVerticalNav"> <ul class="navbar-nav flex-column" id="navbarVerticalNav">
@ -142,6 +142,13 @@
</div> </div>
</a> </a>
</li> </li>
<li class="nav-item">
<a class="nav-link" href="{% url 'opportunity_list' %}">
<div class="d-flex align-items-center">
<span class="nav-link-icon"><span data-feather="users"></span></span><span class="nav-link-text">{% trans 'Opportunity'|capfirst %}</span>
</div>
</a>
</li>
{% endif %} {% endif %}
{% if perms.django_ledger.view_customermodel %} {% if perms.django_ledger.view_customermodel %}
<li class="nav-item"> <li class="nav-item">
@ -324,7 +331,7 @@
<span class="uil uil-left-arrow-to-left fs-8"></span><span class="uil uil-arrow-from-right fs-8"></span><span class="navbar-vertical-footer-text ms-2">Collapsed View</span> <span class="uil uil-left-arrow-to-left fs-8"></span><span class="uil uil-arrow-from-right fs-8"></span><span class="navbar-vertical-footer-text ms-2">Collapsed View</span>
</button> </button>
</div> </div>
</nav> </nav>
{% endif %} {% endif %}
<nav class="navbar navbar-top fixed-top navbar-expand" id="navbarDefault"> <nav class="navbar navbar-top fixed-top navbar-expand" id="navbarDefault">
@ -357,7 +364,7 @@
<label class="mb-0 theme-control-toggle-label theme-control-toggle-dark" for="themeControlToggleSm" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="{{ _("Switch theme")}}" style="height:32px;width:32px;"><span class="icon" data-feather="sun"></span></label> <label class="mb-0 theme-control-toggle-label theme-control-toggle-dark" for="themeControlToggleSm" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="{{ _("Switch theme")}}" style="height:32px;width:32px;"><span class="icon" data-feather="sun"></span></label>
</div> </div>
</li> </li>
<li class="nav-item dropdown"> <li class="nav-item dropdown">
<a class="nav-link lh-1 pe-0" href="#" id="languageDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false" data-bs-auto-close="outside" aria-haspopup="true" > <a class="nav-link lh-1 pe-0" href="#" id="languageDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false" data-bs-auto-close="outside" aria-haspopup="true" >
<span class="me-1" data-feather="globe" ></span> <span class="me-1" data-feather="globe" ></span>
</a> </a>
@ -457,8 +464,8 @@
{% endif %} {% endif %}
</div> </div>
</div> </div>
</div> </div>
</li> </li>
</ul> </ul>
</div> </div>
</nav> </nav>

View File

@ -1,7 +1,7 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% load i18n static custom_filters django_ledger %} {% load i18n static custom_filters django_ledger %}
{% block content %} {% block content %}
{% if request.user.is_authenticated %} {% if request.user.is_authenticated %}
<div <div
id="dashboard-content" id="dashboard-content"
hx-get="{% if request.user.dealer %}{% url 'manager_dashboard' %}{% else %}{% url 'sales_dashboard' %}{% endif %}" hx-get="{% if request.user.dealer %}{% url 'manager_dashboard' %}{% else %}{% url 'sales_dashboard' %}{% endif %}"
@ -14,6 +14,6 @@
<p>Loading dashboard...</p> <p>Loading dashboard...</p>
</div> </div>
</div> </div>
{% endif %} {% endif %}
{% endblock %} {% endblock %}

View File

@ -1,7 +1,7 @@
{% extends "base.html" %} {% extends "base.html" %}
{% load i18n %} {% load i18n %}
{% block content %} {% block content %}
<div class="row mt-4"> <div class="row mt-4">
<h5 class="text-center">{% trans "Add Colors" %}</h5> <h5 class="text-center">{% trans "Add Colors" %}</h5>
<p class="text-center">{% trans "Select exterior and interior colors for" %} {{ car.id_car_make.get_local_name }} {{ car.id_car_model.get_local_name }}</p> <p class="text-center">{% trans "Select exterior and interior colors for" %} {{ car.id_car_make.get_local_name }} {{ car.id_car_model.get_local_name }}</p>
@ -58,9 +58,9 @@
</div> </div>
</div> </div>
</form> </form>
</div> </div>
<style> <style>
.color-card { .color-card {
cursor: pointer; cursor: pointer;
transition: all 0.3s ease; transition: all 0.3s ease;
@ -113,5 +113,5 @@
text-align: center; text-align: center;
width: 100%; width: 100%;
} }
</style> </style>
{% endblock %} {% endblock %}

View File

@ -2,7 +2,7 @@
{% load crispy_forms_filters %} {% load crispy_forms_filters %}
<form method="post" id="customCardForm" action="{% url 'add_custom_card' car.pk %}"> <form method="post" id="customCardForm" action="{% url 'add_custom_card' car.pk %}">
{% csrf_token %} {% csrf_token %}
{{ form|crispy }} {{ form|crispy }}
<div class="d-flex gap-1"> <div class="d-flex gap-1">
<button type="button" <button type="button"

View File

@ -5,12 +5,12 @@
{% block title %}Delete Car{% endblock %} {% block title %}Delete Car{% endblock %}
{% block content %} {% block content %}
<h1>Delete Car</h1> <h1>Delete Car</h1>
<p>Are you sure you want to delete the car "{{ car }}"?</p> <p>Are you sure you want to delete the car "{{ car }}"?</p>
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %}
<button type="submit" class="btn btn-danger">Confirm Delete</button> <button type="submit" class="btn btn-danger">Confirm Delete</button>
<a href="{% url 'car_detail' car.pk %}" class="btn btn-secondary">{% trans 'Cancel' %}</a> <a href="{% url 'car_detail' car.pk %}" class="btn btn-secondary">{% trans 'Cancel' %}</a>
</form> </form>
{% endblock %} {% endblock %}

View File

@ -2,7 +2,7 @@
{% load i18n static custom_filters %} {% load i18n static custom_filters %}
{% block title %}{{ _("Car Details") }}{% endblock %} {% block title %}{{ _("Car Details") }}{% endblock %}
{% block customCSS %} {% block customCSS %}
<style> <style>
.disabled{ .disabled{
opacity: 0.5; opacity: 0.5;
pointer-events: none; pointer-events: none;
@ -13,11 +13,11 @@
left: 90%; left: 90%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
} }
</style> </style>
{% endblock customCSS %} {% endblock customCSS %}
{% block content %} {% block content %}
{% if not car.ready %} {% if not car.ready %}
<div class="alert alert-outline-warning d-flex align-items-center" role="alert"> <div class="alert alert-outline-warning d-flex align-items-center" role="alert">
<i class="fa-solid fa-circle-info fs-6"></i> <i class="fa-solid fa-circle-info fs-6"></i>
<p class="mb-0 flex-1">{{ _("This car information is not complete , please add colors and finances before making it ready for sale .") }}</p> <p class="mb-0 flex-1">{{ _("This car information is not complete , please add colors and finances before making it ready for sale .") }}</p>
@ -43,11 +43,11 @@
<i class="fa-solid fa-circle-info fs-6"></i> <i class="fa-solid fa-circle-info fs-6"></i>
<p class="mb-0 flex-1">{{ _("This car is reserved until ") }}{{ car.get_reservation.reserved_until }}</p> <p class="mb-0 flex-1">{{ _("This car is reserved until ") }}{{ car.get_reservation.reserved_until }}</p>
<button class="btn-close" type="button" data-bs-dismiss="alert" aria-label="Close"></button> <button class="btn-close" type="button" data-bs-dismiss="alert" aria-label="Close"></button>
</div> </div>
{% endif %} {% endif %}
<!-- Main row --> <!-- Main row -->
<div class="row-fluid {% if car.status == 'sold' %}disabled{% endif %}"> <div class="row-fluid {% if car.status == 'sold' %}disabled{% endif %}">
<div class="row g-3 justify-content-between"> <div class="row g-3 justify-content-between">
<div class="col-lg-12 col-xl-6"> <div class="col-lg-12 col-xl-6">
<div class="card rounded shadow d-flex align-content-center {% if car.get_transfer %}disabled{% endif %}"> <div class="card rounded shadow d-flex align-content-center {% if car.get_transfer %}disabled{% endif %}">
@ -411,10 +411,10 @@
{% if car.status == 'sold' %} {% if car.status == 'sold' %}
<img class="car_status" src="{% static 'images/sold.png' %}" width="200" height="100" alt=""> <img class="car_status" src="{% static 'images/sold.png' %}" width="200" height="100" alt="">
{% endif %} {% endif %}
</div> </div>
<!-- Custom Card Modal --> <!-- Custom Card Modal -->
<div class="modal fade" id="customCardModal" tabindex="-1" aria-labelledby="customCardModalLabel" aria-hidden="true"> <div class="modal fade" id="customCardModal" tabindex="-1" aria-labelledby="customCardModalLabel" aria-hidden="true">
<div class="modal-dialog modal-sm"> <div class="modal-dialog modal-sm">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
@ -426,10 +426,10 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<!-- Registration Modal --> <!-- Registration Modal -->
<div class="modal fade" id="registrationModal" tabindex="-1" aria-labelledby="registrationModalLabel" aria-hidden="true"> <div class="modal fade" id="registrationModal" tabindex="-1" aria-labelledby="registrationModalLabel" aria-hidden="true">
<div class="modal-dialog modal-sm"> <div class="modal-dialog modal-sm">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
@ -441,10 +441,10 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<!-- Reservation Modal --> <!-- Reservation Modal -->
<div class="modal fade" id="reserveModal" tabindex="-1" aria-labelledby="reserveModalLabel" aria-hidden="true"> <div class="modal fade" id="reserveModal" tabindex="-1" aria-labelledby="reserveModalLabel" aria-hidden="true">
<div class="modal-dialog modal-sm"> <div class="modal-dialog modal-sm">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
@ -454,7 +454,7 @@
<div class="modal-body"> <div class="modal-body">
{% trans 'Are you sure you want to reserve this car?' %} {% trans 'Are you sure you want to reserve this car?' %}
</div> </div>
<form method="POST" action="{% url 'reserve_car' car.id %}" class="form "> <form method="POST" action="{% url 'reserve_car' car.id %}" class="form ">
{% csrf_token %} {% csrf_token %}
@ -476,9 +476,9 @@
</form> </form>
</div> </div>
</div> </div>
</div> </div>
<!-- Specification Modal --> <!-- Specification Modal -->
<div class="modal fade" id="specificationsModal" tabindex="-1" aria-labelledby="specificationsModalLabel" aria-hidden="true"> <div class="modal fade" id="specificationsModal" tabindex="-1" aria-labelledby="specificationsModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg modal-dialog-scrollable"> <div class="modal-dialog modal-lg modal-dialog-scrollable">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
@ -490,8 +490,8 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<script> <script>
document.addEventListener("DOMContentLoaded", function () { document.addEventListener("DOMContentLoaded", function () {
@ -603,7 +603,7 @@
specificationsContent.innerHTML = '<p>{% trans "Error loading specifications." %}</p>'; specificationsContent.innerHTML = '<p>{% trans "Error loading specifications." %}</p>';
console.error("Error fetching specifications:", error); console.error("Error fetching specifications:", error);
}); });
}); });
document.querySelectorAll(".reserve-btn").forEach((button) => { document.querySelectorAll(".reserve-btn").forEach((button) => {
button.addEventListener("click", async function () { button.addEventListener("click", async function () {
@ -641,6 +641,6 @@
button.classList.add("d-none"); button.classList.add("d-none");
}); });
} }
</script> </script>
{% endblock %} {% endblock %}

View File

@ -1,5 +1,5 @@
{% extends 'base.html' %} {% load crispy_forms_filters %} {% load i18n %} {% load custom_filters %} {% block title %} {% trans 'Edit Car' %} {% endblock %} {% block content %} {% extends 'base.html' %} {% load crispy_forms_filters %} {% load i18n %} {% load custom_filters %} {% block title %} {% trans 'Edit Car' %} {% endblock %} {% block content %}
<div class="row"> <div class="row">
<div class="card rounded shadow mt-3"> <div class="card rounded shadow mt-3">
<p class="card-header bg-primary text-white rounded-top fw-bold">{% trans 'Edit Car' %}</p> <p class="card-header bg-primary text-white rounded-top fw-bold">{% trans 'Edit Car' %}</p>
<div class="card-body"> <div class="card-body">
@ -15,5 +15,5 @@
</form> </form>
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -6,7 +6,7 @@
{% block title %}{% trans "Car Finance Details" %}{% endblock %} {% block title %}{% trans "Car Finance Details" %}{% endblock %}
{% block content %} {% block content %}
<div class="row p-4"> <div class="row p-4">
<p class="mb-4">{% trans "Finance Details for" %} <p class="mb-4">{% trans "Finance Details for" %}
{{ car.id_car_make.get_local_name }} - {{ car.id_car_model.get_local_name }} {{ car.id_car_make.get_local_name }} - {{ car.id_car_model.get_local_name }}
</p> </p>
@ -26,7 +26,7 @@
</ul> </ul>
</div> </div>
{% endif %} {% endif %}
<form method="post" class="needs-validation" novalidate> <form method="post" class="needs-validation" novalidate>
<div class="row g-1"> <div class="row g-1">
<div class="col-lg-4 col-xl-12"> <div class="col-lg-4 col-xl-12">
@ -43,7 +43,7 @@
</div> </div>
</form> </form>
</div> </div>
<!-- JavaScript Section --> <!-- JavaScript Section -->

View File

@ -1,5 +1,5 @@
{% extends "base.html" %} {% load i18n static custom_filters %} {% block content %} {% extends "base.html" %} {% load i18n static custom_filters %} {% block content %}
<style> <style>
#video { #video {
width: 100%; width: 100%;
max-width: 480px; max-width: 480px;
@ -10,7 +10,7 @@
opacity: 0.5; opacity: 0.5;
pointer-events: none; pointer-events: none;
} }
</style> </style>
<!-- JavaScript Section --> <!-- JavaScript Section -->
@ -23,7 +23,7 @@
<button class="btn-close" type="button" data-bs-dismiss="alert" aria-label="Close"></button> <button class="btn-close" type="button" data-bs-dismiss="alert" aria-label="Close"></button>
</div> </div>
{% endif %} {% endif %}
<div class=" container-fluid m-0 {% if not vendor_exists %}disabled{% endif %}"> <div class=" container-fluid m-0 {% if not vendor_exists %}disabled{% endif %}">
<form method="post" id="carForm" class="form needs-validation" novalidate> <form method="post" id="carForm" class="form needs-validation" novalidate>
{% csrf_token %} {% csrf_token %}
{% include 'partials/form_errors.html' %} {% include 'partials/form_errors.html' %}
@ -297,9 +297,9 @@
</div> </div>
</div> </div>
</div> </div>
<script> <script>
function getCookie(name) { function getCookie(name) {
let cookieValue = null; let cookieValue = null;
if (document.cookie && document.cookie !== "") { if (document.cookie && document.cookie !== "") {
@ -606,7 +606,7 @@
loadSeries(e.target.value, yearSelect.value); loadSeries(e.target.value, yearSelect.value);
}) })
decodeVinBtn.addEventListener("click", decodeVin); decodeVinBtn.addEventListener("click", decodeVin);
}) })
function showLoading() { function showLoading() {
@ -630,6 +630,6 @@
titleText: msg, titleText: msg,
}); });
} }
</script> </script>
{% endblock %} {% endblock %}

View File

@ -1,5 +1,5 @@
{% extends "base.html" %} {% load i18n static custom_filters %} {% block content %} {% extends "base.html" %} {% load i18n static custom_filters %} {% block content %}
<style> <style>
#video { #video {
width: 100%; width: 100%;
max-width: 480px; max-width: 480px;
@ -9,14 +9,14 @@
.modal-dialog { .modal-dialog {
max-width: 95%; max-width: 95%;
} }
</style> </style>
{% include 'partials/form_errors.html' %} {% include 'partials/form_errors.html' %}
<!-- JavaScript Section --> <!-- JavaScript Section -->
<script src="https://unpkg.com/@zxing/library@latest"></script> <script src="https://unpkg.com/@zxing/library@latest"></script>
<script src="https://cdn.jsdelivr.net/npm/tesseract.js@5/dist/tesseract.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/tesseract.js@5/dist/tesseract.min.js"></script>
<div class="container-lg"> <div class="container-lg">
<form method="post" id="carForm" class="form needs-validation" novalidate> <form method="post" id="carForm" class="form needs-validation" novalidate>
{% csrf_token %} {% csrf_token %}
<div class="d-flex flex-column min-vh-100"> <div class="d-flex flex-column min-vh-100">
@ -341,9 +341,9 @@
</div> </div>
</div> </div>
<!-- CAR FORM --> <!-- CAR FORM -->
</div> </div>
<script> <script>
function getCookie(name) { function getCookie(name) {
let cookieValue = null; let cookieValue = null;
if (document.cookie && document.cookie !== "") { if (document.cookie && document.cookie !== "") {
@ -646,7 +646,7 @@
loadSeries(e.target.value, yearSelect.value); loadSeries(e.target.value, yearSelect.value);
}) })
decodeVinBtn.addEventListener("click", decodeVin); decodeVinBtn.addEventListener("click", decodeVin);
}) })
function showLoading() { function showLoading() {
@ -670,6 +670,6 @@
titleText: msg, titleText: msg,
}); });
} }
</script> </script>
{% endblock %} {% endblock %}

View File

@ -2,12 +2,12 @@
{% load i18n static %} {% load i18n static %}
{% block title %} {% block title %}
{% trans "inventory"|capfirst %} {% trans "inventory"|capfirst %}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div class="row g-3 justify-content-between"> <div class="row g-3 justify-content-between">
<div class="col-sm-12"> <div class="col-sm-12">
<div class="card border h-100 w-100 overflow-hidden"> <div class="card border h-100 w-100 overflow-hidden">
<div class="bg-holder d-block bg-card" style="background-image:url({% static 'images/spot-illustrations/32.png' %});background-position: top right;"> <div class="bg-holder d-block bg-card" style="background-image:url({% static 'images/spot-illustrations/32.png' %});background-position: top right;">
@ -41,8 +41,8 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="row g-3 justify-content-between mt-4"> <div class="row g-3 justify-content-between mt-4">
<div class="col-sm-12"> <div class="col-sm-12">
<div class="table-list" id="inventoryTable"> <div class="table-list" id="inventoryTable">
<div class="table-responsive scrollbar mb-3"> <div class="table-responsive scrollbar mb-3">
@ -131,5 +131,5 @@
{% include 'partials/pagination.html' %} {% include 'partials/pagination.html' %}
{% endif %} {% endif %}
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -3,7 +3,7 @@
{% load custom_filters %} {% load custom_filters %}
{% block content %} {% block content %}
<div class="row-fluid p-2"> <div class="row-fluid p-2">
<!-- Display Validation Errors --> <!-- Display Validation Errors -->
{% if errors %} {% if errors %}
<div class="alert alert-danger"> <div class="alert alert-danger">
@ -15,7 +15,7 @@
</div> </div>
{% endif %} {% endif %}
<!-- Option Modal --> <!-- Option Modal -->
<div class="modal fade" id="optionsModal" <div class="modal fade" id="optionsModal"
data-bs-backdrop="static" data-bs-backdrop="static"
data-bs-keyboard="false" data-bs-keyboard="false"
tabindex="-1" tabindex="-1"
@ -32,10 +32,10 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<!-- Specification Modal --> <!-- Specification Modal -->
<div class="modal fade" id="specificationsModal" <div class="modal fade" id="specificationsModal"
data-bs-backdrop="static" data-bs-backdrop="static"
data-bs-keyboard="false" data-bs-keyboard="false"
tabindex="-1" tabindex="-1"
@ -52,7 +52,7 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<!-- CAR FORM --> <!-- CAR FORM -->
<form method="post" id="carForm" class="form"> <form method="post" id="carForm" class="form">
{% csrf_token %} {% csrf_token %}
@ -232,13 +232,13 @@
</div> </div>
</div> </div>
</form> </form>
</div> </div>
<!-- JavaScript Section --> <!-- JavaScript Section -->
<script> <script>
document.addEventListener("DOMContentLoaded", function() { document.addEventListener("DOMContentLoaded", function() {
const vinInput = document.getElementById('vin'); const vinInput = document.getElementById('vin');
const statusSelect = document.getElementById('status'); const statusSelect = document.getElementById('status');
const stockTypeSelect = document.getElementById('stock_type'); const stockTypeSelect = document.getElementById('stock_type');
@ -593,7 +593,7 @@ checkFormCompletion();
}); });
} }
}); });
}); });
</script> </script>
{% endblock %} {% endblock %}

View File

@ -15,7 +15,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-md-12 p-1"> <div class="col-md-12 p-1">
<div class="table-responsive scrollbar mx-n1 p-1 align-center"> <div class="table-responsive scrollbar mx-n1 p-1 align-center">
{% render_table table %} {% render_table table %}
@ -23,8 +23,8 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -3,7 +3,7 @@
{% load custom_filters %} {% load custom_filters %}
{% block customCSS %} {% block customCSS %}
<style> <style>
.htmx-indicator{ .htmx-indicator{
opacity:0; opacity:0;
transition: opacity 500ms ease-in; transition: opacity 500ms ease-in;
@ -21,7 +21,7 @@
.transition { .transition {
transition: all ease-in 1s ; transition: all ease-in 1s ;
} }
</style> </style>
{% endblock customCSS %} {% endblock customCSS %}
{% block content %} {% block content %}
@ -189,7 +189,7 @@
{% endblock %} {% endblock %}
{% block customJS %} {% 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', () => {
@ -223,5 +223,5 @@
document.querySelector('.car_status').removeAttribute('disabled') document.querySelector('.car_status').removeAttribute('disabled')
} }
</script> </script>
{% endblock customJS %} {% endblock customJS %}

View File

@ -13,5 +13,5 @@
<button type="submit" class="btn btn-phoenix-success">{% trans "Save" %}</button> <button type="submit" class="btn btn-phoenix-success">{% trans "Save" %}</button>
</div> </div>
</form> </form>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -13,5 +13,5 @@
<button type="submit" class="btn btn-phoenix-primary">{% trans "Sell" %}</button> <button type="submit" class="btn btn-phoenix-primary">{% trans "Sell" %}</button>
</div> </div>
</form> </form>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -2,7 +2,7 @@
{% load static i18n %} {% load static i18n %}
{% block content %} {% block content %}
<div class="container"> <div class="container">
<div id="car_list" data-list=""> <div id="car_list" data-list="">
<div class="search-box mb-3 mx-auto"> <div class="search-box mb-3 mx-auto">
@ -48,10 +48,10 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<script> <script>
document.addEventListener("DOMContentLoaded", function () { document.addEventListener("DOMContentLoaded", function () {
let currentPage = 1; let currentPage = 1;
function loadPage(page) { function loadPage(page) {
@ -144,7 +144,7 @@ document.addEventListener("DOMContentLoaded", function () {
// Load the first page when the document is ready // Load the first page when the document is ready
loadPage(currentPage); loadPage(currentPage);
}); });
</script> </script>
{% endblock %} {% endblock %}

View File

@ -1,10 +1,10 @@
{% extends "base.html" %} {% extends "base.html" %}
{% load i18n %} {% load i18n %}
{% load static %} {% load static %}
{% load custom_filters %} {% load custom_filters %}
{% block content %} {% block content %}
<style> <style>
.color-option { .color-option {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -62,18 +62,18 @@
.btn-group button { .btn-group button {
margin: 0 5px; margin: 0 5px;
} }
</style> </style>
<div class="row mt-3"> <div class="row mt-3">
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %}
<div class="d-flex flex-column min-vh-100"> <div class="d-flex flex-column min-vh-100">
<div class="d-flex flex-column flex-sm-grow-1 ms-sm-14 p-4"> <div class="d-flex flex-column flex-sm-grow-1 ms-sm-14 p-4">
<main class="d-grid gap-4 p-1"> <main class="d-grid gap-4 p-1">
{% if car.colors.exists %} {% if car.colors.exists %}
<p class="text-center mb-4">{% trans 'Update Color' %}</p> <p class="text-center mb-4">{% trans 'Update Color' %}</p>
{% else %} {% else %}
<div class="form-title"> <div class="form-title">
<p>{% trans 'Add Color for' %} {{ car.id_car_make.get_local_name }} {{ car.id_car_model.get_local_name }}</p> <p>{% trans 'Add Color for' %} {{ car.id_car_make.get_local_name }} {{ car.id_car_model.get_local_name }}</p>
</div> </div>
<!-- Color Type Selection --> <!-- Color Type Selection -->
@ -110,7 +110,7 @@
</div> </div>
</div> </div>
</form> </form>
</div> </div>
<script> <script>
function highlightSelectedColor(selectedId) { function highlightSelectedColor(selectedId) {
document.querySelectorAll('.color-option').forEach(option => { document.querySelectorAll('.color-option').forEach(option => {
@ -129,5 +129,5 @@
document.getElementById() document.getElementById()
} }
}); });
</script> </script>
{% endblock content %} {% endblock content %}

View File

@ -2,15 +2,15 @@
<div class="margin10 center" style="min-height:120px;"> <div class="margin10 center" style="min-height:120px;">
<div data-aaad="true" data-aa-adunit="/22815767462/CLHX_728v_1" data-status="rendered" id="9868dff0-5025-4bf8-ba3a-df1a6220e51b" data-aa-device="[&quot;bigDesktop&quot;,&quot;desktop&quot;,&quot;smallDesktop&quot;,&quot;tablet&quot;]" data-aa-sizes="[[970,90],[728,90]]" data-aa-lazy-loaded="false" data-aa-refresh-viewable="30" data-google-query-id="CL7JkYCp64kDFZp1pAQdPh4w0w"><div id="google_ads_iframe_/22815767462,22668611618/CLHX_728v_1_0__row__" style="border: 0pt none;"><iframe id="google_ads_iframe_/22815767462,22668611618/CLHX_728v_1_0" name="google_ads_iframe_/22815767462,22668611618/CLHX_728v_1_0" title="3rd party ad content" width="1" height="1" scrolling="no" marginwidth="0" marginheight="0" frameborder="0" aria-label="Advertisement" tabindex="0" allow="private-state-token-redemption;attribution-reporting" data-load-complete="true" style="border: 0px; vertical-align: bottom; width: 728px; height: 90px;" data-google-row-id="1"></iframe></div></div> <div data-aaad="true" data-aa-adunit="/22815767462/CLHX_728v_1" data-status="rendered" id="9868dff0-5025-4bf8-ba3a-df1a6220e51b" data-aa-device="[&quot;bigDesktop&quot;,&quot;desktop&quot;,&quot;smallDesktop&quot;,&quot;tablet&quot;]" data-aa-sizes="[[970,90],[728,90]]" data-aa-lazy-loaded="false" data-aa-refresh-viewable="30" data-google-query-id="CL7JkYCp64kDFZp1pAQdPh4w0w"><div id="google_ads_iframe_/22815767462,22668611618/CLHX_728v_1_0__row__" style="border: 0pt none;"><iframe id="google_ads_iframe_/22815767462,22668611618/CLHX_728v_1_0" name="google_ads_iframe_/22815767462,22668611618/CLHX_728v_1_0" title="3rd party ad content" width="1" height="1" scrolling="no" marginwidth="0" marginheight="0" frameborder="0" aria-label="Advertisement" tabindex="0" allow="private-state-token-redemption;attribution-reporting" data-load-complete="true" style="border: 0px; vertical-align: bottom; width: 728px; height: 90px;" data-google-row-id="1"></iframe></div></div>
<div data-aaad="true" data-aa-adunit="/22815767462/CLHX_Mob_300v_1" data-status="skipped" id="0b22b9ef-8269-48aa-8684-e1c990efc466" data-aa-device="[&quot;mobile&quot;]" data-aa-sizes="[[320,100],[320,50]]" data-aa-lazy-loaded="true" data-aa-refresh-viewable="30"></div> <div data-aaad="true" data-aa-adunit="/22815767462/CLHX_Mob_300v_1" data-status="skipped" id="0b22b9ef-8269-48aa-8684-e1c990efc466" data-aa-device="[&quot;mobile&quot;]" data-aa-sizes="[[320,100],[320,50]]" data-aa-lazy-loaded="true" data-aa-refresh-viewable="30"></div>
</div> </div>
<h1>Popular Colors</h1> <h1>Popular Colors</h1>
#ff80ed #ff80ed
#065535 #065535
#000000 #000000
#133337 #133337
#ffc0cb</a><br><span class="glyphicon glyphicon-star"></span>707</div> #ffc0cb</a><br><span class="glyphicon glyphicon-star"></span>707</div>
#ffffff</a><br><span class="glyphicon glyphicon-star"></span>607</div> #ffffff</a><br><span class="glyphicon glyphicon-star"></span>607</div>
#ffe4e1</a><br><span class="glyphicon glyphicon-star"></span>559</div> #ffe4e1</a><br><span class="glyphicon glyphicon-star"></span>559</div>
#008080</a><br><span class="glyphicon glyphicon-star"></span>542</div> #008080</a><br><span class="glyphicon glyphicon-star"></span>542</div>

View File

@ -2,12 +2,12 @@
{% load i18n static %} {% load i18n static %}
{% block title %} {% block title %}
{% trans "inventory"|capfirst %} {% trans "inventory"|capfirst %}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div class="row justify-content-between"> <div class="row justify-content-between">
<div class="col-sm-12 "> <div class="col-sm-12 ">
<div class="card border h-100 w-100 p-lg-10"> <div class="card border h-100 w-100 p-lg-10">
<div class="bg-holder bg-card" style="background-image:url({% static 'images/spot-illustrations/32.png' %});background-position: top right;"> <div class="bg-holder bg-card" style="background-image:url({% static 'images/spot-illustrations/32.png' %});background-position: top right;">
@ -22,10 +22,10 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<!-- Total Cars --> <!-- Total Cars -->
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-sm-12"> <div class="col-sm-12">
<!-- Inventory by Makes --> <!-- Inventory by Makes -->
<div class="accordion" id="makesAccordion"> <div class="accordion" id="makesAccordion">
{% for make in inventory.makes %} {% for make in inventory.makes %}
@ -86,7 +86,7 @@
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -6,11 +6,11 @@
{% block title %}{% trans "Reserve Car" %}{% endblock %} {% block title %}{% trans "Reserve Car" %}{% endblock %}
{% block content %} {% block content %}
<h1>{% trans "Reserve Car" %}</h1> <h1>{% trans "Reserve Car" %}</h1>
<p>{% trans "You are reserving" %}: {{ car }}</p> <p>{% trans "You are reserving" %}: {{ car }}</p>
<form method="post" class="needs-validation" novalidate> <form method="post" class="needs-validation" novalidate>
{% csrf_token %} {% csrf_token %}
<div class="mb-3"> <div class="mb-3">
<label for="id_reservation_start">{% trans "Reservation Start Time" %}</label> <label for="id_reservation_start">{% trans "Reservation Start Time" %}</label>
@ -28,5 +28,5 @@
</div> </div>
<button type="submit" class="btn btn-primary">{% trans "Reserve" %}</button> <button type="submit" class="btn btn-primary">{% trans "Reserve" %}</button>
<a href="{% url 'car_detail' car.pk %}" class="btn btn-secondary">{% trans "Cancel" %}</a> <a href="{% url 'car_detail' car.pk %}" class="btn btn-secondary">{% trans "Cancel" %}</a>
</form> </form>
{% endblock %} {% endblock %}

View File

@ -2,7 +2,7 @@
{% load static i18n%} {% load static i18n%}
{% block content %} {% block content %}
<div class="container my-4"> <div class="container my-4">
<h3 class="mb-4">{{ _("Scan Vehicle Code")}}</h3> <h3 class="mb-4">{{ _("Scan Vehicle Code")}}</h3>
<form id="car-form" class="mb-3"> <form id="car-form" class="mb-3">
@ -25,9 +25,9 @@
</div> </div>
<div id="result" class="alert mt-3" style="display:none;"></div> <div id="result" class="alert mt-3" style="display:none;"></div>
</div> </div>
<script> <script>
function getCookie(name) { function getCookie(name) {
let cookieValue = null; let cookieValue = null;
if (document.cookie && document.cookie !== '') { if (document.cookie && document.cookie !== '') {
@ -152,5 +152,5 @@
} }
cameraContainer.style.display = 'none'; cameraContainer.style.display = 'none';
} }
</script> </script>
{% endblock content %} {% endblock content %}

View File

@ -3,8 +3,8 @@
{% block title %}{% trans "Transfer Car"|capfirst %}{% endblock title %} {% block title %}{% trans "Transfer Car"|capfirst %}{% endblock title %}
{% block content %} {% block content %}
<h1>{% trans "transfer car"|capfirst %}</h1> <h1>{% trans "transfer car"|capfirst %}</h1>
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %}
{% for field in form %} {% for field in form %}
<div class="form-group"> <div class="form-group">
@ -21,7 +21,7 @@
</div> </div>
{% endfor %} {% endfor %}
<button type="submit" class="btn btn-sm btn-primary">{% trans "transfer"|capfirst %}</button> <button type="submit" class="btn btn-sm btn-primary">{% trans "transfer"|capfirst %}</button>
</form> </form>
{% endblock %} {% endblock %}

View File

@ -55,7 +55,7 @@
<div class="row g-3"> <div class="row g-3">
<div class="col-12"> <div class="col-12">
<h3 class="my-3">{% trans 'Transfer Details' %}</h3> <h3 class="my-3">{% trans 'Transfer Details' %}</h3>
<div class="transfer-details"> <div class="transfer-details">
<p><strong>{% trans "Date" %} :</strong> {{transfer.created_at}}</p> <p><strong>{% trans "Date" %} :</strong> {{transfer.created_at}}</p>
<p><strong>{% trans "From" %} :</strong> {{transfer.from_dealer}}</p> <p><strong>{% trans "From" %} :</strong> {{transfer.from_dealer}}</p>
<p><strong>{% trans "To" %} :</strong> {{transfer.to_dealer}}</p> <p><strong>{% trans "To" %} :</strong> {{transfer.to_dealer}}</p>

View File

@ -1,7 +1,7 @@
{% load static i18n %} {% load static i18n %}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>transfer</title> <title>transfer</title>
@ -121,10 +121,10 @@
<link href="{% static 'css/user-rtl.min.css' %}" type="text/css" rel="stylesheet" id="user-style-rtl"> <link href="{% static 'css/user-rtl.min.css' %}" type="text/css" rel="stylesheet" id="user-style-rtl">
{% endif %} {% endif %}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
</head> </head>
<body> <body>
{% if transfer.status != "approved" %} {% if transfer.status != "approved" %}
<main class="main" id="top"> <main class="main" id="top">
<div class="px-3"> <div class="px-3">
<div class="row min-vh-100 flex-center p-5"> <div class="row min-vh-100 flex-center p-5">
<div class="col-12 col-xl-10 col-xxl-8"> <div class="col-12 col-xl-10 col-xxl-8">
@ -153,7 +153,7 @@
</script> </script>
</main> </main>
{% else%} {% else%}
<div class="button-row"> <div class="button-row">
<button id="download-pdf" class="btn btn-primary"> <button id="download-pdf" class="btn btn-primary">
<i class="fas fa-download"></i> {% trans 'Download transfer' %} <i class="fas fa-download"></i> {% trans 'Download transfer' %}
@ -293,5 +293,5 @@
$('#rejectModal').modal('hide'); $('#rejectModal').modal('hide');
}); });
</script> </script>
</body> </body>
</html> </html>

View File

@ -4,7 +4,7 @@
{% block title %}{{ _("Expenses") }}{% endblock title %} {% block title %}{{ _("Expenses") }}{% endblock title %}
{% block content %} {% block content %}
<div class="row mt-4 mx-4"> <div class="row mt-4 mx-4">
<div class="d-flex justify-content-between mb-2 p-6"> <div class="d-flex justify-content-between mb-2 p-6">
<span></span> <span></span>
<h3 class="text-center">{% trans "Expenses" %}</h3> <h3 class="text-center">{% trans "Expenses" %}</h3>
@ -46,5 +46,5 @@
<div class="d-flex justify-content-center"> <div class="d-flex justify-content-center">
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -4,7 +4,7 @@
{% block title %}{{ _("Expenses") }}{% endblock title %} {% block title %}{{ _("Expenses") }}{% endblock title %}
{% block content %} {% block content %}
<div class="row"> <div class="row">
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">
<h3 class="mb-2">{% trans "Services" %}</h3> <h3 class="mb-2">{% trans "Services" %}</h3>

View File

@ -1,10 +1,10 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Title</title> <title>Title</title>
</head> </head>
<body> <body>
</body> </body>
</html> </html>

View File

@ -35,7 +35,7 @@
</div> </div>
</div> </div>
<div class="row my-5"> <div class="row my-5">
<div class="card rounded "> <div class="card rounded ">
<div class="card-header bg-primary text-white "> <div class="card-header bg-primary text-white ">
<p class="mb-0">{{ _("Bank Account Details") }}</p> <p class="mb-0">{{ _("Bank Account Details") }}</p>
@ -69,5 +69,5 @@
</a> </a>
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

Some files were not shown because too many files have changed in this diff Show More