adding editing main page from admin panel

This commit is contained in:
Flatlogic Bot 2026-01-24 03:19:24 +00:00
parent f1cec56a71
commit 081f578fb5
11 changed files with 140 additions and 7 deletions

View File

@ -4,7 +4,7 @@ from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.contrib import messages
from django.utils.translation import gettext_lazy as _
from .models import Profile, Truck, Shipment, Bid, Message, WhatsAppConfig, Country, City, TruckType, AppSetting, Banner
from .models import Profile, Truck, Shipment, Bid, Message, WhatsAppConfig, Country, City, TruckType, AppSetting, Banner, HomeSection
from .whatsapp import send_whatsapp_message
@admin.register(Country)
@ -102,4 +102,11 @@ class AppSettingAdmin(admin.ModelAdmin):
class BannerAdmin(admin.ModelAdmin):
list_display = ('title', 'order', 'is_active', 'created_at')
list_editable = ('order', 'is_active')
search_fields = ('title', 'title_ar', 'subtitle', 'subtitle_ar')
search_fields = ('title', 'title_ar', 'subtitle', 'subtitle_ar')
@admin.register(HomeSection)
class HomeSectionAdmin(admin.ModelAdmin):
list_display = ('title', 'section_type', 'order', 'is_active')
list_editable = ('order', 'is_active')
list_filter = ('section_type', 'is_active', 'background_color')
search_fields = ('title', 'title_ar', 'subtitle', 'subtitle_ar', 'content', 'content_ar')

View File

@ -0,0 +1,35 @@
# Generated by Django 5.2.7 on 2026-01-24 03:16
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0015_banner'),
]
operations = [
migrations.CreateModel(
name='HomeSection',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=200, verbose_name='Title (EN)')),
('title_ar', models.CharField(blank=True, max_length=200, verbose_name='Title (AR)')),
('subtitle', models.CharField(blank=True, max_length=255, verbose_name='Subtitle (EN)')),
('subtitle_ar', models.CharField(blank=True, max_length=255, verbose_name='Subtitle (AR)')),
('content', models.TextField(blank=True, verbose_name='Content (EN)')),
('content_ar', models.TextField(blank=True, verbose_name='Content (AR)')),
('image', models.ImageField(blank=True, null=True, upload_to='home_sections/', verbose_name='Image')),
('order', models.PositiveIntegerField(default=0, verbose_name='Order')),
('is_active', models.BooleanField(default=True, verbose_name='Is Active')),
('section_type', models.CharField(choices=[('SIMPLE', 'Simple Text & Image'), ('FEATURES', 'Features List'), ('CTA', 'Call to Action')], default='SIMPLE', max_length=20)),
('background_color', models.CharField(default='white', help_text='e.g. white, light, primary', max_length=50)),
],
options={
'verbose_name': 'Home Section',
'verbose_name_plural': 'Home Sections',
'ordering': ['order'],
},
),
]

View File

@ -279,6 +279,50 @@ class Banner(models.Model):
return self.subtitle_ar
return self.subtitle
class HomeSection(models.Model):
SECTION_TYPES = (
('SIMPLE', _('Simple Text & Image')),
('FEATURES', _('Features List')),
('CTA', _('Call to Action')),
)
title = models.CharField(_('Title (EN)'), max_length=200)
title_ar = models.CharField(_('Title (AR)'), max_length=200, blank=True)
subtitle = models.CharField(_('Subtitle (EN)'), max_length=255, blank=True)
subtitle_ar = models.CharField(_('Subtitle (AR)'), max_length=255, blank=True)
content = models.TextField(_('Content (EN)'), blank=True)
content_ar = models.TextField(_('Content (AR)'), blank=True)
image = models.ImageField(_('Image'), upload_to='home_sections/', blank=True, null=True)
order = models.PositiveIntegerField(_('Order'), default=0)
is_active = models.BooleanField(_('Is Active'), default=True)
section_type = models.CharField(max_length=20, choices=SECTION_TYPES, default='SIMPLE')
background_color = models.CharField(max_length=50, default='white', help_text="e.g. white, light, primary")
class Meta:
verbose_name = _('Home Section')
verbose_name_plural = _('Home Sections')
ordering = ['order']
def __str__(self):
return self.title
@property
def display_title(self):
if get_language() == 'ar' and self.title_ar:
return self.title_ar
return self.title
@property
def display_subtitle(self):
if get_language() == 'ar' and self.subtitle_ar:
return self.subtitle_ar
return self.subtitle
@property
def display_content(self):
if get_language() == 'ar' and self.content_ar:
return self.content_ar
return self.content
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
@ -307,4 +351,4 @@ def sync_user_groups(sender, instance, **kwargs):
instance.user.groups.remove(*other_groups)
# Add user to the correct group
instance.user.groups.add(group)
instance.user.groups.add(group)

View File

@ -50,7 +50,7 @@
</section>
{% endif %}
<!-- Hero Section (Only show if no banners, or maybe as a secondary section?) -->
<!-- Hero Section (Only show if no banners) -->
{% if not banners %}
<section class="hero-section py-5">
<div class="container">
@ -76,6 +76,51 @@
</section>
{% endif %}
<!-- Dynamic Home Sections -->
{% for section in home_sections %}
<section class="py-5 {% if section.background_color == 'light' %}bg-light{% elif section.background_color == 'primary' %}bg-primary text-white{% else %}bg-white{% endif %}">
<div class="container py-5">
{% if section.section_type == 'SIMPLE' %}
<div class="row align-items-center {% if forloop.counter|divisibleby:2 %}flex-row-reverse{% endif %}">
<div class="col-lg-6 mb-4 mb-lg-0">
<h2 class="fw-bold mb-3">{{ section.display_title }}</h2>
{% if section.display_subtitle %}
<h5 class="{% if section.background_color == 'primary' %}text-white-50{% else %}text-muted{% endif %} mb-4">{{ section.display_subtitle }}</h5>
{% endif %}
<div class="content lead">
{{ section.display_content|linebreaks }}
</div>
</div>
{% if section.image %}
<div class="col-lg-6">
<img src="{{ section.image.url }}" alt="{{ section.display_title }}" class="img-fluid rounded-4 shadow">
</div>
{% endif %}
</div>
{% elif section.section_type == 'CTA' %}
<div class="text-center">
<h2 class="fw-bold mb-3">{{ section.display_title }}</h2>
{% if section.display_subtitle %}
<p class="lead mb-4 opacity-75">{{ section.display_subtitle }}</p>
{% endif %}
<div class="mb-4">
{{ section.display_content|linebreaks }}
</div>
<a href="{% url 'register' %}" class="btn {% if section.background_color == 'primary' %}btn-light text-primary{% else %}btn-primary{% endif %} btn-lg px-5 rounded-pill fw-bold">{% trans "Get Started" %}</a>
</div>
{% elif section.section_type == 'FEATURES' %}
<div class="text-center mb-5">
<h2 class="fw-bold mb-3">{{ section.display_title }}</h2>
<p class="lead text-muted">{{ section.display_subtitle }}</p>
</div>
<div class="row g-4">
{{ section.display_content|safe }}
</div>
{% endif %}
</div>
</section>
{% endfor %}
<!-- Role Selection Section -->
<section class="py-5 bg-light" id="how-it-works">
<div class="container py-5">
@ -189,4 +234,4 @@
</div>
</section>
{% endblock %}
{% endblock %}

View File

@ -2,7 +2,7 @@ from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.decorators import login_required
from django.contrib.auth import login, authenticate, logout
from django.utils import timezone
from .models import Profile, Truck, Shipment, Bid, Message, OTPCode, Country, City, AppSetting, Banner
from .models import Profile, Truck, Shipment, Bid, Message, OTPCode, Country, City, AppSetting, Banner, HomeSection
from .forms import TruckForm, ShipmentForm, BidForm, UserRegistrationForm, OTPVerifyForm, ShipperOfferForm
from django.contrib import messages
from django.utils.translation import gettext as _
@ -14,9 +14,11 @@ from django.contrib.auth.forms import AuthenticationForm
def home(request):
"""Render the landing screen for MASAR CARGO."""
banners = Banner.objects.filter(is_active=True)
home_sections = HomeSection.objects.filter(is_active=True).order_by('order')
context = {
"deployment_timestamp": timezone.now().timestamp(),
"banners": banners,
"home_sections": home_sections,
}
return render(request, "core/index.html", context)
@ -399,4 +401,4 @@ def terms_of_service(request):
'content': app_settings.terms_of_service if app_settings else _("Terms of service are coming soon.")
}
}
return render(request, 'core/article_detail.html', context)
return render(request, 'core/article_detail.html', context)

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

BIN
media/app/masarlogo.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB