diff --git a/core/__pycache__/admin.cpython-311.pyc b/core/__pycache__/admin.cpython-311.pyc index 184ee40..36d2b33 100644 Binary files a/core/__pycache__/admin.cpython-311.pyc and b/core/__pycache__/admin.cpython-311.pyc differ diff --git a/core/__pycache__/models.cpython-311.pyc b/core/__pycache__/models.cpython-311.pyc index 3fa3578..640695f 100644 Binary files a/core/__pycache__/models.cpython-311.pyc and b/core/__pycache__/models.cpython-311.pyc differ diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index f76bffb..82e52a2 100644 Binary files a/core/__pycache__/views.cpython-311.pyc and b/core/__pycache__/views.cpython-311.pyc differ diff --git a/core/admin.py b/core/admin.py index 9cc410d..1fb517a 100644 --- a/core/admin.py +++ b/core/admin.py @@ -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 +from .models import Profile, Truck, Shipment, Bid, Message, WhatsAppConfig, Country, City, TruckType, AppSetting, Banner from .whatsapp import send_whatsapp_message @admin.register(Country) @@ -97,3 +97,9 @@ class AppSettingAdmin(admin.ModelAdmin): if self.model.objects.exists(): return False return super().has_add_permission(request) + +@admin.register(Banner) +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') \ No newline at end of file diff --git a/core/migrations/0015_banner.py b/core/migrations/0015_banner.py new file mode 100644 index 0000000..5b9e097 --- /dev/null +++ b/core/migrations/0015_banner.py @@ -0,0 +1,33 @@ +# Generated by Django 5.2.7 on 2026-01-23 17:20 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0014_appsetting'), + ] + + operations = [ + migrations.CreateModel( + name='Banner', + 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)')), + ('image', models.ImageField(upload_to='banners/', verbose_name='Banner Image')), + ('link', models.URLField(blank=True, help_text='Internal or external URL', null=True, verbose_name='Link URL')), + ('is_active', models.BooleanField(default=True, verbose_name='Is Active')), + ('order', models.PositiveIntegerField(default=0, verbose_name='Order')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ], + options={ + 'verbose_name': 'Banner', + 'verbose_name_plural': 'Banners', + 'ordering': ['order', '-created_at'], + }, + ), + ] diff --git a/core/migrations/__pycache__/0015_banner.cpython-311.pyc b/core/migrations/__pycache__/0015_banner.cpython-311.pyc new file mode 100644 index 0000000..3a6b72e Binary files /dev/null and b/core/migrations/__pycache__/0015_banner.cpython-311.pyc differ diff --git a/core/models.py b/core/models.py index b5918c4..36e9cda 100644 --- a/core/models.py +++ b/core/models.py @@ -248,6 +248,37 @@ class AppSetting(models.Model): def __str__(self): return self.app_name +class Banner(models.Model): + 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) + image = models.ImageField(_('Banner Image'), upload_to='banners/') + link = models.URLField(_('Link URL'), blank=True, null=True, help_text=_("Internal or external URL")) + is_active = models.BooleanField(_('Is Active'), default=True) + order = models.PositiveIntegerField(_('Order'), default=0) + created_at = models.DateTimeField(auto_now_add=True) + + class Meta: + verbose_name = _('Banner') + verbose_name_plural = _('Banners') + ordering = ['order', '-created_at'] + + 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 + @receiver(post_save, sender=User) def create_user_profile(sender, instance, created, **kwargs): if created: @@ -276,4 +307,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) \ No newline at end of file + instance.user.groups.add(group) diff --git a/core/templates/core/index.html b/core/templates/core/index.html index 23febdf..b8a78a4 100644 --- a/core/templates/core/index.html +++ b/core/templates/core/index.html @@ -2,7 +2,56 @@ {% load i18n static %} {% block content %} - + +{% if banners %} + + +{% endif %} + + +{% if not banners %}
@@ -25,6 +74,7 @@
+{% endif %}
@@ -139,4 +189,4 @@
-{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/core/views.py b/core/views.py index 3c979ce..700236e 100644 --- a/core/views.py +++ b/core/views.py @@ -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 +from .models import Profile, Truck, Shipment, Bid, Message, OTPCode, Country, City, AppSetting, Banner from .forms import TruckForm, ShipmentForm, BidForm, UserRegistrationForm, OTPVerifyForm, ShipperOfferForm from django.contrib import messages from django.utils.translation import gettext as _ @@ -13,8 +13,10 @@ from django.contrib.auth.forms import AuthenticationForm def home(request): """Render the landing screen for MASAR CARGO.""" + banners = Banner.objects.filter(is_active=True) context = { "deployment_timestamp": timezone.now().timestamp(), + "banners": banners, } return render(request, "core/index.html", context) @@ -397,4 +399,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) \ No newline at end of file diff --git a/media/banners/banner_1.jpg b/media/banners/banner_1.jpg new file mode 100644 index 0000000..bf9cd02 Binary files /dev/null and b/media/banners/banner_1.jpg differ diff --git a/media/banners/banner_2.jpg b/media/banners/banner_2.jpg new file mode 100644 index 0000000..339013e Binary files /dev/null and b/media/banners/banner_2.jpg differ