This commit is contained in:
Flatlogic Bot 2026-01-23 09:32:37 +00:00
parent d457a5b75d
commit de92a4ccc0
38 changed files with 2098 additions and 211 deletions

View File

@ -42,6 +42,7 @@ SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SAMESITE = "None"
CSRF_COOKIE_SAMESITE = "None"
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/
@ -61,6 +62,7 @@ INSTALLED_APPS = [
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
@ -133,7 +135,7 @@ AUTH_PASSWORD_VALIDATORS = [
# Internationalization
# https://docs.djangoproject.com/en/5.2/topics/i18n/
LANGUAGE_CODE = 'en-us'
LANGUAGE_CODE = 'en'
TIME_ZONE = 'UTC'
@ -180,3 +182,17 @@ if EMAIL_USE_SSL:
# https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
from django.utils.translation import gettext_lazy as _
LANGUAGES = [
('en', _('English')),
('ar', _('Arabic')),
]
LOCALE_PATHS = [
BASE_DIR / 'locale',
]
MEDIA_URL = 'media/'
MEDIA_ROOT = BASE_DIR / 'media'

View File

@ -1,25 +1,10 @@
"""
URL configuration for config project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/5.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import include, path
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('i18n/', include('django.conf.urls.i18n')),
path("admin/", admin.site.urls),
path("", include("core.urls")),
]
@ -27,3 +12,4 @@ urlpatterns = [
if settings.DEBUG:
urlpatterns += static("/assets/", document_root=settings.BASE_DIR / "assets")
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

View File

@ -1,3 +1,30 @@
from django.contrib import admin
from .models import Profile, Truck, Shipment, Bid, Message
# Register your models here.
@admin.register(Profile)
class ProfileAdmin(admin.ModelAdmin):
list_display = ('user', 'role', 'phone_number')
list_filter = ('role',)
search_fields = ('user__username', 'phone_number')
@admin.register(Truck)
class TruckAdmin(admin.ModelAdmin):
list_display = ('truck_type', 'model', 'plate_no', 'owner', 'load_capacity')
search_fields = ('plate_no', 'owner__username', 'truck_type')
@admin.register(Shipment)
class ShipmentAdmin(admin.ModelAdmin):
list_display = ('origin', 'destination', 'shipper', 'status', 'delivery_date')
list_filter = ('status', 'delivery_date')
search_fields = ('origin', 'destination', 'shipper__username')
@admin.register(Bid)
class BidAdmin(admin.ModelAdmin):
list_display = ('shipment', 'truck_owner', 'amount', 'status')
list_filter = ('status',)
search_fields = ('shipment__origin', 'shipment__destination', 'truck_owner__username')
@admin.register(Message)
class MessageAdmin(admin.ModelAdmin):
list_display = ('shipment', 'sender', 'timestamp')
search_fields = ('content', 'sender__username')

View File

@ -0,0 +1,26 @@
# Generated by Django 5.2.7 on 2026-01-23 07:18
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Profile',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('role', models.CharField(choices=[('SHIPPER', 'Shipper (Need Goods Moved)'), ('TRUCK_OWNER', 'Truck Owner (Service Provider)'), ('ADMIN', 'Administrator')], default='SHIPPER', max_length=20)),
('phone_number', models.CharField(blank=True, max_length=20)),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
]

View File

@ -0,0 +1,76 @@
# Generated by Django 5.2.7 on 2026-01-23 09:01
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Shipment',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('description', models.TextField(verbose_name='Goods Description')),
('weight', models.CharField(max_length=100, verbose_name='Weight/Volume')),
('origin', models.CharField(max_length=255, verbose_name='Origin')),
('destination', models.CharField(max_length=255, verbose_name='Destination')),
('delivery_date', models.DateField(verbose_name='Requested Delivery Date')),
('status', models.CharField(choices=[('OPEN', 'Open for Bids'), ('IN_PROGRESS', 'In Progress'), ('COMPLETED', 'Completed'), ('CANCELLED', 'Cancelled')], default='OPEN', max_length=20)),
('created_at', models.DateTimeField(auto_now_add=True)),
('shipper', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='shipments', to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name='Message',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('content', models.TextField()),
('timestamp', models.DateTimeField(auto_now_add=True)),
('sender', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sent_messages', to=settings.AUTH_USER_MODEL)),
('shipment', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='messages', to='core.shipment')),
],
),
migrations.CreateModel(
name='Truck',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('truck_type', models.CharField(max_length=100, verbose_name='Truck Type')),
('model', models.CharField(max_length=100, verbose_name='Model')),
('year', models.PositiveIntegerField(verbose_name='Year')),
('plate_no', models.CharField(max_length=50, verbose_name='Plate No')),
('load_capacity', models.CharField(max_length=100, verbose_name='Load Capacity')),
('color', models.CharField(max_length=50, verbose_name='Color')),
('truck_picture', models.ImageField(blank=True, null=True, upload_to='trucks/', verbose_name='Truck Picture')),
('registration_front', models.ImageField(blank=True, null=True, upload_to='docs/', verbose_name='Registration Front')),
('registration_back', models.ImageField(blank=True, null=True, upload_to='docs/', verbose_name='Registration Back')),
('driver_license', models.ImageField(blank=True, null=True, upload_to='docs/', verbose_name='Driver License')),
('created_at', models.DateTimeField(auto_now_add=True)),
('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='trucks', to=settings.AUTH_USER_MODEL)),
],
),
migrations.AddField(
model_name='shipment',
name='assigned_truck',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='assigned_shipments', to='core.truck'),
),
migrations.CreateModel(
name='Bid',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('amount', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='Offer Amount')),
('comments', models.TextField(blank=True, verbose_name='Comments')),
('status', models.CharField(choices=[('PENDING', 'Pending'), ('ACCEPTED', 'Accepted'), ('REJECTED', 'Rejected')], default='PENDING', max_length=20)),
('created_at', models.DateTimeField(auto_now_add=True)),
('truck_owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='bids', to=settings.AUTH_USER_MODEL)),
('shipment', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='bids', to='core.shipment')),
('truck', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.truck')),
],
),
]

View File

@ -1,3 +1,99 @@
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.utils.translation import gettext_lazy as _
# Create your models here.
class Profile(models.Model):
ROLE_CHOICES = (
('SHIPPER', _('Shipper (Need Goods Moved)')),
('TRUCK_OWNER', _('Truck Owner (Service Provider)')),
('ADMIN', _('Administrator')),
)
user = models.OneToOneField(User, on_delete=models.CASCADE)
role = models.CharField(max_length=20, choices=ROLE_CHOICES, default='SHIPPER')
phone_number = models.CharField(max_length=20, blank=True)
def __str__(self):
return f"{self.user.username} - {self.role}"
class Truck(models.Model):
owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name='trucks')
truck_type = models.CharField(_('Truck Type'), max_length=100)
model = models.CharField(_('Model'), max_length=100)
year = models.PositiveIntegerField(_('Year'))
plate_no = models.CharField(_('Plate No'), max_length=50)
load_capacity = models.CharField(_('Load Capacity'), max_length=100)
color = models.CharField(_('Color'), max_length=50)
# Pictures
truck_picture = models.ImageField(_('Truck Picture'), upload_to='trucks/', blank=True, null=True)
registration_front = models.ImageField(_('Registration Front'), upload_to='docs/', blank=True, null=True)
registration_back = models.ImageField(_('Registration Back'), upload_to='docs/', blank=True, null=True)
driver_license = models.ImageField(_('Driver License'), upload_to='docs/', blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"{self.truck_type} - {self.plate_no}"
class Shipment(models.Model):
STATUS_CHOICES = (
('OPEN', _('Open for Bids')),
('IN_PROGRESS', _('In Progress')),
('COMPLETED', _('Completed')),
('CANCELLED', _('Cancelled')),
)
shipper = models.ForeignKey(User, on_delete=models.CASCADE, related_name='shipments')
description = models.TextField(_('Goods Description'))
weight = models.CharField(_('Weight/Volume'), max_length=100)
origin = models.CharField(_('Origin'), max_length=255)
destination = models.CharField(_('Destination'), max_length=255)
delivery_date = models.DateField(_('Requested Delivery Date'))
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='OPEN')
assigned_truck = models.ForeignKey(Truck, on_delete=models.SET_NULL, null=True, blank=True, related_name='assigned_shipments')
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"{self.origin} to {self.destination} - {self.status}"
class Bid(models.Model):
STATUS_CHOICES = (
('PENDING', _('Pending')),
('ACCEPTED', _('Accepted')),
('REJECTED', _('Rejected')),
)
shipment = models.ForeignKey(Shipment, on_delete=models.CASCADE, related_name='bids')
truck_owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name='bids')
truck = models.ForeignKey(Truck, on_delete=models.CASCADE)
amount = models.DecimalField(_('Offer Amount'), max_digits=10, decimal_places=2)
comments = models.TextField(_('Comments'), blank=True)
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='PENDING')
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"Bid by {self.truck_owner.username} for {self.shipment}"
class Message(models.Model):
shipment = models.ForeignKey(Shipment, on_delete=models.CASCADE, related_name='messages')
sender = models.ForeignKey(User, on_delete=models.CASCADE, related_name='sent_messages')
content = models.TextField()
timestamp = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"From {self.sender.username} at {self.timestamp}"
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
if hasattr(instance, 'profile'):
instance.profile.save()
else:
Profile.objects.create(user=instance)

View File

@ -1,25 +1,156 @@
{% load static i18n %}
<!DOCTYPE html>
<html lang="en">
<html lang="{{ request.LANGUAGE_CODE }}" {% if request.LANGUAGE_CODE == 'ar' %}dir="rtl"{% endif %}>
<head>
<meta charset="UTF-8">
<title>{% block title %}Knowledge Base{% endblock %}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}MASAR CARGO{% endblock %}</title>
{% if project_description %}
<meta name="description" content="{{ project_description }}">
<meta property="og:description" content="{{ project_description }}">
<meta property="twitter:description" content="{{ project_description }}">
{% endif %}
{% if project_image_url %}
<meta property="og:image" content="{{ project_image_url }}">
<meta property="twitter:image" content="{{ project_image_url }}">
<!-- Bootstrap 5 CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
{% if request.LANGUAGE_CODE == 'ar' %}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.rtl.min.css">
{% endif %}
{% load static %}
<!-- Font Awesome -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link rel="stylesheet" href="{% static 'css/custom.css' %}?v={{ deployment_timestamp }}">
{% block head %}{% endblock %}
<style>
body { font-family: 'Outfit', sans-serif; background-color: #f8f9fa; }
{% if request.LANGUAGE_CODE == 'ar' %}
body { font-family: 'Cairo', sans-serif; }
{% endif %}
.navbar { background-color: #0A1D37; }
.navbar-brand, .nav-link { color: #fff !important; }
.btn-primary { background-color: #2196F3; border-color: #2196F3; }
footer { background-color: #0A1D37; color: #fff; padding: 3rem 0; }
</style>
</head>
<body>
{% block content %}{% endblock %}
<nav class="navbar navbar-expand-lg sticky-top">
<div class="container">
<a class="navbar-brand" href="/">
<i class="fa-solid fa-truck-fast me-2 text-info"></i> MASAR CARGO
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto align-items-center">
{% if user.is_authenticated %}
<li class="nav-item">
<a class="nav-link" href="{% url 'dashboard' %}">{% trans "Dashboard" %}</a>
</li>
{% if user.profile.role == 'TRUCK_OWNER' %}
<li class="nav-item">
<a class="nav-link" href="{% url 'marketplace' %}">{% trans "Marketplace" %}</a>
</li>
{% endif %}
{% endif %}
<li class="nav-item dropdown ms-lg-3">
<a class="nav-link dropdown-toggle" href="#" id="langDropdown" role="button" data-bs-toggle="dropdown">
<i class="fa-solid fa-globe me-1"></i> {{ request.LANGUAGE_CODE|upper }}
</a>
<ul class="dropdown-menu">
<li>
<form action="{% url 'set_language' %}" method="post">
{% csrf_token %}
<input name="next" type="hidden" value="{{ request.path }}">
<input name="language" type="hidden" value="en">
<button type="submit" class="dropdown-item">English</button>
</form>
</li>
<li>
<form action="{% url 'set_language' %}" method="post">
{% csrf_token %}
<input name="next" type="hidden" value="{{ request.path }}">
<input name="language" type="hidden" value="ar">
<button type="submit" class="dropdown-item">العربية</button>
</form>
</li>
</ul>
</li>
{% if user.is_authenticated %}
<li class="nav-item dropdown ms-lg-3">
<a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown">
<i class="fa-solid fa-user-circle me-1"></i> {{ user.username }}
</a>
<ul class="dropdown-menu">
<li>
<form action="{% url 'logout' %}" method="post">
{% csrf_token %}
<button type="submit" class="dropdown-item">{% trans "Logout" %}</button>
</form>
</li>
</ul>
</li>
{% else %}
<li class="nav-item ms-lg-3">
<a class="nav-link" href="{% url 'login' %}">{% trans "Login" %}</a>
</li>
<li class="nav-item">
<a class="btn btn-primary" href="{% url 'register' %}">{% trans "Get Started" %}</a>
</li>
{% endif %}
</ul>
</div>
</div>
</nav>
{% if messages %}
<div class="container mt-3">
{% for message in messages %}
<div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert">
{{ message }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
{% endfor %}
</div>
{% endif %}
<main>
{% block content %}{% endblock %}
</main>
<footer>
<div class="container">
<div class="row">
<div class="col-md-4 mb-4">
<h4 class="fw-bold">MASAR CARGO</h4>
<p class="text-white-50">{% trans "Empowering logistics with smart technology. Locally and abroad." %}</p>
</div>
<div class="col-md-4 mb-4">
<h5 class="fw-bold">{% trans "Quick Links" %}</h5>
<ul class="list-unstyled">
<li><a href="#" class="text-white-50 text-decoration-none">{% trans "Privacy Policy" %}</a></li>
<li><a href="#" 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>
</ul>
</div>
<div class="col-md-4 mb-4">
<h5 class="fw-bold">{% trans "Contact" %}</h5>
<p class="text-white-50">
<i class="fa-brands fa-whatsapp me-2"></i> +123 456 7890<br>
<i class="fa-solid fa-envelope me-2"></i> info@masarcargo.com
</p>
</div>
</div>
<hr class="bg-white-50">
<p class="text-center text-white-50 mb-0">&copy; 2026 MASAR CARGO. All rights reserved.</p>
</div>
</footer>
<!-- Bootstrap 5 JS Bundle -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
</html>

View File

@ -1,145 +1,142 @@
{% extends "base.html" %}
{% block title %}{{ project_name }}{% endblock %}
{% block head %}
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">
<style>
:root {
--bg-color-start: #6a11cb;
--bg-color-end: #2575fc;
--text-color: #ffffff;
--card-bg-color: rgba(255, 255, 255, 0.01);
--card-border-color: rgba(255, 255, 255, 0.1);
}
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: 'Inter', sans-serif;
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
color: var(--text-color);
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
text-align: center;
overflow: hidden;
position: relative;
}
body::before {
content: '';
position: absolute;
inset: 0;
background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' viewBox='0 0 100 100'><path d='M-10 10L110 10M10 -10L10 110' stroke-width='1' stroke='rgba(255,255,255,0.05)'/></svg>");
animation: bg-pan 20s linear infinite;
z-index: -1;
}
@keyframes bg-pan {
0% {
background-position: 0% 0%;
}
100% {
background-position: 100% 100%;
}
}
main {
padding: 2rem;
}
.card {
background: var(--card-bg-color);
border: 1px solid var(--card-border-color);
border-radius: 16px;
padding: 2.5rem 2rem;
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
box-shadow: 0 12px 36px rgba(0, 0, 0, 0.25);
}
h1 {
font-size: clamp(2.2rem, 3vw + 1.2rem, 3.2rem);
font-weight: 700;
margin: 0 0 1.2rem;
letter-spacing: -0.02em;
}
p {
margin: 0.5rem 0;
font-size: 1.1rem;
opacity: 0.92;
}
.loader {
margin: 1.5rem auto;
width: 56px;
height: 56px;
border: 4px solid rgba(255, 255, 255, 0.25);
border-top-color: #fff;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
.runtime code {
background: rgba(0, 0, 0, 0.25);
padding: 0.15rem 0.45rem;
border-radius: 4px;
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
border: 0;
}
footer {
position: absolute;
bottom: 1rem;
width: 100%;
text-align: center;
font-size: 0.85rem;
opacity: 0.75;
}
</style>
{% endblock %}
{% extends 'base.html' %}
{% load i18n static %}
{% block content %}
<main>
<div class="card">
<h1>Analyzing your requirements and generating your app…</h1>
<div class="loader" role="status" aria-live="polite" aria-label="Applying initial changes">
<span class="sr-only">Loading…</span>
<!-- Hero Section -->
<section class="hero-section py-5">
<div class="container">
<div class="row align-items-center">
<div class="col-lg-6 mb-5 mb-lg-0">
<h1 class="hero-title display-4 fw-bold mb-4">
{% trans "Smart Cargo Solutions" %}<br>
<span class="text-primary">{% trans "Locally & Abroad" %}</span>
</h1>
<p class="hero-subtitle lead text-muted mb-4">
{% trans "The most reliable platform connecting shippers with truck owners across the region. Transparent, fast, and secure." %}
</p>
<div class="d-flex gap-3">
<a href="{% url 'register' %}" class="btn btn-primary btn-lg px-4">{% trans "Start Shipping" %}</a>
<a href="#how-it-works" class="btn btn-outline-primary btn-lg px-4">{% trans "Learn More" %}</a>
</div>
</div>
<div class="col-lg-6">
<img src="https://img.freepik.com/free-vector/delivery-truck-with-packages-concept_23-2148464601.jpg" alt="Logistics" class="img-fluid rounded-4 shadow-lg">
</div>
</div>
</div>
<p class="hint">AppWizzy AI is collecting your requirements and applying the first changes.</p>
<p class="hint">This page will refresh automatically as the plan is implemented.</p>
<p class="runtime">
Runtime: Django <code>{{ django_version }}</code> · Python <code>{{ python_version }}</code>
— UTC <code>{{ current_time|date:"Y-m-d H:i:s" }}</code>
</p>
</div>
</main>
<footer>
Page updated: {{ current_time|date:"Y-m-d H:i:s" }} (UTC)
</footer>
</section>
<!-- Role Selection Section -->
<section class="py-5 bg-light" id="how-it-works">
<div class="container py-5">
<div class="text-center mb-5">
<h2 class="fw-bold text-primary">{% trans "How would you like to use MASAR?" %}</h2>
<p class="text-muted">{% trans "Choose your path to get started with our platform." %}</p>
</div>
<div class="row g-4">
<!-- Shipper Role -->
<div class="col-md-6">
<div class="card h-100 border-0 shadow-sm p-4 text-center">
<div class="mb-4">
<i class="fa-solid fa-box-open fa-3x text-primary"></i>
</div>
<h3 class="fw-bold">{% trans "I am a Shipper" %}</h3>
<p class="text-muted">
{% trans "I need to move goods locally or abroad. Post your shipment, receive offers from verified drivers, and track your cargo in real-time." %}
</p>
<ul class="list-unstyled text-start mb-4 mx-auto" style="max-width: 300px;">
<li><i class="fa-solid fa-check text-success me-2"></i> {% trans "Post shipments easily" %}</li>
<li><i class="fa-solid fa-check text-success me-2"></i> {% trans "Compare competitive bids" %}</li>
<li><i class="fa-solid fa-check text-success me-2"></i> {% trans "Real-time tracking" %}</li>
</ul>
<a href="{% url 'register' %}" class="btn btn-primary w-100 py-3">{% trans "Find a Truck" %}</a>
</div>
</div>
<!-- Truck Owner Role -->
<div class="col-md-6">
<div class="card h-100 border-0 shadow-sm p-4 text-center">
<div class="mb-4">
<i class="fa-solid fa-truck fa-3x text-primary"></i>
</div>
<h3 class="fw-bold">{% trans "I am a Truck Owner" %}</h3>
<p class="text-muted">
{% trans "I have trucks and want to find cargo to transport. Register your fleet, bid on available jobs, and grow your business." %}
</p>
<ul class="list-unstyled text-start mb-4 mx-auto" style="max-width: 300px;">
<li><i class="fa-solid fa-check text-success me-2"></i> {% trans "Access daily cargo leads" %}</li>
<li><i class="fa-solid fa-check text-success me-2"></i> {% trans "Flexible bidding system" %}</li>
<li><i class="fa-solid fa-check text-success me-2"></i> {% trans "Direct chat with shippers" %}</li>
</ul>
<a href="{% url 'register' %}" class="btn btn-primary w-100 py-3">{% trans "Register Your Truck" %}</a>
</div>
</div>
</div>
</div>
</section>
<!-- Features Section -->
<section class="bg-white py-5" id="features">
<div class="container py-5">
<div class="row g-5 align-items-center">
<div class="col-lg-5">
<h2 class="fw-bold mb-4">{% trans "Everything you need for seamless logistics" %}</h2>
<div class="d-flex mb-4">
<div class="flex-shrink-0">
<div class="bg-light p-3 rounded-3 text-primary">
<i class="fa-brands fa-whatsapp fa-2x"></i>
</div>
</div>
<div class="ms-4">
<h5 class="fw-bold">{% trans "WhatsApp Integration" %}</h5>
<p class="text-muted">{% trans "Receive instant updates and communicate easily via WhatsApp API." %}</p>
</div>
</div>
<div class="d-flex mb-4">
<div class="flex-shrink-0">
<div class="bg-light p-3 rounded-3 text-primary">
<i class="fa-solid fa-language fa-2x"></i>
</div>
</div>
<div class="ms-4">
<h5 class="fw-bold">{% trans "Multilingual Support" %}</h5>
<p class="text-muted">{% trans "Fully accessible in both Arabic and English for all users." %}</p>
</div>
</div>
<div class="d-flex">
<div class="flex-shrink-0">
<div class="bg-light p-3 rounded-3 text-primary">
<i class="fa-solid fa-shield-halved fa-2x"></i>
</div>
</div>
<div class="ms-4">
<h5 class="fw-bold">{% trans "Secure Documentation" %}</h5>
<p class="text-muted">{% trans "Digital verification of truck registration and driver licenses." %}</p>
</div>
</div>
</div>
<div class="col-lg-7">
<div class="row g-4">
<div class="col-6">
<img src="https://img.freepik.com/free-photo/view-truck-with-cargo_23-2150821510.jpg" class="img-fluid rounded-4 shadow" alt="">
</div>
<div class="col-6 mt-5">
<img src="https://img.freepik.com/free-photo/industrial-port-container-yard-with-cranes-logistic-import-export-business-logistics-background_35641-2693.jpg" class="img-fluid rounded-4 shadow" alt="">
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Call to Action -->
<section class="py-5">
<div class="container">
<div class="bg-primary text-white p-5 rounded-5 text-center shadow-lg">
<h2 class="fw-bold mb-3">{% trans "Ready to move your cargo?" %}</h2>
<p class="mb-4 opacity-75">{% trans "Join thousands of shippers and drivers on MASAR today." %}</p>
<a href="{% url 'register' %}" class="btn btn-light btn-lg px-5 rounded-pill fw-bold text-primary">{% trans "Join Now" %}</a>
</div>
</div>
</section>
{% endblock %}

View File

@ -0,0 +1,39 @@
{% extends "base.html" %}
{% load i18n %}
{% block content %}
<div class="container py-5">
<h2 class="mb-4">{% trans "Shipment Marketplace" %}</h2>
<div class="row">
{% for shipment in shipments %}
<div class="col-md-6 mb-4">
<div class="card shadow-sm h-100 border-0">
<div class="card-body">
<div class="d-flex justify-content-between mb-2">
<span class="badge bg-primary">{% trans "Open for Bids" %}</span>
<small class="text-muted">{{ shipment.created_at|timesince }} {% trans "ago" %}</small>
</div>
<h5 class="card-title">{{ shipment.origin }} <i class="fa-solid fa-arrow-right mx-2"></i> {{ shipment.destination }}</h5>
<p class="card-text text-muted">{{ shipment.description|truncatechars:100 }}</p>
<div class="d-flex gap-4 mb-3">
<div>
<small class="text-muted d-block">{% trans "Weight" %}</small>
<strong>{{ shipment.weight }}</strong>
</div>
<div>
<small class="text-muted d-block">{% trans "Delivery Date" %}</small>
<strong>{{ shipment.delivery_date }}</strong>
</div>
</div>
<a href="{% url 'place_bid' shipment.id %}" class="btn btn-outline-primary w-100">{% trans "Place an Offer" %}</a>
</div>
</div>
</div>
{% empty %}
<div class="col-12 text-center py-5">
<p class="lead text-muted">{% trans "No shipments available at the moment." %}</p>
</div>
{% endfor %}
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,51 @@
{% extends "base.html" %}
{% load i18n %}
{% block content %}
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card shadow">
<div class="card-body p-5">
<h2 class="mb-4">{% trans "Place an Offer" %}</h2>
<div class="alert alert-info mb-4">
<strong>{% trans "Shipment:" %}</strong> {{ shipment.origin }} to {{ shipment.destination }}<br>
<strong>{% trans "Goods:" %}</strong> {{ shipment.description }}
</div>
{% if trucks %}
<form method="post">
{% csrf_token %}
<div class="mb-3">
<label class="form-label">{% trans "Select Truck" %}</label>
<select name="truck" class="form-select" required>
{% for truck in trucks %}
<option value="{{ truck.id }}">{{ truck.truck_type }} - {{ truck.plate_no }} ({{ truck.load_capacity }})</option>
{% endfor %}
</select>
</div>
<div class="mb-3">
<label class="form-label">{% trans "Your Offer Amount" %}</label>
<div class="input-group">
<span class="input-group-text">$</span>
<input type="number" name="amount" class="form-control" step="0.01" required>
</div>
</div>
<div class="mb-3">
<label class="form-label">{% trans "Comments/Conditions" %}</label>
<textarea name="comments" class="form-control" rows="3"></textarea>
</div>
<button type="submit" class="btn btn-primary w-100 py-3">{% trans "Submit Offer" %}</button>
</form>
{% else %}
<div class="text-center py-4">
<p class="text-danger">{% trans "You must register a truck before placing a bid." %}</p>
<a href="{% url 'truck_register' %}" class="btn btn-success">{% trans "Register Truck Now" %}</a>
</div>
{% endif %}
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,42 @@
{% extends "base.html" %}
{% load i18n %}
{% block content %}
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card shadow">
<div class="card-body p-5">
<h2 class="mb-4">{% trans "Post a New Shipment" %}</h2>
<form method="post">
{% csrf_token %}
<div class="mb-3">
<label class="form-label">{% trans "Goods Description" %}</label>
<textarea name="description" class="form-control" rows="4" placeholder="{% trans 'What are you moving? (e.g. 500 boxes of food)' %}" required></textarea>
</div>
<div class="mb-3">
<label class="form-label">{% trans "Weight/Volume" %}</label>
<input type="text" name="weight" class="form-control" placeholder="e.g. 5 Tons" required>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label">{% trans "Origin" %}</label>
<input type="text" name="origin" class="form-control" placeholder="{% trans 'City, Country' %}" required>
</div>
<div class="col-md-6 mb-3">
<label class="form-label">{% trans "Destination" %}</label>
<input type="text" name="destination" class="form-control" placeholder="{% trans 'City, Country' %}" required>
</div>
</div>
<div class="mb-3">
<label class="form-label">{% trans "Requested Delivery Date" %}</label>
<input type="date" name="delivery_date" class="form-control" required>
</div>
<button type="submit" class="btn btn-primary w-100 py-3 mt-4">{% trans "Post Shipment" %}</button>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,101 @@
{% extends "base.html" %}
{% load i18n %}
{% block content %}
<div class="container py-5">
<div class="row">
<div class="col-md-8">
<div class="card shadow-sm mb-4">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center mb-3">
<h2 class="mb-0">{{ shipment.origin }} <i class="fa-solid fa-arrow-right mx-2"></i> {{ shipment.destination }}</h2>
<span class="badge {% if shipment.status == 'OPEN' %}bg-primary{% elif shipment.status == 'IN_PROGRESS' %}bg-warning{% else %}bg-success{% endif %} fs-6">
{{ shipment.get_status_display }}
</span>
</div>
<hr>
<h5>{% trans "Details" %}</h5>
<p>{{ shipment.description }}</p>
<div class="row">
<div class="col-6 mb-3">
<small class="text-muted d-block">{% trans "Weight" %}</small>
<strong>{{ shipment.weight }}</strong>
</div>
<div class="col-6 mb-3">
<small class="text-muted d-block">{% trans "Delivery Date" %}</small>
<strong>{{ shipment.delivery_date }}</strong>
</div>
</div>
</div>
</div>
{% if user == shipment.shipper and shipment.status == 'OPEN' %}
<div class="card shadow-sm">
<div class="card-header bg-white">
<h5 class="mb-0">{% trans "Received Bids" %}</h5>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover mb-0">
<thead>
<tr>
<th>{% trans "Truck Owner" %}</th>
<th>{% trans "Truck" %}</th>
<th>{% trans "Amount" %}</th>
<th>{% trans "Action" %}</th>
</tr>
</thead>
<tbody>
{% for bid in bids %}
<tr>
<td>{{ bid.truck_owner.username }}</td>
<td>{{ bid.truck.truck_type }}</td>
<td>${{ bid.amount }}</td>
<td>
<a href="{% url 'accept_bid' bid.id %}" class="btn btn-sm btn-success">{% trans "Accept" %}</a>
</td>
</tr>
{% empty %}
<tr>
<td colspan="4" class="text-center py-4 text-muted">{% trans "No bids received yet." %}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endif %}
{% if shipment.status == 'IN_PROGRESS' %}
<div class="alert alert-success d-flex align-items-center">
<i class="fa-solid fa-truck-moving fa-2x me-3"></i>
<div>
<strong>{% trans "Shipment in progress!" %}</strong><br>
{% trans "Assigned Truck:" %} {{ shipment.assigned_truck.truck_type }} ({{ shipment.assigned_truck.plate_no }})
</div>
</div>
<div class="mt-4">
<a href="https://wa.me/{{ shipment.assigned_truck.owner.profile.phone_number }}" class="btn btn-success btn-lg">
<i class="fa-brands fa-whatsapp me-2"></i> {% trans "Contact Driver on WhatsApp" %}
</a>
</div>
{% endif %}
</div>
<div class="col-md-4">
<div class="card shadow-sm">
<div class="card-body">
<h5>{% trans "Contact Information" %}</h5>
<p>
<strong>{% trans "Shipper:" %}</strong> {{ shipment.shipper.username }}<br>
{% if shipment.status == 'IN_PROGRESS' %}
<strong>{% trans "Phone:" %}</strong> {{ shipment.shipper.profile.phone_number }}
{% endif %}
</p>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,61 @@
{% extends "base.html" %}
{% load i18n %}
{% block content %}
<div class="container py-5">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2>{% trans "Shipper Dashboard" %}</h2>
<a href="{% url 'post_shipment' %}" class="btn btn-success">
<i class="fa-solid fa-plus me-2"></i> {% trans "Post New Shipment" %}
</a>
</div>
<div class="row">
<div class="col-md-12">
<div class="card shadow-sm">
<div class="card-header bg-white">
<h5 class="mb-0">{% trans "My Shipments" %}</h5>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover mb-0">
<thead class="table-light">
<tr>
<th>{% trans "Description" %}</th>
<th>{% trans "Route" %}</th>
<th>{% trans "Delivery Date" %}</th>
<th>{% trans "Status" %}</th>
<th>{% trans "Bids" %}</th>
<th>{% trans "Action" %}</th>
</tr>
</thead>
<tbody>
{% for shipment in shipments %}
<tr>
<td>{{ shipment.description|truncatechars:30 }}</td>
<td>{{ shipment.origin }} <i class="fa-solid fa-arrow-right mx-1"></i> {{ shipment.destination }}</td>
<td>{{ shipment.delivery_date }}</td>
<td>
<span class="badge {% if shipment.status == 'OPEN' %}bg-primary{% elif shipment.status == 'IN_PROGRESS' %}bg-warning{% else %}bg-success{% endif %}">
{{ shipment.get_status_display }}
</span>
</td>
<td>{{ shipment.bids.count }}</td>
<td>
<a href="{% url 'shipment_detail' shipment.id %}" class="btn btn-sm btn-outline-primary">{% trans "View Details" %}</a>
</td>
</tr>
{% empty %}
<tr>
<td colspan="6" class="text-center py-4">{% trans "No shipments posted yet." %}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,79 @@
{% extends "base.html" %}
{% load i18n %}
{% block content %}
<div class="container py-5">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2>{% trans "Truck Owner Dashboard" %}</h2>
<div>
<a href="{% url 'marketplace' %}" class="btn btn-primary me-2">
<i class="fa-solid fa-search me-2"></i> {% trans "Find Shipments" %}
</a>
<a href="{% url 'truck_register' %}" class="btn btn-success">
<i class="fa-solid fa-plus me-2"></i> {% trans "Register Truck" %}
</a>
</div>
</div>
<div class="row">
<div class="col-md-6 mb-4">
<div class="card shadow-sm h-100">
<div class="card-header bg-white">
<h5 class="mb-0">{% trans "My Trucks" %}</h5>
</div>
<div class="card-body">
{% if trucks %}
<ul class="list-group list-group-flush">
{% for truck in trucks %}
<li class="list-group-item d-flex justify-content-between align-items-center">
{{ truck.truck_type }} - {{ truck.plate_no }}
<span class="badge bg-secondary">{{ truck.load_capacity }}</span>
</li>
{% endfor %}
</ul>
{% else %}
<p class="text-center py-3">{% trans "No trucks registered." %}</p>
{% endif %}
</div>
</div>
</div>
<div class="col-md-6 mb-4">
<div class="card shadow-sm h-100">
<div class="card-header bg-white">
<h5 class="mb-0">{% trans "My Active Bids" %}</h5>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover mb-0">
<thead>
<tr>
<th>{% trans "Shipment" %}</th>
<th>{% trans "Amount" %}</th>
<th>{% trans "Status" %}</th>
</tr>
</thead>
<tbody>
{% for bid in bids %}
<tr>
<td>{{ bid.shipment.origin }} - {{ bid.shipment.destination }}</td>
<td>{{ bid.amount }}</td>
<td>
<span class="badge {% if bid.status == 'PENDING' %}bg-warning{% elif bid.status == 'ACCEPTED' %}bg-success{% else %}bg-danger{% endif %}">
{{ bid.get_status_display }}
</span>
</td>
</tr>
{% empty %}
<tr>
<td colspan="3" class="text-center py-3">{% trans "No bids placed." %}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,73 @@
{% extends "base.html" %}
{% load i18n %}
{% block content %}
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card shadow">
<div class="card-body p-5">
<h2 class="mb-4">{% trans "Register a Truck" %}</h2>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label">{% trans "Truck Type" %}</label>
<input type="text" name="truck_type" class="form-control" placeholder="e.g. Flatbed, Trailer" required>
</div>
<div class="col-md-6 mb-3">
<label class="form-label">{% trans "Model" %}</label>
<input type="text" name="model" class="form-control" required>
</div>
</div>
<div class="row">
<div class="col-md-4 mb-3">
<label class="form-label">{% trans "Year" %}</label>
<input type="number" name="year" class="form-control" required>
</div>
<div class="col-md-4 mb-3">
<label class="form-label">{% trans "Plate No" %}</label>
<input type="text" name="plate_no" class="form-control" required>
</div>
<div class="col-md-4 mb-3">
<label class="form-label">{% trans "Color" %}</label>
<input type="text" name="color" class="form-control" required>
</div>
</div>
<div class="mb-3">
<label class="form-label">{% trans "Load Capacity (e.g. 20 Tons)" %}</label>
<input type="text" name="load_capacity" class="form-control" required>
</div>
<hr class="my-4">
<h5>{% trans "Documents & Photos" %}</h5>
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label">{% trans "Truck Picture" %}</label>
<input type="file" name="truck_picture" class="form-control" accept="image/*">
</div>
<div class="col-md-6 mb-3">
<label class="form-label">{% trans "Driver License" %}</label>
<input type="file" name="driver_license" class="form-control" accept="image/*">
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label">{% trans "Registration (Front Face)" %}</label>
<input type="file" name="registration_front" class="form-control" accept="image/*">
</div>
<div class="col-md-6 mb-3">
<label class="form-label">{% trans "Registration (Back Face)" %}</label>
<input type="file" name="registration_back" class="form-control" accept="image/*">
</div>
</div>
<button type="submit" class="btn btn-primary w-100 py-3 mt-4">{% trans "Submit Registration" %}</button>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,33 @@
{% extends "base.html" %}
{% load i18n %}
{% block content %}
<section class="py-5">
<div class="container">
<div class="row justify-content-center">
<div class="col-md-5">
<div class="card shadow">
<div class="card-body p-5">
<h2 class="text-center mb-4">{% trans "Login" %}</h2>
<form method="post">
{% csrf_token %}
<div class="mb-3">
<label class="form-label">{% trans "Username" %}</label>
<input type="text" name="username" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label">{% trans "Password" %}</label>
<input type="password" name="password" class="form-control" required>
</div>
<button type="submit" class="btn btn-primary w-100 py-2">{% trans "Login" %}</button>
</form>
<div class="text-center mt-3">
<p>{% trans "Don't have an account?" %} <a href="{% url 'register' %}">{% trans "Register" %}</a></p>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
{% endblock %}

View File

@ -0,0 +1,40 @@
{% extends "base.html" %}
{% load i18n %}
{% block content %}
<section class="py-5">
<div class="container">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card shadow">
<div class="card-body p-5">
<h2 class="text-center mb-4">{% trans "Create your account" %}</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<div class="mb-3">
<label class="form-label">{% trans "I am a:" %}</label>
<select name="role" class="form-select" required>
<option value="SHIPPER">{% trans "Shipper (Need Goods Moved)" %}</option>
<option value="TRUCK_OWNER">{% trans "Truck Owner (Service Provider)" %}</option>
</select>
</div>
<div class="mb-3">
<label class="form-label">{% trans "Phone Number" %}</label>
<input type="text" name="phone_number" class="form-control" placeholder="+1234567890">
</div>
<button type="submit" class="btn btn-primary w-100 py-2">{% trans "Register" %}</button>
</form>
<div class="text-center mt-3">
<p>{% trans "Already have an account?" %} <a href="{% url 'login' %}">{% trans "Login" %}</a></p>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
{% endblock %}

View File

@ -1,7 +1,17 @@
from django.urls import path
from .views import home
from django.contrib.auth import views as auth_views
from . import views
urlpatterns = [
path("", home, name="home"),
]
path("", views.home, name="home"),
path("register/", views.register, name="register"),
path("login/", auth_views.LoginView.as_view(), name="login"),
path("logout/", auth_views.LogoutView.as_view(), name="logout"),
path("dashboard/", views.dashboard, name="dashboard"),
path("truck/register/", views.truck_register, name="truck_register"),
path("shipment/post/", views.post_shipment, name="post_shipment"),
path("marketplace/", views.marketplace, name="marketplace"),
path("shipment/<int:shipment_id>/", views.shipment_detail, name="shipment_detail"),
path("shipment/<int:shipment_id>/bid/", views.place_bid, name="place_bid"),
path("bid/<int:bid_id>/accept/", views.accept_bid, name="accept_bid"),
]

View File

@ -1,25 +1,172 @@
import os
import platform
from django import get_version as django_version
from django.shortcuts import render
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
from django.contrib.auth.forms import UserCreationForm
from django.utils import timezone
from .models import Profile, Truck, Shipment, Bid, Message
from django.contrib import messages
from django.utils.translation import gettext as _
from django.db.models import Q
def home(request):
"""Render the landing screen with loader and environment details."""
host_name = request.get_host().lower()
agent_brand = "AppWizzy" if host_name == "appwizzy.com" else "Flatlogic"
now = timezone.now()
"""Render the landing screen for MASAR CARGO."""
if request.user.is_authenticated:
return redirect('dashboard')
context = {
"project_name": "New Style",
"agent_brand": agent_brand,
"django_version": django_version(),
"python_version": platform.python_version(),
"current_time": now,
"host_name": host_name,
"project_description": os.getenv("PROJECT_DESCRIPTION", ""),
"project_image_url": os.getenv("PROJECT_IMAGE_URL", ""),
"deployment_timestamp": timezone.now().timestamp(),
}
return render(request, "core/index.html", context)
def register(request):
if request.method == 'POST':
form = UserCreationForm(request.POST)
role = request.POST.get('role')
phone = request.POST.get('phone_number')
if form.is_valid():
user = form.save()
profile = user.profile
profile.role = role
profile.phone_number = phone
profile.save()
login(request, user)
return redirect('dashboard')
else:
form = UserCreationForm()
return render(request, 'registration/register.html', {'form': form})
@login_required
def dashboard(request):
profile = request.user.profile
if profile.role == 'SHIPPER':
my_shipments = Shipment.objects.filter(shipper=request.user).order_by('-created_at')
return render(request, 'core/shipper_dashboard.html', {'shipments': my_shipments})
elif profile.role == 'TRUCK_OWNER':
my_trucks = Truck.objects.filter(owner=request.user)
my_bids = Bid.objects.filter(truck_owner=request.user).order_by('-created_at')
return render(request, 'core/truck_owner_dashboard.html', {
'trucks': my_trucks,
'bids': my_bids
})
else:
return redirect('/admin/')
@login_required
def truck_register(request):
if request.user.profile.role != 'TRUCK_OWNER':
return redirect('dashboard')
if request.method == 'POST':
truck_type = request.POST.get('truck_type')
model = request.POST.get('model')
year = request.POST.get('year')
plate_no = request.POST.get('plate_no')
load_capacity = request.POST.get('load_capacity')
color = request.POST.get('color')
truck = Truck.objects.create(
owner=request.user,
truck_type=truck_type,
model=model,
year=year,
plate_no=plate_no,
load_capacity=load_capacity,
color=color,
truck_picture=request.FILES.get('truck_picture'),
registration_front=request.FILES.get('registration_front'),
registration_back=request.FILES.get('registration_back'),
driver_license=request.FILES.get('driver_license')
)
messages.success(request, _("Truck registered successfully!"))
return redirect('dashboard')
return render(request, 'core/truck_register.html')
@login_required
def post_shipment(request):
if request.user.profile.role != 'SHIPPER':
return redirect('dashboard')
if request.method == 'POST':
description = request.POST.get('description')
weight = request.POST.get('weight')
origin = request.POST.get('origin')
destination = request.POST.get('destination')
delivery_date = request.POST.get('delivery_date')
Shipment.objects.create(
shipper=request.user,
description=description,
weight=weight,
origin=origin,
destination=destination,
delivery_date=delivery_date
)
messages.success(request, _("Shipment posted successfully!"))
return redirect('dashboard')
return render(request, 'core/post_shipment.html')
@login_required
def marketplace(request):
if request.user.profile.role != 'TRUCK_OWNER':
return redirect('dashboard')
shipments = Shipment.objects.filter(status='OPEN').order_by('-created_at')
return render(request, 'core/marketplace.html', {'shipments': shipments})
@login_required
def place_bid(request, shipment_id):
shipment = get_object_or_404(Shipment, id=shipment_id)
if request.user.profile.role != 'TRUCK_OWNER':
return redirect('dashboard')
my_trucks = Truck.objects.filter(owner=request.user)
if request.method == 'POST':
truck_id = request.POST.get('truck')
amount = request.POST.get('amount')
comments = request.POST.get('comments')
truck = get_object_or_404(Truck, id=truck_id, owner=request.user)
Bid.objects.create(
shipment=shipment,
truck_owner=request.user,
truck=truck,
amount=amount,
comments=comments
)
messages.success(request, _("Bid placed successfully!"))
return redirect('marketplace')
return render(request, 'core/place_bid.html', {'shipment': shipment, 'trucks': my_trucks})
@login_required
def shipment_detail(request, shipment_id):
shipment = get_object_or_404(Shipment, id=shipment_id)
# Security: check if user is shipper or a truck owner who bid
if shipment.shipper != request.user and not Bid.objects.filter(shipment=shipment, truck_owner=request.user).exists():
if request.user.profile.role != 'ADMIN':
return redirect('dashboard')
bids = shipment.bids.all()
return render(request, 'core/shipment_detail.html', {'shipment': shipment, 'bids': bids})
@login_required
def accept_bid(request, bid_id):
bid = get_object_or_404(Bid, id=bid_id)
if bid.shipment.shipper != request.user:
return redirect('dashboard')
# Accept this bid
bid.status = 'ACCEPTED'
bid.save()
# Reject others
bid.shipment.bids.exclude(id=bid_id).update(status='REJECTED')
# Update shipment
bid.shipment.status = 'IN_PROGRESS'
bid.shipment.assigned_truck = bid.truck
bid.shipment.save()
messages.success(request, _("Bid accepted! Shipment is now in progress."))
return redirect('shipment_detail', shipment_id=bid.shipment.id)

Binary file not shown.

View File

@ -0,0 +1,619 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-01-23 09:04+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: ar\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
"&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
#: config/settings.py:188
msgid "English"
msgstr "الإنجليزية"
#: config/settings.py:189
msgid "Arabic"
msgstr "العربية"
#: core/models.py:9 core/templates/registration/register.html:19
msgid "Shipper (Need Goods Moved)"
msgstr "شاحن (بحاجة لنقل بضائع)"
#: core/models.py:10 core/templates/registration/register.html:20
msgid "Truck Owner (Service Provider)"
msgstr "صاحب شاحنة (مزود خدمة)"
#: core/models.py:11
msgid "Administrator"
msgstr "مدير النظام"
#: core/models.py:22 core/templates/core/truck_register.html:15
msgid "Truck Type"
msgstr "نوع الشاحنة"
#: core/models.py:23 core/templates/core/truck_register.html:19
msgid "Model"
msgstr "الموديل"
#: core/models.py:24 core/templates/core/truck_register.html:25
msgid "Year"
msgstr "السنة"
#: core/models.py:25 core/templates/core/truck_register.html:29
msgid "Plate No"
msgstr "رقم اللوحة"
#: core/models.py:26
msgid "Load Capacity"
msgstr "حمولة الشاحنة"
#: core/models.py:27 core/templates/core/truck_register.html:33
msgid "Color"
msgstr "اللون"
#: core/models.py:30 core/templates/core/truck_register.html:47
msgid "Truck Picture"
msgstr "صورة الشاحنة"
#: core/models.py:31
msgid "Registration Front"
msgstr "التسجيل (الوجه الأمامي)"
#: core/models.py:32
#, fuzzy
#| msgid "Register Your Truck"
msgid "Registration Back"
msgstr "سجل شاحنتك"
#: core/models.py:33 core/templates/core/truck_register.html:51
msgid "Driver License"
msgstr "رخصة القيادة"
#: core/models.py:42 core/templates/core/marketplace.html:13
msgid "Open for Bids"
msgstr "مفتوح للعروض"
#: core/models.py:43
msgid "In Progress"
msgstr "قيد التنفيذ"
#: core/models.py:44
msgid "Completed"
msgstr "مكتمل"
#: core/models.py:45
msgid "Cancelled"
msgstr "ملغي"
#: core/models.py:48 core/templates/core/post_shipment.html:14
msgid "Goods Description"
msgstr "وصف البضائع"
#: core/models.py:49 core/templates/core/post_shipment.html:18
msgid "Weight/Volume"
msgstr "الوزن/الحجم"
#: core/models.py:50 core/templates/core/post_shipment.html:23
msgid "Origin"
msgstr "المصدر"
#: core/models.py:51 core/templates/core/post_shipment.html:27
msgid "Destination"
msgstr "الوجهة"
#: core/models.py:52 core/templates/core/post_shipment.html:32
msgid "Requested Delivery Date"
msgstr "تاريخ التسليم المطلوب"
#: core/models.py:64
msgid "Pending"
msgstr "قيد الانتظار"
#: core/models.py:65
msgid "Accepted"
msgstr "مقبول"
#: core/models.py:66
msgid "Rejected"
msgstr "مرفوض"
#: core/models.py:71
msgid "Offer Amount"
msgstr "قيمة العرض"
#: core/models.py:72
msgid "Comments"
msgstr "تعليقات"
#: core/templates/base.html:49
msgid "Dashboard"
msgstr "لوحة التحكم"
#: core/templates/base.html:53
msgid "Marketplace"
msgstr "السوق"
#: core/templates/base.html:91
msgid "Logout"
msgstr "تسجيل الخروج"
#: core/templates/base.html:98 core/templates/registration/login.html:11
#: core/templates/registration/login.html:22
#: core/templates/registration/register.html:32
msgid "Login"
msgstr "تسجيل الدخول"
#: core/templates/base.html:101
msgid "Get Started"
msgstr "ابدأ الآن"
#: core/templates/base.html:129
msgid "Empowering logistics with smart technology. Locally and abroad."
msgstr "تمكين الخدمات اللوجستية بتقنيات ذكية. محلياً ودولياً."
#: core/templates/base.html:132
msgid "Quick Links"
msgstr "روابط سريعة"
#: core/templates/base.html:134
msgid "Privacy Policy"
msgstr "سياسة الخصوصية"
#: core/templates/base.html:135
msgid "Terms of Service"
msgstr "شروط الخدمة"
#: core/templates/base.html:136
msgid "Contact Us"
msgstr "اتصل بنا"
#: core/templates/base.html:140
msgid "Contact"
msgstr "اتصال"
#: core/templates/core/index.html:11
msgid "Smart Cargo Solutions"
msgstr "حلول شحن ذكية"
#: core/templates/core/index.html:12
msgid "Locally & Abroad"
msgstr "محلياً ودولياً"
#: core/templates/core/index.html:15
msgid ""
"The most reliable platform connecting shippers with truck owners across the "
"region. Transparent, fast, and secure."
msgstr ""
"المنصة الأكثر موثوقية لربط الشاحنين مع أصحاب الشاحنات في جميع أنحاء المنطقة. "
"شفافة، سريعة، وآمنة."
#: core/templates/core/index.html:18
msgid "Start Shipping"
msgstr "ابدأ الشحن"
#: core/templates/core/index.html:19
msgid "Learn More"
msgstr "تعلم المزيد"
#: core/templates/core/index.html:33
msgid "How would you like to use MASAR?"
msgstr "كيف تود استخدام مسار؟"
#: core/templates/core/index.html:34
msgid "Choose your path to get started with our platform."
msgstr "اختر مسارك للبدء مع منصتنا."
#: core/templates/core/index.html:43
msgid "I am a Shipper"
msgstr "أنا شاحن"
#: core/templates/core/index.html:45
msgid ""
"I need to move goods locally or abroad. Post your shipment, receive offers "
"from verified drivers, and track your cargo in real-time."
msgstr ""
"أريد نقل بضائع محلياً أو دولياً. انشر شحنتك، واستقبل عروضاً من سائقين موثقين، "
"وتتبع شحنتك في الوقت الفعلي."
#: core/templates/core/index.html:48
msgid "Post shipments easily"
msgstr "انشر الشحنات بسهولة"
#: core/templates/core/index.html:49
msgid "Compare competitive bids"
msgstr "قارن العروض التنافسية"
#: core/templates/core/index.html:50
msgid "Real-time tracking"
msgstr "تتبع في الوقت الفعلي"
#: core/templates/core/index.html:52
msgid "Find a Truck"
msgstr "ابحث عن شاحنة"
#: core/templates/core/index.html:61
msgid "I am a Truck Owner"
msgstr "أنا صاحب شاحنة"
#: core/templates/core/index.html:63
msgid ""
"I have trucks and want to find cargo to transport. Register your fleet, bid "
"on available jobs, and grow your business."
msgstr ""
"لدي شاحنات وأريد العثور على بضائع لنقلها. سجل أسطولك، وقدم عروضك على الوظائف "
"المتاحة، ونمِ عملك."
#: core/templates/core/index.html:66
msgid "Access daily cargo leads"
msgstr "الوصول إلى فرص شحن يومية"
#: core/templates/core/index.html:67
msgid "Flexible bidding system"
msgstr "نظام عروض مرن"
#: core/templates/core/index.html:68
msgid "Direct chat with shippers"
msgstr "دردشة مباشرة مع الشاحنين"
#: core/templates/core/index.html:70
msgid "Register Your Truck"
msgstr "سجل شاحنتك"
#: core/templates/core/index.html:82
msgid "Everything you need for seamless logistics"
msgstr "كل ما تحتاجه للوجستيات سلسة"
#: core/templates/core/index.html:90
msgid "WhatsApp Integration"
msgstr "تكامل واتساب"
#: core/templates/core/index.html:91
msgid "Receive instant updates and communicate easily via WhatsApp API."
msgstr "استقبل تحديثات فورية وتواصل بسهولة عبر واجهة برمجة تطبيقات واتساب."
#: core/templates/core/index.html:101
msgid "Multilingual Support"
msgstr "دعم متعدد اللغات"
#: core/templates/core/index.html:102
msgid "Fully accessible in both Arabic and English for all users."
msgstr "متاح بالكامل باللغتين العربية والإنجليزية لجميع المستخدمين."
#: core/templates/core/index.html:112
msgid "Secure Documentation"
msgstr "توثيق آمن"
#: core/templates/core/index.html:113
msgid "Digital verification of truck registration and driver licenses."
msgstr "التحقق الرقمي من تسجيل الشاحنات ورخص القيادة."
#: core/templates/core/index.html:135
msgid "Ready to move your cargo?"
msgstr "هل أنت مستعد لنقل شحنتك؟"
#: core/templates/core/index.html:136
msgid "Join thousands of shippers and drivers on MASAR today."
msgstr "انضم إلى آلاف الشاحنين والسائقين على مسار اليوم."
#: core/templates/core/index.html:137
msgid "Join Now"
msgstr "انضم الآن"
#: core/templates/core/marketplace.html:6
msgid "Shipment Marketplace"
msgstr "سوق الشحنات"
#: core/templates/core/marketplace.html:14
msgid "ago"
msgstr "منذ"
#: core/templates/core/marketplace.html:20
#: core/templates/core/shipment_detail.html:21
msgid "Weight"
msgstr "الوزن"
#: core/templates/core/marketplace.html:24
#: core/templates/core/shipment_detail.html:25
#: core/templates/core/shipper_dashboard.html:26
msgid "Delivery Date"
msgstr "تاريخ التسليم"
#: core/templates/core/marketplace.html:28
#: core/templates/core/place_bid.html:10
msgid "Place an Offer"
msgstr "قدم عرضاً"
#: core/templates/core/marketplace.html:34
msgid "No shipments available at the moment."
msgstr "لا توجد شحنات متاحة حالياً."
#: core/templates/core/place_bid.html:12
msgid "Shipment:"
msgstr "الشحنة:"
#: core/templates/core/place_bid.html:13
msgid "Goods:"
msgstr "البضائع:"
#: core/templates/core/place_bid.html:20
msgid "Select Truck"
msgstr "اختر الشاحنة"
#: core/templates/core/place_bid.html:28
msgid "Your Offer Amount"
msgstr "مبلغ عرضك"
#: core/templates/core/place_bid.html:35
msgid "Comments/Conditions"
msgstr "التعليقات/الشروط"
#: core/templates/core/place_bid.html:38
msgid "Submit Offer"
msgstr "تقديم العرض"
#: core/templates/core/place_bid.html:42
msgid "You must register a truck before placing a bid."
msgstr "يجب عليك تسجيل شاحنة قبل تقديم عرض."
#: core/templates/core/place_bid.html:43
#, fuzzy
#| msgid "Register Your Truck"
msgid "Register Truck Now"
msgstr "سجل شاحنتك"
#: core/templates/core/post_shipment.html:10
#, fuzzy
#| msgid "Post shipments easily"
msgid "Post a New Shipment"
msgstr "انشر الشحنات بسهولة"
#: core/templates/core/post_shipment.html:15
msgid "What are you moving? (e.g. 500 boxes of food)"
msgstr "ماذا ستنقل؟ (مثال: 500 صندوق مواد غذائية)"
#: core/templates/core/post_shipment.html:24
#: core/templates/core/post_shipment.html:28
msgid "City, Country"
msgstr "المدينة، الدولة"
#: core/templates/core/post_shipment.html:35
#, fuzzy
#| msgid "Post shipments easily"
msgid "Post Shipment"
msgstr "انشر الشحنات بسهولة"
#: core/templates/core/shipment_detail.html:17
msgid "Details"
msgstr "التفاصيل"
#: core/templates/core/shipment_detail.html:35
msgid "Received Bids"
msgstr "العروض المستلمة"
#: core/templates/core/shipment_detail.html:42
#, fuzzy
#| msgid "I am a Truck Owner"
msgid "Truck Owner"
msgstr "أنا صاحب شاحنة"
#: core/templates/core/shipment_detail.html:43
msgid "Truck"
msgstr "الشاحنة"
#: core/templates/core/shipment_detail.html:44
#: core/templates/core/truck_owner_dashboard.html:51
msgid "Amount"
msgstr "المبلغ"
#: core/templates/core/shipment_detail.html:45
#: core/templates/core/shipper_dashboard.html:29
msgid "Action"
msgstr "الإجراء"
#: core/templates/core/shipment_detail.html:55
msgid "Accept"
msgstr "قبول"
#: core/templates/core/shipment_detail.html:60
msgid "No bids received yet."
msgstr "لم يتم استلام عروض بعد."
#: core/templates/core/shipment_detail.html:74
msgid "Shipment in progress!"
msgstr "الشحنة قيد التنفيذ!"
#: core/templates/core/shipment_detail.html:75
#, fuzzy
#| msgid "Find a Truck"
msgid "Assigned Truck:"
msgstr "ابحث عن شاحنة"
#: core/templates/core/shipment_detail.html:80
msgid "Contact Driver on WhatsApp"
msgstr "تواصل مع السائق عبر واتساب"
#: core/templates/core/shipment_detail.html:89
msgid "Contact Information"
msgstr "معلومات الاتصال"
#: core/templates/core/shipment_detail.html:91
#, fuzzy
#| msgid "I am a Shipper"
msgid "Shipper:"
msgstr "أنا شاحن"
#: core/templates/core/shipment_detail.html:93
msgid "Phone:"
msgstr "الهاتف:"
#: core/templates/core/shipper_dashboard.html:7
#, fuzzy
#| msgid "Dashboard"
msgid "Shipper Dashboard"
msgstr "لوحة التحكم"
#: core/templates/core/shipper_dashboard.html:9
#, fuzzy
#| msgid "Post shipments easily"
msgid "Post New Shipment"
msgstr "انشر الشحنات بسهولة"
#: core/templates/core/shipper_dashboard.html:17
msgid "My Shipments"
msgstr "شحناتي"
#: core/templates/core/shipper_dashboard.html:24
msgid "Description"
msgstr "الوصف"
#: core/templates/core/shipper_dashboard.html:25
msgid "Route"
msgstr "المسار"
#: core/templates/core/shipper_dashboard.html:27
#: core/templates/core/truck_owner_dashboard.html:52
msgid "Status"
msgstr "الحالة"
#: core/templates/core/shipper_dashboard.html:28
msgid "Bids"
msgstr "العروض"
#: core/templates/core/shipper_dashboard.html:45
msgid "View Details"
msgstr "عرض التفاصيل"
#: core/templates/core/shipper_dashboard.html:50
#, fuzzy
#| msgid "Post shipments easily"
msgid "No shipments posted yet."
msgstr "انشر الشحنات بسهولة"
#: core/templates/core/truck_owner_dashboard.html:7
#, fuzzy
#| msgid "Dashboard"
msgid "Truck Owner Dashboard"
msgstr "لوحة التحكم"
#: core/templates/core/truck_owner_dashboard.html:10
msgid "Find Shipments"
msgstr "ابحث عن شحنات"
#: core/templates/core/truck_owner_dashboard.html:13
#, fuzzy
#| msgid "Register Your Truck"
msgid "Register Truck"
msgstr "سجل شاحنتك"
#: core/templates/core/truck_owner_dashboard.html:22
msgid "My Trucks"
msgstr "شاحناتي"
#: core/templates/core/truck_owner_dashboard.html:35
msgid "No trucks registered."
msgstr "لا توجد شاحنات مسجلة."
#: core/templates/core/truck_owner_dashboard.html:43
msgid "My Active Bids"
msgstr "عروضي النشطة"
#: core/templates/core/truck_owner_dashboard.html:50
msgid "Shipment"
msgstr "الشحنة"
#: core/templates/core/truck_owner_dashboard.html:68
msgid "No bids placed."
msgstr "لا توجد عروض مقدمة."
#: core/templates/core/truck_register.html:10
#, fuzzy
#| msgid "Register Your Truck"
msgid "Register a Truck"
msgstr "سجل شاحنتك"
#: core/templates/core/truck_register.html:38
msgid "Load Capacity (e.g. 20 Tons)"
msgstr "الحمولة (مثال: 20 طن)"
#: core/templates/core/truck_register.html:43
msgid "Documents & Photos"
msgstr "المستندات والصور"
#: core/templates/core/truck_register.html:57
msgid "Registration (Front Face)"
msgstr "التسجيل (الوجه الأمامي)"
#: core/templates/core/truck_register.html:61
msgid "Registration (Back Face)"
msgstr "التسجيل (الوجه الخلفي)"
#: core/templates/core/truck_register.html:66
msgid "Submit Registration"
msgstr "إرسال التسجيل"
#: core/templates/registration/login.html:15
msgid "Username"
msgstr "اسم المستخدم"
#: core/templates/registration/login.html:19
msgid "Password"
msgstr "كلمة المرور"
#: core/templates/registration/login.html:25
msgid "Don't have an account?"
msgstr "ليس لديك حساب؟"
#: core/templates/registration/login.html:25
#: core/templates/registration/register.html:29
msgid "Register"
msgstr "تسجيل"
#: core/templates/registration/register.html:11
msgid "Create your account"
msgstr "أنشئ حسابك"
#: core/templates/registration/register.html:17
msgid "I am a:"
msgstr "أنا:"
#: core/templates/registration/register.html:25
msgid "Phone Number"
msgstr "رقم الهاتف"
#: core/templates/registration/register.html:32
msgid "Already have an account?"
msgstr "لديك حساب بالفعل؟"
#: core/views.py:79
msgid "Truck registered successfully!"
msgstr "تم تسجيل الشاحنة بنجاح!"
#: core/views.py:104
msgid "Shipment posted successfully!"
msgstr "تم نشر الشحنة بنجاح!"
#: core/views.py:137
msgid "Bid placed successfully!"
msgstr "تم تقديم العرض بنجاح!"
#: core/views.py:171
msgid "Bid accepted! Shipment is now in progress."
msgstr "تم قبول العرض! الشحنة قيد التنفيذ الآن."
#~ msgid "Features"
#~ msgstr "المميزات"
#~ msgid "How it Works"
#~ msgstr "كيف يعمل"

BIN
media/trucks/red_truk.jfif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -1,4 +1,131 @@
/* Custom styles for the application */
body {
font-family: system-ui, -apple-system, sans-serif;
@import url('https://fonts.googleapis.com/css2?family=Cairo:wght@400;700&family=Outfit:wght@400;600;700&display=swap');
:root {
--primary-color: #0A1D37;
--secondary-color: #2196F3;
--accent-color: #00BCD4;
--bg-light: #F4F7F6;
--white: #FFFFFF;
--text-dark: #333333;
--text-muted: #666666;
}
body {
font-family: 'Outfit', 'Cairo', sans-serif;
background-color: var(--bg-light);
color: var(--text-dark);
margin: 0;
overflow-x: hidden;
}
[lang="ar"] body {
direction: rtl;
text-align: right;
}
.navbar {
background-color: var(--white);
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
padding: 1rem 2rem;
}
.navbar-brand {
font-weight: 700;
font-size: 1.5rem;
color: var(--primary-color) !important;
}
.nav-link {
color: var(--primary-color) !important;
font-weight: 600;
margin: 0 10px;
}
.btn-primary {
background-color: var(--secondary-color);
border: none;
padding: 10px 25px;
border-radius: 50px;
font-weight: 600;
transition: all 0.3s ease;
}
.btn-primary:hover {
background-color: var(--primary-color);
transform: translateY(-2px);
box-shadow: 0 4px 15px rgba(33, 150, 243, 0.3);
}
.btn-outline-primary {
border: 2px solid var(--secondary-color);
color: var(--secondary-color);
padding: 10px 25px;
border-radius: 50px;
font-weight: 600;
}
.hero-section {
padding: 100px 0;
background: linear-gradient(135deg, var(--white) 0%, #E3F2FD 100%);
position: relative;
overflow: hidden;
}
.hero-title {
font-size: 3.5rem;
font-weight: 700;
color: var(--primary-color);
margin-bottom: 20px;
line-height: 1.2;
}
.hero-subtitle {
font-size: 1.25rem;
color: var(--text-muted);
margin-bottom: 40px;
}
.role-card {
background: var(--white);
padding: 40px;
border-radius: 20px;
box-shadow: 0 10px 30px rgba(0,0,0,0.05);
transition: all 0.3s ease;
border: 1px solid transparent;
height: 100%;
cursor: pointer;
}
.role-card:hover {
border-color: var(--secondary-color);
transform: translateY(-10px);
}
.role-icon {
font-size: 3rem;
color: var(--secondary-color);
margin-bottom: 20px;
}
.role-title {
font-size: 1.5rem;
font-weight: 700;
color: var(--primary-color);
}
.role-desc {
color: var(--text-muted);
margin-bottom: 25px;
}
footer {
background-color: var(--primary-color);
color: var(--white);
padding: 50px 0;
}
/* RTL Adjustments */
[lang="ar"] .ms-auto {
margin-right: auto !important;
margin-left: 0 !important;
}

View File

@ -1,21 +1,131 @@
@import url('https://fonts.googleapis.com/css2?family=Cairo:wght@400;700&family=Outfit:wght@400;600;700&display=swap');
:root {
--bg-color-start: #6a11cb;
--bg-color-end: #2575fc;
--text-color: #ffffff;
--card-bg-color: rgba(255, 255, 255, 0.01);
--card-border-color: rgba(255, 255, 255, 0.1);
--primary-color: #0A1D37;
--secondary-color: #2196F3;
--accent-color: #00BCD4;
--bg-light: #F4F7F6;
--white: #FFFFFF;
--text-dark: #333333;
--text-muted: #666666;
}
body {
font-family: 'Outfit', 'Cairo', sans-serif;
background-color: var(--bg-light);
color: var(--text-dark);
margin: 0;
font-family: 'Inter', sans-serif;
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
color: var(--text-color);
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
text-align: center;
overflow: hidden;
position: relative;
overflow-x: hidden;
}
[lang="ar"] body {
direction: rtl;
text-align: right;
}
.navbar {
background-color: var(--white);
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
padding: 1rem 2rem;
}
.navbar-brand {
font-weight: 700;
font-size: 1.5rem;
color: var(--primary-color) !important;
}
.nav-link {
color: var(--primary-color) !important;
font-weight: 600;
margin: 0 10px;
}
.btn-primary {
background-color: var(--secondary-color);
border: none;
padding: 10px 25px;
border-radius: 50px;
font-weight: 600;
transition: all 0.3s ease;
}
.btn-primary:hover {
background-color: var(--primary-color);
transform: translateY(-2px);
box-shadow: 0 4px 15px rgba(33, 150, 243, 0.3);
}
.btn-outline-primary {
border: 2px solid var(--secondary-color);
color: var(--secondary-color);
padding: 10px 25px;
border-radius: 50px;
font-weight: 600;
}
.hero-section {
padding: 100px 0;
background: linear-gradient(135deg, var(--white) 0%, #E3F2FD 100%);
position: relative;
overflow: hidden;
}
.hero-title {
font-size: 3.5rem;
font-weight: 700;
color: var(--primary-color);
margin-bottom: 20px;
line-height: 1.2;
}
.hero-subtitle {
font-size: 1.25rem;
color: var(--text-muted);
margin-bottom: 40px;
}
.role-card {
background: var(--white);
padding: 40px;
border-radius: 20px;
box-shadow: 0 10px 30px rgba(0,0,0,0.05);
transition: all 0.3s ease;
border: 1px solid transparent;
height: 100%;
cursor: pointer;
}
.role-card:hover {
border-color: var(--secondary-color);
transform: translateY(-10px);
}
.role-icon {
font-size: 3rem;
color: var(--secondary-color);
margin-bottom: 20px;
}
.role-title {
font-size: 1.5rem;
font-weight: 700;
color: var(--primary-color);
}
.role-desc {
color: var(--text-muted);
margin-bottom: 25px;
}
footer {
background-color: var(--primary-color);
color: var(--white);
padding: 50px 0;
}
/* RTL Adjustments */
[lang="ar"] .ms-auto {
margin-right: auto !important;
margin-left: 0 !important;
}