adding contact form
This commit is contained in:
parent
d8b540ccd4
commit
7c076b687a
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -7,7 +7,7 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.html import format_html
|
from django.utils.html import format_html
|
||||||
import os
|
import os
|
||||||
from .models import Profile, Truck, Shipment, Bid, Message, WhatsAppConfig, Country, City, TruckType, AppSetting, Banner, HomeSection
|
from .models import Profile, Truck, Shipment, Bid, Message, WhatsAppConfig, Country, City, TruckType, AppSetting, Banner, HomeSection, ContactMessage
|
||||||
from .whatsapp import send_whatsapp_message
|
from .whatsapp import send_whatsapp_message
|
||||||
|
|
||||||
@admin.register(Country)
|
@admin.register(Country)
|
||||||
@ -189,4 +189,12 @@ class HomeSectionAdmin(admin.ModelAdmin):
|
|||||||
list_display = ('title', 'section_type', 'order', 'is_active')
|
list_display = ('title', 'section_type', 'order', 'is_active')
|
||||||
list_editable = ('order', 'is_active')
|
list_editable = ('order', 'is_active')
|
||||||
list_filter = ('section_type', 'is_active', 'background_color')
|
list_filter = ('section_type', 'is_active', 'background_color')
|
||||||
search_fields = ('title', 'title_ar', 'subtitle', 'subtitle_ar', 'content', 'content_ar')
|
search_fields = ('title', 'title_ar', 'subtitle', 'subtitle_ar', 'content', 'content_ar')
|
||||||
|
|
||||||
|
@admin.register(ContactMessage)
|
||||||
|
class ContactMessageAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('subject', 'name', 'email', 'created_at', 'is_read')
|
||||||
|
list_filter = ('is_read', 'created_at')
|
||||||
|
search_fields = ('subject', 'name', 'email', 'message')
|
||||||
|
readonly_fields = ('created_at',)
|
||||||
|
list_editable = ('is_read',)
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
from django import forms
|
from django import forms
|
||||||
from .models import Truck, Shipment, Bid, Profile, Country, OTPCode, City, TruckType, AppSetting
|
from .models import Truck, Shipment, Bid, Profile, Country, OTPCode, City, TruckType, AppSetting, ContactMessage
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.contrib.auth.forms import UserCreationForm
|
from django.contrib.auth.forms import UserCreationForm
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
@ -187,4 +187,15 @@ class AppSettingForm(forms.ModelForm):
|
|||||||
'shipper_annual_fee': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01'}),
|
'shipper_annual_fee': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01'}),
|
||||||
'truck_owner_monthly_fee': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01'}),
|
'truck_owner_monthly_fee': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01'}),
|
||||||
'truck_owner_annual_fee': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01'}),
|
'truck_owner_annual_fee': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01'}),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ContactForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = ContactMessage
|
||||||
|
fields = ['name', 'email', 'subject', 'message']
|
||||||
|
widgets = {
|
||||||
|
'name': forms.TextInput(attrs={'class': 'form-control', 'placeholder': _('Your Name')}),
|
||||||
|
'email': forms.EmailInput(attrs={'class': 'form-control', 'placeholder': _('Your Email')}),
|
||||||
|
'subject': forms.TextInput(attrs={'class': 'form-control', 'placeholder': _('Subject')}),
|
||||||
|
'message': forms.Textarea(attrs={'class': 'form-control', 'rows': 5, 'placeholder': _('Your Message')}),
|
||||||
|
}
|
||||||
|
|||||||
30
core/migrations/0023_contactmessage.py
Normal file
30
core/migrations/0023_contactmessage.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# Generated by Django 5.2.7 on 2026-01-24 08:43
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('core', '0022_alter_truck_driver_license_back_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='ContactMessage',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=100, verbose_name='Name')),
|
||||||
|
('email', models.EmailField(max_length=254, verbose_name='Email')),
|
||||||
|
('subject', models.CharField(max_length=200, verbose_name='Subject')),
|
||||||
|
('message', models.TextField(verbose_name='Message')),
|
||||||
|
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('is_read', models.BooleanField(default=False)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Contact Message',
|
||||||
|
'verbose_name_plural': 'Contact Messages',
|
||||||
|
'ordering': ['-created_at'],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
BIN
core/migrations/__pycache__/0023_contactmessage.cpython-311.pyc
Normal file
BIN
core/migrations/__pycache__/0023_contactmessage.cpython-311.pyc
Normal file
Binary file not shown.
@ -474,4 +474,20 @@ class Transaction(models.Model):
|
|||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.receipt_number} - {self.user.username} ({self.amount})"
|
return f"{self.receipt_number} - {self.user.username} ({self.amount})"
|
||||||
|
|
||||||
|
class ContactMessage(models.Model):
|
||||||
|
name = models.CharField(_('Name'), max_length=100)
|
||||||
|
email = models.EmailField(_('Email'))
|
||||||
|
subject = models.CharField(_('Subject'), max_length=200)
|
||||||
|
message = models.TextField(_('Message'))
|
||||||
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
|
is_read = models.BooleanField(default=False)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _('Contact Message')
|
||||||
|
verbose_name_plural = _('Contact Messages')
|
||||||
|
ordering = ['-created_at']
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.subject} - {self.name}"
|
||||||
|
|||||||
@ -66,6 +66,9 @@
|
|||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="{% url 'contact' %}">{% trans "Contact" %}</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li class="nav-item dropdown ms-lg-3">
|
<li class="nav-item dropdown ms-lg-3">
|
||||||
<a class="nav-link dropdown-toggle" href="#" id="langDropdown" role="button" data-bs-toggle="dropdown">
|
<a class="nav-link dropdown-toggle" href="#" id="langDropdown" role="button" data-bs-toggle="dropdown">
|
||||||
@ -156,7 +159,7 @@
|
|||||||
<ul class="list-unstyled">
|
<ul class="list-unstyled">
|
||||||
<li><a href="{% url 'privacy_policy' %}" class="text-white-50 text-decoration-none">{% trans "Privacy Policy" %}</a></li>
|
<li><a href="{% url 'privacy_policy' %}" class="text-white-50 text-decoration-none">{% trans "Privacy Policy" %}</a></li>
|
||||||
<li><a href="{% url 'terms_of_service' %}" class="text-white-50 text-decoration-none">{% trans "Terms of Service" %}</a></li>
|
<li><a href="{% url 'terms_of_service' %}" class="text-white-50 text-decoration-none">{% trans "Terms of Service" %}</a></li>
|
||||||
<li><a href="#" class="text-white-50 text-decoration-none">{% trans "Contact Us" %}</a></li>
|
<li><a href="{% url 'contact' %}" class="text-white-50 text-decoration-none">{% trans "Contact Us" %}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4 mb-4">
|
<div class="col-md-4 mb-4">
|
||||||
@ -186,4 +189,4 @@
|
|||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
101
core/templates/core/contact.html
Normal file
101
core/templates/core/contact.html
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<section class="py-5 bg-light">
|
||||||
|
<div class="container py-5">
|
||||||
|
<div class="row g-5">
|
||||||
|
<!-- Contact Info -->
|
||||||
|
<div class="col-lg-5">
|
||||||
|
<div class="mb-5">
|
||||||
|
<h1 class="fw-bold mb-3">{% trans "Get in Touch" %}</h1>
|
||||||
|
<p class="text-muted lead">
|
||||||
|
{% trans "Have questions about our services or need assistance? Fill out the form and our team will get back to you shortly." %}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-flex mb-4">
|
||||||
|
<div class="flex-shrink-0">
|
||||||
|
<div class="bg-primary text-white p-3 rounded-3" style="width: 50px; height: 50px; display: flex; align-items: center; justify-content: center;">
|
||||||
|
<i class="fa-solid fa-phone"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ms-4">
|
||||||
|
<h5 class="fw-bold">{% trans "Phone" %}</h5>
|
||||||
|
<p class="text-muted">{{ app_settings.contact_phone|default:"+966 XXX XXX XXX" }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-flex mb-4">
|
||||||
|
<div class="flex-shrink-0">
|
||||||
|
<div class="bg-primary text-white p-3 rounded-3" style="width: 50px; height: 50px; display: flex; align-items: center; justify-content: center;">
|
||||||
|
<i class="fa-solid fa-envelope"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ms-4">
|
||||||
|
<h5 class="fw-bold">{% trans "Email" %}</h5>
|
||||||
|
<p class="text-muted">{{ app_settings.contact_email|default:"info@masarcargo.com" }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-flex mb-4">
|
||||||
|
<div class="flex-shrink-0">
|
||||||
|
<div class="bg-primary text-white p-3 rounded-3" style="width: 50px; height: 50px; display: flex; align-items: center; justify-content: center;">
|
||||||
|
<i class="fa-solid fa-location-dot"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ms-4">
|
||||||
|
<h5 class="fw-bold">{% trans "Address" %}</h5>
|
||||||
|
<p class="text-muted">{{ app_settings.contact_address|default:"Muscat, Oman"|linebreaksbr }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Contact Form -->
|
||||||
|
<div class="col-lg-7">
|
||||||
|
<div class="card border-0 shadow-sm rounded-4 p-4 p-md-5">
|
||||||
|
<h2 class="fw-bold mb-4">{% trans "Send us a Message" %}</h2>
|
||||||
|
<form method="post" novalidate>
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="row g-3">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label class="form-label fw-bold small text-uppercase">{% trans "Your Name" %}</label>
|
||||||
|
{{ form.name }}
|
||||||
|
{% if form.name.errors %}
|
||||||
|
<div class="text-danger small mt-1">{{ form.name.errors }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label class="form-label fw-bold small text-uppercase">{% trans "Email Address" %}</label>
|
||||||
|
{{ form.email }}
|
||||||
|
{% if form.email.errors %}
|
||||||
|
<div class="text-danger small mt-1">{{ form.email.errors }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="col-12">
|
||||||
|
<label class="form-label fw-bold small text-uppercase">{% trans "Subject" %}</label>
|
||||||
|
{{ form.subject }}
|
||||||
|
{% if form.subject.errors %}
|
||||||
|
<div class="text-danger small mt-1">{{ form.subject.errors }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="col-12">
|
||||||
|
<label class="form-label fw-bold small text-uppercase">{% trans "Message" %}</label>
|
||||||
|
{{ form.message }}
|
||||||
|
{% if form.message.errors %}
|
||||||
|
<div class="text-danger small mt-1">{{ form.message.errors }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="col-12 mt-4">
|
||||||
|
<button type="submit" class="btn btn-primary btn-lg px-5 rounded-pill w-100">
|
||||||
|
{% trans "Send Message" %}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{% endblock %}
|
||||||
@ -22,6 +22,7 @@ urlpatterns = [
|
|||||||
path("bid/<int:bid_id>/reject/", views.reject_bid, name="reject_bid"),
|
path("bid/<int:bid_id>/reject/", views.reject_bid, name="reject_bid"),
|
||||||
path("privacy-policy/", views.privacy_policy, name="privacy_policy"),
|
path("privacy-policy/", views.privacy_policy, name="privacy_policy"),
|
||||||
path("terms-of-service/", views.terms_of_service, name="terms_of_service"),
|
path("terms-of-service/", views.terms_of_service, name="terms_of_service"),
|
||||||
|
path("contact/", views.contact, name="contact"),
|
||||||
path("subscription-expired/", views.subscription_expired, name="subscription_expired"),
|
path("subscription-expired/", views.subscription_expired, name="subscription_expired"),
|
||||||
path("subscription-renew/", views.renew_subscription, name="renew_subscription"),
|
path("subscription-renew/", views.renew_subscription, name="renew_subscription"),
|
||||||
path("payment/success/", views.thawani_success, name="thawani_success"),
|
path("payment/success/", views.thawani_success, name="thawani_success"),
|
||||||
|
|||||||
@ -5,10 +5,11 @@ from django.contrib.auth.decorators import login_required
|
|||||||
from django.contrib.auth import login, authenticate, logout
|
from django.contrib.auth import login, authenticate, logout
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from .models import Profile, Truck, Shipment, Bid, Message, OTPCode, Country, City, AppSetting, Banner, HomeSection, Transaction
|
from .models import Profile, Truck, Shipment, Bid, Message, OTPCode, Country, City, AppSetting, Banner, HomeSection, Transaction, ContactMessage
|
||||||
from .forms import (
|
from .forms import (
|
||||||
TruckForm, ShipmentForm, BidForm, UserRegistrationForm,
|
TruckForm, ShipmentForm, BidForm, UserRegistrationForm,
|
||||||
OTPVerifyForm, ShipperOfferForm, RenewSubscriptionForm, AppSettingForm
|
OTPVerifyForm, ShipperOfferForm, RenewSubscriptionForm, AppSettingForm,
|
||||||
|
ContactForm
|
||||||
)
|
)
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
@ -23,6 +24,7 @@ from django.http import HttpResponse
|
|||||||
from django.contrib.sites.shortcuts import get_current_site
|
from django.contrib.sites.shortcuts import get_current_site
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -731,4 +733,26 @@ def admin_app_settings(request):
|
|||||||
else:
|
else:
|
||||||
form = AppSettingForm(instance=settings_obj)
|
form = AppSettingForm(instance=settings_obj)
|
||||||
|
|
||||||
return render(request, 'core/app_settings.html', {'form': form})
|
return render(request, 'core/app_settings.html', {'form': form})
|
||||||
|
|
||||||
|
def contact(request):
|
||||||
|
app_settings = AppSetting.objects.first()
|
||||||
|
if request.method == 'POST':
|
||||||
|
form = ContactForm(request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
form.save()
|
||||||
|
messages.success(request, _("Your message has been sent successfully! We will get back to you soon."))
|
||||||
|
return redirect('contact')
|
||||||
|
else:
|
||||||
|
messages.error(request, _("There was an error in your form. Please check the fields below."))
|
||||||
|
else:
|
||||||
|
form = ContactForm()
|
||||||
|
if request.user.is_authenticated:
|
||||||
|
# Pre-fill name and email if user is logged in
|
||||||
|
form.fields['name'].initial = request.user.get_full_name() or request.user.username
|
||||||
|
form.fields['email'].initial = request.user.email
|
||||||
|
|
||||||
|
return render(request, 'core/contact.html', {
|
||||||
|
'form': form,
|
||||||
|
'app_settings': app_settings
|
||||||
|
})
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user