This commit is contained in:
gitea 2025-02-09 07:38:44 +00:00
commit ffd72e2d93
256 changed files with 8946 additions and 2033 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@ -28,6 +28,11 @@
<orderEntry type="library" name="line" level="application" />
<orderEntry type="library" name="@turf/turf" level="application" />
<orderEntry type="library" name="apexcharts" level="application" />
<orderEntry type="library" name="moment.js" level="application" />
<orderEntry type="library" name="moment-timezone" level="application" />
<orderEntry type="library" name="fullcalendar" level="application" />
<orderEntry type="library" name="popper.js" level="application" />
<orderEntry type="library" name="tempusdominus-bootstrap-4" level="application" />
</component>
<component name="TemplatesService">
<option name="TEMPLATE_CONFIGURATION" value="Django" />

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptLibraryMappings">
<file url="file://$PROJECT_DIR$" libraries="{@turf/turf, @zxing, apexcharts, bootstrap-icons, jquery, jquery-3.5.1, line, quagga, sweetalert2, tesseract.js}" />
<file url="file://$PROJECT_DIR$" libraries="{@turf/turf, @zxing, apexcharts, bootstrap-icons, fullcalendar, jquery, jquery-3.5.1, line, moment-timezone, moment.js, popper.js, quagga, sweetalert2, tempusdominus-bootstrap-4, tesseract.js}" />
</component>
</project>

BIN
inventory/.DS_Store vendored

Binary file not shown.

View File

@ -33,6 +33,9 @@ admin.site.register(models.Customer)
admin.site.register(models.Opportunity)
admin.site.register(models.Notification)
admin.site.register(models.Lead)
admin.site.register(models.Activity)
admin.site.register(models.Schedule)
admin.site.register(models.Notes)
@admin.register(models.CarMake)
class CarMakeAdmin(admin.ModelAdmin):

View File

@ -38,7 +38,7 @@ from .models import (
Staff,
Opportunity, Priority, Sources, Lead, Activity, Notes, CarModel,SaleOrder,CarMake
)
from django_ledger.models import ItemModel, InvoiceModel, BillModel,VendorModel
from django_ledger import models as ledger_models
from django.forms import ModelMultipleChoiceField, ValidationError, DateInput,DateTimeInput
from django.utils.translation import gettext_lazy as _
import django_tables2 as tables
@ -191,7 +191,7 @@ class CarForm(
(obj.id_car_model, obj.get_local_name()) for obj in queryset
]
if "vendor" in self.fields:
self.fields["vendor"].queryset = VendorModel.objects.filter(active=True)
self.fields["vendor"].queryset = ledger_models.VendorModel.objects.filter(active=True)
# queryset = self.fields["vendor"].queryset
# self.fields["vendor"].choices = [
# (obj.pk, obj.get_local_name()) for obj in queryset
@ -596,7 +596,7 @@ class WizardForm3(forms.Form):
class ItemForm(forms.Form):
item = forms.ModelChoiceField(
queryset=ItemModel.objects.all(), label="Item", required=True,
queryset=ledger_models.ItemModel.objects.all(), label="Item", required=True,
validators=[MinLengthValidator(5)],
)
quantity = forms.DecimalField(label="Quantity", required=True)
@ -607,10 +607,10 @@ class ItemForm(forms.Form):
class PaymentForm(forms.Form):
invoice = forms.ModelChoiceField(
queryset=InvoiceModel.objects.all(), label="Invoice", required=False
queryset=ledger_models.InvoiceModel.objects.all(), label="Invoice", required=False
)
bill = forms.ModelChoiceField(
queryset=BillModel.objects.all(), label="Bill", required=False
queryset=ledger_models.BillModel.objects.all(), label="Bill", required=False
)
amount = forms.DecimalField(label="Amount", required=True)
payment_method = forms.ChoiceField(
@ -688,6 +688,7 @@ class ScheduleForm(forms.ModelForm):
model = Schedule
fields = ['purpose','scheduled_type', 'scheduled_at', 'notes']
class NoteForm(forms.ModelForm):
class Meta:
model = Notes
@ -737,6 +738,32 @@ class SaleOrderForm(forms.ModelForm):
}
class EstimateModelCreateForm(EstimateModelCreateFormBase):
class Meta:
model = ledger_models.EstimateModel
fields = ['title', 'customer', 'terms']
widgets = {
'customer': forms.Select(attrs={
'id': 'djl-customer-estimate-customer-input',
'class': 'input',
'label': _('Customer'),
}),
'terms': forms.Select(attrs={
'id': 'djl-customer-estimate-terms-input',
'class': 'input',
'label': _('Terms'),
}),
'title': forms.TextInput(attrs={
'id': 'djl-customer-job-title-input',
'class': 'input' + ' is-large',
'label': _('Title'),
})
}
labels = {
'title': _('Title'),
'terms': _('Terms'),
'customer': _('Customer'),
}
def __init__(self, *args, entity_slug, user_model, **kwargs):
super(EstimateModelCreateForm, self).__init__(*args, entity_slug=entity_slug, user_model=user_model, **kwargs)
self.ENTITY_SLUG = entity_slug

View File

@ -1614,14 +1614,14 @@ def decode_vds(manufacturer, vds):
},
'Dongfeng': {
1: { # First character
1: {
'A': 'A-Series',
'B': 'SHINE', # SHINE model
'C': 'C-Series', # General C-Series
'D': 'MAGE', # MAGE model
'E': ['CAPTAIN E', 'E32'], # CAPTAIN and E-Series models
'F': 'CAPTAIN C', # CAPTAIN C model
'G': 'S50', # S50 model
'B': 'SHINE',
'C': 'C-Series',
'D': 'MAGE',
'E': ['CAPTAIN E', 'E32'],
'F': 'CAPTAIN C',
'G': 'S50',
'H': 'Dongfeng Fengshen AX3',
'J': 'Dongfeng Joyear SUV',
'K': 'Dongfeng Rich 6',
@ -1629,7 +1629,7 @@ def decode_vds(manufacturer, vds):
'M': 'Dongfeng Glory 580',
},
2: { # Second character (for C-Series)
2: {
'3': 'C35', # Specific models in C-Series
'1': 'C31',
'2': 'C32',

View File

@ -0,0 +1,14 @@
# Generated by Django 5.1.5 on 2025-02-06 08:51
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('inventory', '0002_alter_carregistration_car'),
('inventory', '0011_remove_lead_year_alter_schedule_customer'),
]
operations = [
]

View File

@ -1,4 +1,4 @@
# Generated by Django 4.2.17 on 2025-02-06 11:25
# Generated by Django 5.1.5 on 2025-02-07 01:25
from django.db import migrations, models
@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0012_merge_20250206_1308'),
('inventory', '0012_merge_20250206_1151'),
]
operations = [

View File

@ -1,4 +1,5 @@
from datetime import timezone
# from datetime import timezone
from django.utils import timezone
import itertools
from uuid import uuid4
from django.conf import settings
@ -1224,7 +1225,7 @@ class Schedule(models.Model):
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return f"Scheduled {self.purpose} with {self.customer.customer_name} on {self.scheduled_at}"
return f"Scheduled {self.purpose} with {self.lead.full_name} on {self.scheduled_at}"
@property
def schedule_past_date(self):
@ -1342,7 +1343,7 @@ class Activity(models.Model):
verbose_name_plural = _("Activities")
def __str__(self):
return f"{self.get_activity_type_display()} by {self.created_by.name} on {self.content_object}"
return f"{self.get_activity_type_display()} by {self.created_by.get_full_name} on {self.content_object}"
class Notification(models.Model):

View File

@ -855,3 +855,14 @@ def update_car_status_on_reservation_update(sender, instance, **kwargs):
# items = instance.get_itemtxs_data()[0].all()
# total = sum([Decimal(item.item_model.additional_info['car_finance']["selling_price"]) * Decimal(item.ce_quantity) for item in items])
@receiver(post_save, sender=models.Schedule)
def create_activity_on_schedule_creation(sender, instance, created, **kwargs):
if created:
models.Activity.objects.create(
content_object=instance,
activity_type='Schedule Created',
created_by=instance.scheduled_by.user,
notes=f"New schedule created for {instance.purpose} with {instance.lead.full_name} on {instance.scheduled_at}."
)

View File

@ -93,8 +93,10 @@ urlpatterns = [
"crm/leads/<int:pk>/update/", views.LeadUpdateView.as_view(), name="lead_update"
),
path("crm/leads/<int:pk>/delete/", views.LeadDeleteView, name="lead_delete"),
path("crm/leads/<int:pk>/add-note/", views.add_note_to_lead, name="add_note"),
path("crm/leads/<int:pk>/lead-convert/", views.lead_convert, name="lead_convert"),
path("crm/leads/<int:pk>/add-note/", views.add_note_to_lead, name="add_note"),
path('crm/leads/<int:pk>/update-note/', views.update_note, name='update_note'),
path("crm/leads/<int:pk>/delete-note/", views.delete_note, name="delete_note"),
path(
"crm/leads/<int:pk>/add-activity/",
views.add_activity_to_lead,

View File

@ -210,26 +210,23 @@ def dealer_signup(request, *args, **kwargs):
)
# class Login(allauth_views.LoginView):
# template_name = "account/login.html"
# redirect_authenticated_user = True
class OTPView(View, LoginRequiredMixin):
template_name = "account/otp_verification.html"
def get(self, request, *args, **kwargs):
# device = default_device(request.user)
# device.generate_challenge()
return render(request, self.template_name)
def post(self, request, *args, **kwargs):
otp_code = request.POST.get("otp_code")
if self.verify_otp(otp_code, request.user):
messages.success(request, _("OTP verified successfully!"))
return redirect("home")
messages.error(request, _("Invalid OTP. Please try again."))
return render(request, self.template_name)
# class OTPView(View, LoginRequiredMixin):
# template_name = "account/otp_verification.html"
#
# def get(self, request, *args, **kwargs):
# # device = default_device(request.user)
# # device.generate_challenge()
# return render(request, self.template_name)
#
# def post(self, request, *args, **kwargs):
# otp_code = request.POST.get("otp_code")
#
# if self.verify_otp(otp_code, request.user):
# messages.success(request, _("OTP verified successfully!"))
# return redirect("home")
#
# messages.error(request, _("Invalid OTP. Please try again."))
# return render(request, self.template_name)
# def verify_otp(self, otp_code, user):
# device = default_device(user)
@ -238,8 +235,6 @@ class OTPView(View, LoginRequiredMixin):
# return False
class HomeView(TemplateView):
template_name = "index.html"
@ -2435,7 +2430,7 @@ def create_estimate(request):
return JsonResponse(
{
"status": "success",
"message": "Estimate created successfully!",
"message": "Quotation created successfully!",
"url": f"{url}",
}
)
@ -2983,6 +2978,7 @@ def LeadDeleteView(request,pk):
return redirect("lead_list")
@login_required
def add_note_to_lead(request, pk):
lead = get_object_or_404(models.Lead, pk=pk)
if request.method == "POST":
@ -2990,14 +2986,45 @@ def add_note_to_lead(request, pk):
if form.is_valid():
note = form.save(commit=False)
note.content_object = lead
note.created_by = request.user
note.save()
return redirect("lead_detail", pk=pk)
messages.success(request, "Note added successfully!")
return redirect("lead_detail", pk=lead.pk)
else:
form = forms.NoteForm()
return render(request, "crm/add_note.html", {"form": form, "lead": lead})
return render(request, "crm/note_form.html", {"form": form, "lead": lead})
@login_required
def update_note(request, pk):
note = get_object_or_404(models.Notes, pk=pk, created_by=request.user)
lead_pk = note.content_object.pk
if request.method == "POST":
form = forms.NoteForm(request.POST, instance=note)
if form.is_valid():
updated_note = form.save(commit=False)
updated_note.content_object = note.content_object
updated_note.created_by = request.user
updated_note.save()
messages.success(request, "Note updated successfully!")
return redirect("lead_detail", pk=lead_pk)
else:
form = forms.NoteForm(instance=note)
return render(request, "crm/note_form.html", {"form": form, "note": note})
@login_required
def delete_note(request, pk):
note = get_object_or_404(models.Notes, pk=pk, created_by=request.user)
lead_pk = note.content_object.pk
note.delete()
messages.success(request, _("Note deleted successfully."))
return redirect("lead_detail", pk=lead_pk)
@login_required
def lead_convert(request, pk):
lead = get_object_or_404(models.Lead, pk=pk)
dealer = get_user_type(request)
@ -3009,6 +3036,8 @@ def lead_convert(request, pk):
messages.success(request, "Lead converted to customer successfully!")
return redirect("opportunity_create",pk=lead.pk)
@login_required
def schedule_lead(request, pk):
lead = get_object_or_404(models.Lead, pk=pk)
if request.method == "POST":
@ -3028,6 +3057,8 @@ def schedule_lead(request, pk):
form = forms.ScheduleForm()
return render(request, "crm/leads/schedule_lead.html", {"lead": lead, "form": form})
@login_required
def send_lead_email(request, pk):
lead = get_object_or_404(models.Lead, pk=pk)
dealer = get_user_type(request)
@ -3070,6 +3101,8 @@ def send_lead_email(request, pk):
{"lead": lead, "message": msg},
)
@login_required
def add_activity_to_lead(request, pk):
lead = get_object_or_404(models.Lead, pk=pk)
if request.method == "POST":

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -40,7 +40,7 @@ dj-rest-auth==7.0.1
dj-shop-cart==8.0.0a2
Django==5.1.5
django-allauth==65.3.1
django-appointment==3.7.4
django-appointment==3.8.0
django-autoslug==1.9.9
django-bootstrap5==24.3
django-classy-tags==4.1.0

BIN
static/.DS_Store vendored

Binary file not shown.

View File

@ -0,0 +1,53 @@
/* Hide scrollbar for day grid month view on small screens */
@media (max-width: 767px) {
.djangoAppt_no-events {
margin-bottom: 10px;
}
.djangoAppt_btn-new-event {
padding: 5px 8px !important;
font-size: 13px !important;
}
.fc-dayGridMonth-view .fc-scroller {
overflow: hidden !important;
}
.modal-content {
margin: 0 auto !important;
}
.modal-footer {
text-align: left !important;
flex-wrap: inherit !important;
justify-content: center !important;
align-content: flex-start;
}
#eventDetailsModal .btn {
margin-right: 2px !important;
font-size: 13px !important;
}
#eventModalBody, #serviceSelect {
font-size: 13px !important;
}
#eventModalLabel {
font-size: 15px !important;
}
}
/* Hide scrollbar for time grid day view on larger screens */
@media (min-width: 450px) {
.fc-timeGridDay-view .fc-scroller {
overflow: hidden !important;
}
}
@media (min-width: 600px) {
.fc-scroller {
overflow: hidden !important;
}
}

View File

@ -0,0 +1,144 @@
.section-content-button {
position: absolute;
top: 20px;
right: 20px;
}
.modify-btn {
color: #fff;
padding: 8px 12px;
border: none;
border-radius: 4px;
cursor: pointer;
text-decoration: none;
transition: all 0.3s; /* Consistent transition */
}
/* Button hover effects for a dynamic touch */
.modify-btn:hover {
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.1);
transform: scale(1.05) translateY(-3px);
}
.button-color-blue {
background: linear-gradient(90deg, #007BFF, #0056b3);
}
.button-color-red {
background: linear-gradient(90deg, #dc3545, #c82333);
}
.button-color-green {
background: linear-gradient(90deg, #28a745, #218838);
}
.button-color-yellow {
background: linear-gradient(90deg, #ffc107, #d39e00);
}
.button-color-purple {
background: linear-gradient(90deg, #6f42c1, #5a32a3);
}
.button-color-orange {
background: linear-gradient(90deg, #fd7e14, #e66400);
}
.button-color-teal {
background: linear-gradient(90deg, #20c997, #17a2b8);
}
.button-color-pink {
background: linear-gradient(90deg, #e83e8c, #d63384);
}
.button-color-gray {
background: linear-gradient(90deg, #6c757d, #5a636e);
}
.button-color-blue:hover {
background: linear-gradient(90deg, #0056b3, #007BFF); /* Reverse gradient on hover */
transform: scale(1.05); /* Slight scale on hover for engagement */
color: #babaf5;
}
.button-color-red:hover {
background: linear-gradient(90deg, #c82333, #dc3545);
transform: scale(1.05);
color: #efcece;
}
.button-color-green:hover {
background: linear-gradient(90deg, #218838, #28a745);
transform: scale(1.05);
color: #c3e6cb;
}
.button-color-yellow:hover {
background: linear-gradient(90deg, #d39e00, #ffc107); /* Reverse gradient on hover */
transform: scale(1.05); /* Slight scale on hover for engagement */
color: #ffe58a;
}
.button-color-purple:hover {
background: linear-gradient(90deg, #5a32a3, #6f42c1);
transform: scale(1.05);
color: #d1b6e1;
}
.button-color-orange:hover {
background: linear-gradient(90deg, #e66400, #fd7e14);
transform: scale(1.05);
color: #ffcc99;
}
.button-color-teal:hover {
background: linear-gradient(90deg, #17a2b8, #20c997);
transform: scale(1.05);
color: #ace2e1;
}
.button-color-pink:hover {
background: linear-gradient(90deg, #d63384, #e83e8c);
transform: scale(1.05);
color: #f2a6c6;
}
.button-color-gray:hover {
background: linear-gradient(90deg, #5a636e, #6c757d);
transform: scale(1.05);
color: #d1d5d9;
}
.buttons-container {
display: flex;
gap: 5px; /* Provides space between the buttons */
}
.service-btn-container {
display: flex;
flex-direction: row;
gap: 20px;
}
.service-btn {
padding: 8px 20px !important;
}
@media screen and (max-width: 768px) {
.modify-btn {
padding: 6px 10px;
font-size: 14px;
}
}
@media screen and (max-width: 487px) {
.section-content-button.modify-btn {
padding: 4px 8px;
font-size: 12px;
}
.buttons-container {
gap: 3px;
}
}

View File

@ -0,0 +1,35 @@
.days-off-form-wrapper {
margin: 0 auto;
padding-top: 50px;
}
.days-off-form-wrapper h2 {
margin-top: 0;
margin-bottom: 20px;
text-align: center;
}
.do-form-content {
padding: 20px;
border: 1px solid #ddd;
border-radius: 5px;
max-width: 600px;
margin: 0 auto;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 5px;
}
.form-group input, .form-group select, .form-group textarea {
width: 100%;
padding: 10px;
border: 1px solid #e0e0e0;
border-radius: 4px;
}

View File

@ -0,0 +1,140 @@
.appointment-display-content{
margin: 30px auto;
padding: 20px 0;
}
.app-content {
max-width: 950px;
padding: 20px;
border: 1px solid #ddd;
border-radius: 5px;
margin: 0 auto;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(800px);
background-color: transparent;
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes fadeInGreen {
from {
background-color: transparent;
}
to {
background-color: #4CAF50; /* green */
}
}
@keyframes fadeInRed {
from {
background-color: transparent;
}
to {
background-color: #F44336; /* red */
}
}
.appointment-card {
border: 1px solid #e0e0e0;
padding: 20px;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
margin-top: 20px;
animation: fadeIn 0.5s forwards;
display: flex;
flex-direction: column;
align-items: center; /* Center the contents */
}
.appointment-card h2 {
margin-top: 0;
border-bottom: 1px solid #e0e0e0;
padding-bottom: 10px;
width: 100%;
}
.appointment-details {
display: flex;
flex-wrap: wrap;
margin-top: 20px;
width: 100%;
justify-content: space-between; /* Evenly space the details */
}
.appointment-detail, .appointment-detail-payment {
flex: 1;
padding: 10px;
border: 1px solid #e0e0e0;
margin: 5px;
border-radius: 4px;
flex-basis: 48%; /* Allow 2 details per row with a little space in between */
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* Add subtle shadow */
transition: all 0.3s; /* Smooth transitions */
animation: fadeIn 0.6s forwards; /* Default fade-in */
}
.appointment-detail:nth-child(1) { animation-delay: 0.05s; }
.appointment-detail:nth-child(2) { animation-delay: 0.05s; }
.appointment-detail:nth-child(3) { animation-delay: 0.1s; }
.appointment-detail:nth-child(4) { animation-delay: 0.1s; }
.appointment-detail:nth-child(5) { animation-delay: 0.15s; }
.appointment-detail:nth-child(6) { animation-delay: 0.15s; }
.appointment-detail:nth-child(7) { animation-delay: 0.2s; }
.appointment-detail:nth-child(8) { animation-delay: 0.2s; }
.appointment-detail:nth-child(9) { animation-delay: 0.25s; }
.appointment-detail:nth-child(10) { animation-delay: 0.25s; }
.appointment-detail:nth-child(11) { animation-delay: 0.3s; }
.appointment-detail:nth-child(12) { animation-delay: 0.3s; }
.is-paid-true {
animation: fadeIn 0.35s forwards, fadeInGreen 0.35s forwards;
color: white;
}
.is-paid-false {
animation: fadeIn 0.35s forwards, fadeInRed 0.35s forwards;
color: white;
}
.hover-element:hover {
background-color: #f7f7f7;
transform: translateY(-5px); /* Slight elevation on hover */
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15); /* Enhanced shadow on hover */
}
.appointment-detail i {
margin-right: 10px;
color: #555; /* Slightly darker icon color */
}
/* Mobile First Styles (Default) */
.appointment-detail, .appointment-detail-payment {
flex-basis: 100%; /* Each detail takes the full width on mobile */
margin: 10px 0; /* Adjusted margin */
}
/* Tablet Styles */
@media (min-width: 768px) and (max-width: 991px) {
.appointment-detail, .appointment-detail-payment {
flex-basis: 48%; /* 2 details per row for tablets */
margin: 5px; /* Revert to original margin */
}
}
/* Desktop Styles */
@media (min-width: 992px) {
.appointment-detail, .appointment-detail-payment {
flex-basis: 48%; /* 2 details per row for desktop */
margin: 5px;
}
}

View File

@ -0,0 +1,37 @@
.service-form-wrapper {
padding: 20px 0;
}
.service-form-content {
padding: 20px;
margin: 30px auto;
border: 1px solid #ddd;
border-radius: 5px;
max-width: 600px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
h2 {
border-bottom: 1px solid #e0e0e0;
padding-bottom: 15px;
margin-bottom: 30px;
font-weight: 600;
}
.form-control {
width: 100%;
padding: 5px;
border: 1px solid #ccc;
border-radius: 5px;
transition: border 0.3s;
}
.form-control:focus {
border-color: #007BFF;
box-shadow: 0 0 5px rgba(0,123,255,0.2);
}
/* Design TextArea */
textarea.form-control {
height:60px;
}

View File

@ -0,0 +1,92 @@
/* staff_form.css */
.staff-form-wrapper {
margin: 15px auto;
padding: 10px 0;
}
.staff-form-content {
padding: 20px;
border: 1px solid #ddd;
border-radius: 5px;
max-width: 1100px;
margin: 0 auto;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
h3 {
border-bottom: 1px solid #e0e0e0;
padding-bottom: 15px;
margin-bottom: 20px;
font-weight: 500;
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: 500;
}
.form-control {
width: 100%;
padding: 2px 10px;
border: 1px solid #ccc;
border-radius: 5px;
transition: border 0.3s;
}
.form-control:focus {
border-color: #007BFF;
box-shadow: 0 0 5px rgba(0,123,255,0.2);
}
.form-check {
margin-bottom: 10px;
}
.form-check label {
margin-left: 5px;
font-weight: 400;
}
.btn {
padding: 10px 20px;
border: none;
background-color: #007bff;
color: #fff;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s;
}
.btn:hover {
background-color: #0056b3;
}
/* ############################### */
.user-not-found {
margin-top: 2px;
margin-bottom: 20px;
padding: 5px;
background-color: #f9f9f9;
border-radius: 4px;
font-size: 0.9rem;
}
.user-not-found a {
color: #007bff;
text-decoration: underline;
}
.user-not-found small {
color: #666;
}
small {
color: #3d3d3d;
font-size: 12px;
}

View File

@ -0,0 +1,202 @@
body {
font-family: 'Arial', sans-serif;
}
.profile-container {
margin: 5px auto;
background-color: #fff;
border-radius: 8px;
}
.service-container {
margin: 5px auto;
border-radius: 8px;
}
.profile-section {
border: 1px solid inherit;
max-width: 1000px;
padding: 20px;
margin: 0 auto 30px auto;
position: relative;
background-color: inherit;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
border-radius: 6px;
transition: all 0.3s;
}
.profile-section:hover {
transform: translateY(-5px);
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.12);
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.section-content {
margin-top: 20px;
}
.profile-section h2 {
margin-bottom: 20px; /* Space between the title and content */
}
.profile-section p {
line-height: 1.5em; /* Enhanced line spacing for readability */
margin-bottom: 15px;
}
table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
font-size: 16px;
text-align: left;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
border-radius: 6px;
overflow: hidden; /* To respect border-radius in tables */
}
table th, table td {
padding: 12px 15px;
border-bottom: 1px solid #ddd;
transition: background-color 0.3s; /* Smooth transition for hover effect */
}
table th {
background-color: #f2f2f2;
font-weight: bold;
}
table tbody tr:hover {
background-color: #f5f5f5;
}
/* Adding gradient backgrounds for a more vibrant look */
.profile-container {
/*background-image: linear-gradient(to bottom right, #fff, #f7f9fc);*/
}
/* Additional hover effect for the sections */
.profile-section:hover {
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.08);
}
/* Elegant & smooth transitions for all elements */
* {
transition: all 0.3s ease-out;
}
/* Elevate the table headers for a layered appearance */
table th {
position: relative;
z-index: 2;
box-shadow: 0 6px 10px rgba(0, 0, 0, 0.06);
}
/* Subtle hover effects for table rows */
table tbody tr {
position: relative;
z-index: 1;
transform: scale(1);
transition: transform 0.3s, box-shadow 0.3s;
}
table tbody tr:hover {
transform: scale(1.01);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
/* Animate the appearance of the profile sections for a smooth load-in effect */
@keyframes slideInFromLeft {
0% {
transform: translateX(-100%);
opacity: 0;
}
100% {
transform: translateX(0);
opacity: 1;
}
}
.profile-section {
animation: slideInFromLeft 0.6s forwards;
}
/* Staggered animation delays for each section for a sequential load-in */
.profile-section:nth-child(1) {
animation-delay: 0.2s;
}
.profile-section:nth-child(2) {
animation-delay: 0.4s;
}
.profile-section:nth-child(3) {
animation-delay: 0.6s;
}
.profile-section:nth-child(4) {
animation-delay: 0.8s;
}
.profile-section:nth-child(5) {
animation-delay: 1.0s;
}
/* Consider adding this for a smoother feel when scrolling */
body {
scroll-behavior: smooth;
}
/* Responsive design for tablets and mobile devices */
@media screen and (max-width: 768px) {
.profile-container {
margin: 20px 10px;
padding: 15px;
}
.profile-section {
padding: 15px;
}
.section-content-button {
top: 10px;
right: 10px;
}
table th, table td {
padding: 10px;
}
.profile-section h2 {
font-size: 20px;
margin-bottom: 15px;
}
.profile-section p {
font-size: 14px;
}
.responsive-table-container {
overflow-x: auto; /* Allows horizontal scrolling */
-webkit-overflow-scrolling: touch; /* Smooth scroll for touch devices */
}
/* Optional: Add a shadow on the right to indicate more content */
.responsive-table-container::before {
content: '';
position: absolute;
top: 0;
right: 0;
width: 10px;
height: 100%;
box-shadow: -5px 0 10px rgba(0, 0, 0, 0.05);
pointer-events: none; /* Ensures it doesn't interfere with other interactions */
}
}

View File

@ -0,0 +1,262 @@
/* Set margins for the main container */
.main-container {
margin-left: 20px;
margin-right: 20px;
}
/* Center and set max width for the body container */
.body-container {
margin: 0 auto;
max-width: 1080px;
padding: 0 15px;
}
/* Set display and margin for page body */
.page-body {
display: flex;
flex-direction: row;
margin-top: 50px;
}
/* Set flex for appointment user info */
.appointment-user-info {
flex: 3;
}
/* Set flex and margin for service description and pay */
.service-description-and-pay {
flex: 1;
margin-left: 20px; /* Adjust the value as needed */
}
/* Set margins and font styles for title sections */
.appointment-user-info-title, .service-details-title, .payment-details-title {
margin-bottom: 10px;
font-family: Lobster, cursive;
font-size: 18px;
color: #0c042c;
}
/* Set font styles for description titles */
.description-title {
font-size: 16px;
font-weight: 400;
color: #0c042c;
}
/* Set margins, borders, padding, and font styles for the "already have an account" section */
.already-have-account {
margin-top: 25px;
margin-bottom: 30px;
width: 100%;
border: 1px solid #0c042c;
border-radius: 2px;
justify-content: left;
padding: 10px 8px;
display: flex;
align-items: center;
font-family: "DejaVu Serif", serif;
}
/* Set grid display and column gap for name and email input fields */
.name-email {
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 10px;
}
/* Set margin and display for "receive email" checkbox */
.receive-email {
margin-bottom: 20px;
}
/* Set margins and display for phone number, address, and additional information input fields */
.address, .additional-information {
margin-top: 20px;
display: grid;
}
.phone-number {
margin-bottom: 15px;
}
.phone-input-container {
display: flex;
align-items: center; /* vertically center the items */
}
.phone-number select {
margin-right: 10px; /* add some space between them */
}
.phone-number input {
flex: 1; /* take available space */
}
.phone-number select {
padding: 6px 10px;
border-radius: 4px;
border: 1px solid #ccc;
appearance: none; /* remove default appearance */
background-color: #fff;
margin-right: 10px;
cursor: pointer;
font-size: 14px;
color: #333;
transition: border-color 0.3s;
}
.phone-number select:focus {
border-color: #007bff;
outline: none;
}
/* Set font styles for input labels */
label {
font-family: "DejaVu Serif", serif;
}
/* Set margin for second part horizontal line */
.second-part {
margin-top: 10px;
}
/* Set grid display, padding, and margin for user info input fields */
.user-info-input {
margin-top: 20px;
display: grid;
padding: 30px 10px;
}
/* Set grid display, padding, margin, and font styles for service description */
.service-description-content {
margin-top: 20px;
color: black;
padding-top: 30px;
display: grid;
grid-template-rows: 1fr 1fr 1fr;
grid-gap: 10px;
font-family: "DejaVu Serif", serif;
font-size: 16px;
}
/* Set font style for service name */
.item-name {
color: black;
}
/* Set flex for title section */
.title {
flex: 1;
}
/* Set color for links */
a {
color: #0c042c;
}
/* Set padding, border radius, and font styles for input fields */
.user-info input {
box-sizing: border-box;
padding: 5px;
border-radius: 5px;
}
.name-email {
margin-bottom: 15px;
}
/* Set width, margin and border */
.user-info-input input[type="text"],
.user-info-input input[type="email"],
.user-info-input textarea {
width: 100%;
border: 1px solid #a2a2a2;
}
/* Set a 2px solid border with a specific color when the input or textarea is in focus */
.user-info-input input[type="text"]:focus,
.user-info-input input[type="email"]:focus,
.user-info-input input[type="tel"]:focus,
.user-info-input textarea:focus {
border: 2px solid #040f49;
}
/* Style for the payment total */
.total {
margin-top: 20px;
margin-bottom: 10px;
display: flex;
justify-content: space-between;
align-items: center;
font-family: "DejaVu Serif", serif;
color: rgba(12, 4, 44, 0.93);
font-size: 16px;
line-height: 1.8;
}
/* Media query for screens up to 795px */
@media only screen and (max-width: 795px) {
/* Adjust the page body layout for smaller screens */
.page-body {
flex-direction: column;
}
/* Adjust the flex properties for smaller screens */
.appointment-user-info,
.service-description-and-pay {
flex: none; /* reset the flex */
width: 100%; /* take full width */
}
/* Remove the margin for service description and pay */
.service-description-and-pay {
margin-left: 0;
margin-bottom: 20px;
}
/* Adjust the grid for name and email for smaller screens */
.name-email {
grid-template-columns: 1fr; /* stack them vertically */
}
/* Adjust the phone number container */
.phone-input-container {
flex-direction: column;
align-items: stretch; /* make them take full width */
}
.phone-number select,
.phone-number input {
margin-right: 0;
margin-bottom: 10px;
}
/* Adjust the user info input fields */
.user-info-input {
padding: 20px 10px;
}
/* Adjust the service description content */
.service-description-content {
grid-template-rows: repeat(3, auto); /* adjust the grid rows */
}
/* Adjust the total layout */
.total {
flex-direction: column;
text-align: center;
}
}
@media only screen and (max-width: 450px) {
/* Adjust the page body layout for smaller screens */
.main-container {
width: 97%;
margin: 0 !important;
}
}

View File

@ -0,0 +1,17 @@
.fc-scroller {
overflow: hidden !important;
}
@media (max-width: 450px) {
.fc-daygrid-day-events {
display: none !important;
margin: 0 !important;
padding: 0 !important;
font-size: 0 !important;
height: 0 !important;
}
.fc, .fc-button {
padding: .3em .45em !important;
}
}

View File

@ -1,7 +1,7 @@
.djangoAppt_main-container {
margin: 20px auto;
max-width: 1200px;
padding: 20px;
background-color: rgba(248, 249, 250, 0.4);
border-radius: 5px;
box-shadow: 0 0 2px rgba(0, 0, 0, 0.1);
@ -22,7 +22,7 @@
.djangoAppt_appointment-calendar {
flex: 3;
padding: 20px;
background-color: #fff;
border-radius: 5px;
box-shadow: 0 0 2px rgba(0, 0, 0, 0.1);
}

66
static/css/thank_you.css Normal file
View File

@ -0,0 +1,66 @@
/* thank_you.css */
.content-body-apd {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
margin-top: 50px;
margin-bottom: 50px;
}
.main-content {
font-family: Arial, sans-serif;
line-height: 1.6;
padding: 20px;
color: #333;
max-width: 600px;
margin: 0 auto;
background-color: #fff;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
.thank-you-title {
font-size: 24px;
font-weight: bold;
text-align: center;
margin-bottom: 20px;
color: #007BFF;
}
.thank-you-message {
font-size: 18px;
text-align: center;
margin-bottom: 10px;
color: #333;
}
.appointment-details-title {
font-size: 16px;
font-weight: bold;
margin-bottom: 5px;
margin-top: 40px;
margin-left: 3px;
color: #333;
}
.appointment-details {
list-style-type: none;
padding: 0;
margin: 0;
}
.appointment-details li {
font-size: 14px;
margin-bottom: 5px;
background-color: #f4f4f4;
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.05);
}
.appointment-details li:last-child {
margin-bottom: 0;
}

View File

@ -0,0 +1,113 @@
/* verification_code_v2.css */
.vcode-container {
display: flex;
justify-content: center;
align-items: center;
min-height: 60vh;
padding: 20px;
}
.vcode-card {
background-color: #ffffff;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
padding: 40px;
width: 100%;
max-width: 400px;
}
.vcode-title {
font-size: 24px;
font-weight: 600;
color: #333;
text-align: center;
margin-bottom: 20px;
}
.vcode-instruction {
font-size: 16px;
color: #666;
text-align: center;
margin-bottom: 30px;
}
.vcode-form {
display: flex;
flex-direction: column;
}
.vcode-input-group {
margin-bottom: 20px;
}
.vcode-label {
display: block;
font-size: 14px;
font-weight: 500;
color: #333;
margin-bottom: 8px;
}
.vcode-input {
width: 100%;
padding: 10px;
font-size: 16px;
border: 1px solid #ddd;
border-radius: 4px;
transition: border-color 0.3s ease;
}
.vcode-input:focus {
outline: none;
border-color: #4a90e2;
}
.vcode-button {
background-color: #4a90e2;
color: #ffffff;
font-size: 16px;
font-weight: 500;
padding: 12px;
border: none;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s ease;
}
.vcode-button:hover {
background-color: #3a7bc8;
}
.vcode-alert {
margin-top: 20px;
padding: 12px;
border-radius: 4px;
font-size: 14px;
text-align: center;
}
.vcode-alert-error {
background-color: #fde8e8;
color: #9b1c1c;
border: 1px solid #fbd5d5;
}
.vcode-alert-success {
background-color: #e6fffa;
color: #046c4e;
border: 1px solid #b2f5ea;
}
@media (max-width: 480px) {
.vcode-card {
padding: 30px;
}
.vcode-title {
font-size: 22px;
}
.vcode-instruction {
font-size: 14px;
}
}

Binary file not shown.

BIN
static/images/car_make/.DS_Store vendored Normal file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

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