diff --git a/config/__pycache__/settings.cpython-311.pyc b/config/__pycache__/settings.cpython-311.pyc index 96bce55..625a9a3 100644 Binary files a/config/__pycache__/settings.cpython-311.pyc and b/config/__pycache__/settings.cpython-311.pyc differ diff --git a/config/__pycache__/urls.cpython-311.pyc b/config/__pycache__/urls.cpython-311.pyc index 0b85e94..b44c4bc 100644 Binary files a/config/__pycache__/urls.cpython-311.pyc and b/config/__pycache__/urls.cpython-311.pyc differ diff --git a/config/settings.py b/config/settings.py index 291d043..fbbd525 100644 --- a/config/settings.py +++ b/config/settings.py @@ -61,6 +61,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', @@ -134,6 +135,14 @@ AUTH_PASSWORD_VALIDATORS = [ # https://docs.djangoproject.com/en/5.2/topics/i18n/ LANGUAGE_CODE = 'en-us' +LANGUAGES = [ + ('en', 'English'), + ('ar', 'Arabic'), +] + +LOCALE_PATHS = [ + BASE_DIR / 'locale', +] TIME_ZONE = 'UTC' diff --git a/config/urls.py b/config/urls.py index bcfc074..4d288c5 100644 --- a/config/urls.py +++ b/config/urls.py @@ -1,29 +1,19 @@ -""" -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.urls import path, include from django.conf import settings from django.conf.urls.static import static +from django.conf.urls.i18n import i18n_patterns urlpatterns = [ - path("admin/", admin.site.urls), - path("", include("core.urls")), + path('i18n/', include('django.conf.urls.i18n')), ] +urlpatterns += i18n_patterns( + path('admin/', admin.site.urls), + path('', include('core.urls')), + prefix_default_language=False +) + if settings.DEBUG: - urlpatterns += static("/assets/", document_root=settings.BASE_DIR / "assets") urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) + urlpatterns += static("/assets/", document_root=settings.BASE_DIR / "assets") \ No newline at end of file diff --git a/core/__pycache__/admin.cpython-311.pyc b/core/__pycache__/admin.cpython-311.pyc index a5ed392..d1dabe0 100644 Binary files a/core/__pycache__/admin.cpython-311.pyc and b/core/__pycache__/admin.cpython-311.pyc differ diff --git a/core/__pycache__/forms.cpython-311.pyc b/core/__pycache__/forms.cpython-311.pyc new file mode 100644 index 0000000..e8430d1 Binary files /dev/null and b/core/__pycache__/forms.cpython-311.pyc differ diff --git a/core/__pycache__/models.cpython-311.pyc b/core/__pycache__/models.cpython-311.pyc index e061640..158b311 100644 Binary files a/core/__pycache__/models.cpython-311.pyc and b/core/__pycache__/models.cpython-311.pyc differ diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc index 5a69659..4e4db3b 100644 Binary files a/core/__pycache__/urls.cpython-311.pyc and b/core/__pycache__/urls.cpython-311.pyc differ diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index 2a36fd6..eaa4220 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 8c38f3f..0dbb9bb 100644 --- a/core/admin.py +++ b/core/admin.py @@ -1,3 +1,15 @@ from django.contrib import admin +from .models import Profile, Parcel -# 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(Parcel) +class ParcelAdmin(admin.ModelAdmin): + list_display = ('tracking_number', 'shipper', 'carrier', 'status', 'created_at') + list_filter = ('status', 'created_at') + search_fields = ('tracking_number', 'receiver_name', 'receiver_phone') + readonly_fields = ('tracking_number',) \ No newline at end of file diff --git a/core/forms.py b/core/forms.py new file mode 100644 index 0000000..278dc97 --- /dev/null +++ b/core/forms.py @@ -0,0 +1,39 @@ +from django import forms +from django.contrib.auth.models import User +from django.utils.translation import gettext_lazy as _ +from .models import Profile + +class UserRegistrationForm(forms.ModelForm): + password = forms.CharField(widget=forms.PasswordInput, label=_("Password")) + password_confirm = forms.CharField(widget=forms.PasswordInput, label=_("Confirm Password")) + role = forms.ChoiceField(choices=Profile.ROLE_CHOICES, label=_("Register as")) + phone_number = forms.CharField(max_length=20, label=_("Phone Number")) + + class Meta: + model = User + fields = ['username', 'email', 'first_name', 'last_name'] + labels = { + 'username': _('Username'), + 'email': _('Email'), + 'first_name': _('First Name'), + 'last_name': _('Last Name'), + } + + def clean_password_confirm(self): + password = self.cleaned_data.get('password') + password_confirm = self.cleaned_data.get('password_confirm') + if password and password_confirm and password != password_confirm: + raise forms.ValidationError(_("Passwords don't match")) + return password_confirm + + def save(self, commit=True): + user = super().save(commit=False) + user.set_password(self.cleaned_data['password']) + if commit: + user.save() + Profile.objects.create( + user=user, + role=self.cleaned_data['role'], + phone_number=self.cleaned_data['phone_number'] + ) + return user \ No newline at end of file diff --git a/core/migrations/0001_initial.py b/core/migrations/0001_initial.py new file mode 100644 index 0000000..9d8caa2 --- /dev/null +++ b/core/migrations/0001_initial.py @@ -0,0 +1,44 @@ +# Generated by Django 5.2.7 on 2026-01-25 07:04 + +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='Parcel', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('tracking_number', models.CharField(blank=True, max_length=20, unique=True)), + ('description', models.TextField()), + ('weight', models.DecimalField(decimal_places=2, help_text='Weight in kg', max_digits=5)), + ('pickup_address', models.CharField(max_length=255)), + ('delivery_address', models.CharField(max_length=255)), + ('receiver_name', models.CharField(max_length=100)), + ('receiver_phone', models.CharField(max_length=20)), + ('status', models.CharField(choices=[('pending', 'Pending Pickup'), ('picked_up', 'Picked Up'), ('in_transit', 'In Transit'), ('delivered', 'Delivered'), ('cancelled', 'Cancelled')], default='pending', max_length=20)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('carrier', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='carried_parcels', to=settings.AUTH_USER_MODEL)), + ('shipper', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sent_parcels', to=settings.AUTH_USER_MODEL)), + ], + ), + 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'), ('car_owner', 'Car Owner')], 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)), + ], + ), + ] diff --git a/core/migrations/0002_alter_parcel_options_alter_profile_options_and_more.py b/core/migrations/0002_alter_parcel_options_alter_profile_options_and_more.py new file mode 100644 index 0000000..ff9a151 --- /dev/null +++ b/core/migrations/0002_alter_parcel_options_alter_profile_options_and_more.py @@ -0,0 +1,99 @@ +# Generated by Django 5.2.7 on 2026-01-25 07:14 + +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.AlterModelOptions( + name='parcel', + options={'verbose_name': 'Parcel', 'verbose_name_plural': 'Parcels'}, + ), + migrations.AlterModelOptions( + name='profile', + options={'verbose_name': 'Profile', 'verbose_name_plural': 'Profiles'}, + ), + migrations.AlterField( + model_name='parcel', + name='carrier', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='carried_parcels', to=settings.AUTH_USER_MODEL, verbose_name='Carrier'), + ), + migrations.AlterField( + model_name='parcel', + name='created_at', + field=models.DateTimeField(auto_now_add=True, verbose_name='Created At'), + ), + migrations.AlterField( + model_name='parcel', + name='delivery_address', + field=models.CharField(max_length=255, verbose_name='Delivery Address'), + ), + migrations.AlterField( + model_name='parcel', + name='description', + field=models.TextField(verbose_name='Description'), + ), + migrations.AlterField( + model_name='parcel', + name='pickup_address', + field=models.CharField(max_length=255, verbose_name='Pickup Address'), + ), + migrations.AlterField( + model_name='parcel', + name='receiver_name', + field=models.CharField(max_length=100, verbose_name='Receiver Name'), + ), + migrations.AlterField( + model_name='parcel', + name='receiver_phone', + field=models.CharField(max_length=20, verbose_name='Receiver Phone'), + ), + migrations.AlterField( + model_name='parcel', + name='shipper', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sent_parcels', to=settings.AUTH_USER_MODEL, verbose_name='Shipper'), + ), + migrations.AlterField( + model_name='parcel', + name='status', + field=models.CharField(choices=[('pending', 'Pending Pickup'), ('picked_up', 'Picked Up'), ('in_transit', 'In Transit'), ('delivered', 'Delivered'), ('cancelled', 'Cancelled')], default='pending', max_length=20, verbose_name='Status'), + ), + migrations.AlterField( + model_name='parcel', + name='tracking_number', + field=models.CharField(blank=True, max_length=20, unique=True, verbose_name='Tracking Number'), + ), + migrations.AlterField( + model_name='parcel', + name='updated_at', + field=models.DateTimeField(auto_now=True, verbose_name='Updated At'), + ), + migrations.AlterField( + model_name='parcel', + name='weight', + field=models.DecimalField(decimal_places=2, help_text='Weight in kg', max_digits=5, verbose_name='Weight (kg)'), + ), + migrations.AlterField( + model_name='profile', + name='phone_number', + field=models.CharField(blank=True, max_length=20, verbose_name='Phone Number'), + ), + migrations.AlterField( + model_name='profile', + name='role', + field=models.CharField(choices=[('shipper', 'Shipper'), ('car_owner', 'Car Owner')], default='shipper', max_length=20, verbose_name='Role'), + ), + migrations.AlterField( + model_name='profile', + name='user', + field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='User'), + ), + ] diff --git a/core/migrations/__pycache__/0001_initial.cpython-311.pyc b/core/migrations/__pycache__/0001_initial.cpython-311.pyc new file mode 100644 index 0000000..d3a915f Binary files /dev/null and b/core/migrations/__pycache__/0001_initial.cpython-311.pyc differ diff --git a/core/migrations/__pycache__/0002_alter_parcel_options_alter_profile_options_and_more.cpython-311.pyc b/core/migrations/__pycache__/0002_alter_parcel_options_alter_profile_options_and_more.cpython-311.pyc new file mode 100644 index 0000000..3fb3a9a Binary files /dev/null and b/core/migrations/__pycache__/0002_alter_parcel_options_alter_profile_options_and_more.cpython-311.pyc differ diff --git a/core/models.py b/core/models.py index 71a8362..4d7b7fe 100644 --- a/core/models.py +++ b/core/models.py @@ -1,3 +1,58 @@ from django.db import models +from django.contrib.auth.models import User +from django.utils.translation import gettext_lazy as _ +import uuid -# Create your models here. +class Profile(models.Model): + ROLE_CHOICES = ( + ('shipper', _('Shipper')), + ('car_owner', _('Car Owner')), + ) + user = models.OneToOneField(User, on_delete=models.CASCADE, verbose_name=_('User')) + role = models.CharField(_('Role'), max_length=20, choices=ROLE_CHOICES, default='shipper') + phone_number = models.CharField(_('Phone Number'), max_length=20, blank=True) + + def __str__(self): + return f"{self.user.username} - {self.get_role_display()}" + + class Meta: + verbose_name = _('Profile') + verbose_name_plural = _('Profiles') + +class Parcel(models.Model): + STATUS_CHOICES = ( + ('pending', _('Pending Pickup')), + ('picked_up', _('Picked Up')), + ('in_transit', _('In Transit')), + ('delivered', _('Delivered')), + ('cancelled', _('Cancelled')), + ) + + tracking_number = models.CharField(_('Tracking Number'), max_length=20, unique=True, blank=True) + shipper = models.ForeignKey(User, on_delete=models.CASCADE, related_name='sent_parcels', verbose_name=_('Shipper')) + carrier = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='carried_parcels', verbose_name=_('Carrier')) + + description = models.TextField(_('Description')) + weight = models.DecimalField(_('Weight (kg)'), max_digits=5, decimal_places=2, help_text=_("Weight in kg")) + + pickup_address = models.CharField(_('Pickup Address'), max_length=255) + delivery_address = models.CharField(_('Delivery Address'), max_length=255) + + receiver_name = models.CharField(_('Receiver Name'), max_length=100) + receiver_phone = models.CharField(_('Receiver Phone'), max_length=20) + + status = models.CharField(_('Status'), max_length=20, choices=STATUS_CHOICES, default='pending') + created_at = models.DateTimeField(_('Created At'), auto_now_add=True) + updated_at = models.DateTimeField(_('Updated At'), auto_now=True) + + def save(self, *args, **kwargs): + if not self.tracking_number: + self.tracking_number = str(uuid.uuid4().hex[:10]).upper() + super().save(*args, **kwargs) + + def __str__(self): + return f"Parcel {self.tracking_number} - {self.status}" + + class Meta: + verbose_name = _('Parcel') + verbose_name_plural = _('Parcels') \ No newline at end of file diff --git a/core/templates/base.html b/core/templates/base.html index 1e7e5fb..6fef6cc 100644 --- a/core/templates/base.html +++ b/core/templates/base.html @@ -1,25 +1,121 @@ +{% load i18n static %} +{% get_current_language as LANGUAGE_CODE %} +{% get_language_info for LANGUAGE_CODE as lang %} - - + - - {% block title %}Knowledge Base{% endblock %} - {% if project_description %} - - - - {% endif %} - {% if project_image_url %} - - - {% endif %} - {% load static %} - - {% block head %}{% endblock %} + + + {% block title %}masarX | {% trans "Small Shipments, Smart Delivery" %}{% endblock %} + + {% if project_description %} + + + + {% endif %} + {% if project_image_url %} + + + {% endif %} + + + + + + + + + + {% if lang.direction == 'rtl' %} + + {% endif %} + + {% block head %}{% endblock %} - - {% block content %}{% endblock %} - + + + +
+ {% block content %}{% endblock %} +
+ + + + + + diff --git a/core/templates/core/index.html b/core/templates/core/index.html index faec813..a82bcf4 100644 --- a/core/templates/core/index.html +++ b/core/templates/core/index.html @@ -1,145 +1,105 @@ -{% extends "base.html" %} - -{% block title %}{{ project_name }}{% endblock %} - -{% block head %} - - - - -{% endblock %} +{% extends 'base.html' %} +{% load static i18n %} {% block content %} -
-
-

Analyzing your requirements and generating your app…

-
- Loading… + +
+
+
+
+

{% trans "Small Shipments," %}
{% trans "Smart Delivery." %}

+

{% trans "masarX connects shippers with local car owners for fast, reliable, and trackable deliveries. Your cargo, our priority." %}

+ +
+
+
+

{% trans "Track your Parcel" %}

+
+
+ + +
+
+ + {% if parcel %} +
+
+ {% trans "Status" %} + {{ parcel.get_status_display }} +
+
{{ parcel.description|truncatechars:30 }}
+

{% trans "From" %}: {{ parcel.pickup_address }}

+

{% trans "To" %}: {{ parcel.delivery_address }}

+
+ {% elif error %} +
+ {{ error }} +
+ {% else %} +

{% trans "Enter your 10-character tracking ID to see live updates." %}

+ {% endif %} +
+
+
-

AppWizzy AI is collecting your requirements and applying the first changes.

-

This page will refresh automatically as the plan is implemented.

-

- Runtime: Django {{ django_version }} · Python {{ python_version }} - — UTC {{ current_time|date:"Y-m-d H:i:s" }} -

-
-
- + + + +
+
+
+

{% trans "How masarX Works" %}

+

{% trans "Simple steps to get your shipment moving" %}

+
+
+
+
+
+ +
+

1. {% trans "List your Parcel" %}

+

{% trans "Enter shipment details, weight, and delivery addresses. It's quick and easy." %}

+
+
+
+
+
+ +
+

2. {% trans "Connect with Driver" %}

+

{% trans "A verified car owner near you picks up the parcel and starts the journey." %}

+
+
+
+
+
+ +
+

3. {% trans "Secure Delivery" %}

+

{% trans "Track your parcel in real-time until it reaches its destination safely." %}

+
+
+
+
+
+ + +
+
+

{% trans "Ready to join the movement?" %}

+
+
+

{% trans "I want to send a parcel" %}

+ {% trans "Become a Shipper" %} +
+
+

{% trans "I have a car and want to earn" %}

+ {% trans "Become a Driver" %} +
+
+
+
{% endblock %} \ No newline at end of file diff --git a/core/templates/core/login.html b/core/templates/core/login.html new file mode 100644 index 0000000..0d181ef --- /dev/null +++ b/core/templates/core/login.html @@ -0,0 +1,50 @@ +{% extends 'base.html' %} +{% load i18n %} + +{% block title %}{% trans "Login" %} | masarX{% endblock %} + +{% block content %} +
+
+
+
+
+
+

{% trans "Login to masarX" %}

+
+ {% csrf_token %} + {% for field in form %} +
+ + {{ field }} + {% if field.errors %} +
{{ field.errors }}
+ {% endif %} +
+ {% endfor %} + +
+
+

{% trans "Don't have an account?" %} {% trans "Register here" %}

+
+
+
+
+
+
+
+ + +{% endblock %} diff --git a/core/templates/core/register.html b/core/templates/core/register.html new file mode 100644 index 0000000..2bdddbf --- /dev/null +++ b/core/templates/core/register.html @@ -0,0 +1,64 @@ +{% extends 'base.html' %} +{% load i18n %} + +{% block title %}{% trans "Register" %} | masarX{% endblock %} + +{% block content %} +
+
+
+
+
+
+

{% trans "Join masarX" %}

+
+ {% csrf_token %} + {% for field in form %} +
+ + {{ field }} + {% if field.help_text %} +
{{ field.help_text }}
+ {% endif %} + {% if field.errors %} +
{{ field.errors }}
+ {% endif %} +
+ {% endfor %} + +
+
+

{% trans "Already have an account?" %} {% trans "Login here" %}

+
+
+
+
+
+
+
+ + +{% endblock %} diff --git a/core/templates/core/shipment_request.html b/core/templates/core/shipment_request.html new file mode 100644 index 0000000..de179ad --- /dev/null +++ b/core/templates/core/shipment_request.html @@ -0,0 +1,42 @@ +{% extends 'base.html' %} +{% load static %} + +{% block content %} +
+
+
+
+

Request a Shipment

+
+ {% csrf_token %} +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+
+
+
+
+
+{% endblock %} diff --git a/core/urls.py b/core/urls.py index 6299e3d..ddda4d3 100644 --- a/core/urls.py +++ b/core/urls.py @@ -1,7 +1,12 @@ 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.index, name='index'), + path('register/', views.register, name='register'), + path('login/', auth_views.LoginView.as_view(template_name='core/login.html'), name='login'), + path('logout/', auth_views.LogoutView.as_view(next_page='index'), name='logout'), + path('shipment-request/', views.shipment_request, name='shipment_request'), + path('article-detail/', views.article_detail, name='article_detail'), ] diff --git a/core/views.py b/core/views.py index c9aed12..f9e0421 100644 --- a/core/views.py +++ b/core/views.py @@ -1,25 +1,44 @@ -import os -import platform +from django.shortcuts import render, redirect +from django.contrib.auth import login, authenticate +from django.contrib.auth.forms import AuthenticationForm +from django.contrib.auth.decorators import login_required +from .models import Parcel, Profile +from .forms import UserRegistrationForm +from django.utils.translation import gettext_lazy as _ -from django import get_version as django_version -from django.shortcuts import render -from django.utils import timezone +def index(request): + tracking_id = request.GET.get('tracking_id') + parcel = None + error = None + if tracking_id: + try: + parcel = Parcel.objects.get(tracking_number=tracking_id) + except Parcel.DoesNotExist: + error = _("Parcel not found.") + + return render(request, 'core/index.html', { + 'parcel': parcel, + 'error': error, + 'tracking_id': tracking_id + }) +def register(request): + if request.method == 'POST': + form = UserRegistrationForm(request.POST) + if form.is_valid(): + user = form.save() + login(request, user) + return redirect('index') + else: + form = UserRegistrationForm() + return render(request, 'core/register.html', {'form': form}) -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() +@login_required +def shipment_request(request): + if request.method == 'POST': + # Logic for creating shipment will go here + pass + return render(request, 'core/shipment_request.html') - 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", ""), - } - return render(request, "core/index.html", context) +def article_detail(request): + return render(request, 'core/article_detail.html') diff --git a/locale/ar/LC_MESSAGES/django.mo b/locale/ar/LC_MESSAGES/django.mo new file mode 100644 index 0000000..d09703c Binary files /dev/null and b/locale/ar/LC_MESSAGES/django.mo differ diff --git a/locale/ar/LC_MESSAGES/django.po b/locale/ar/LC_MESSAGES/django.po new file mode 100644 index 0000000..b844de2 --- /dev/null +++ b/locale/ar/LC_MESSAGES/django.po @@ -0,0 +1,316 @@ +# 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 , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2026-01-25 07:13+0000\n" +"PO-Revision-Date: 2026-01-25 07:13+0000\n" +"Last-Translator: Gemini\n" +"Language-Team: Arabic\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" + +#: core/forms.py:7 +msgid "Password" +msgstr "كلمة المرور" + +#: core/forms.py:8 +msgid "Confirm Password" +msgstr "تأكيد كلمة المرور" + +#: core/forms.py:9 +msgid "Register as" +msgstr "التسجيل كـ" + +#: core/forms.py:10 core/models.py:13 +msgid "Phone Number" +msgstr "رقم الهاتف" + +#: core/forms.py:16 +msgid "Username" +msgstr "اسم المستخدم" + +#: core/forms.py:17 +msgid "Email" +msgstr "البريد الإلكتروني" + +#: core/forms.py:18 +msgid "First Name" +msgstr "الاسم الأول" + +#: core/forms.py:19 +msgid "Last Name" +msgstr "اسم العائلة" + +#: core/forms.py:26 +msgid "Passwords don't match" +msgstr "كلمات المرور غير متطابقة" + +#: core/models.py:8 core/models.py:32 +msgid "Shipper" +msgstr "شاحن" + +#: core/models.py:9 +msgid "Car Owner" +msgstr "صاحب سيارة" + +#: core/models.py:11 +msgid "User" +msgstr "مستخدم" + +#: core/models.py:12 +msgid "Role" +msgstr "الدور" + +#: core/models.py:19 +msgid "Profile" +msgstr "الملف الشخصي" + +#: core/models.py:20 +msgid "Profiles" +msgstr "الملفات الشخصية" + +#: core/models.py:24 +msgid "Pending Pickup" +msgstr "في انتظار الاستلام" + +#: core/models.py:25 +msgid "Picked Up" +msgstr "تم الاستلام" + +#: core/models.py:26 +msgid "In Transit" +msgstr "في الطريق" + +#: core/models.py:27 +msgid "Delivered" +msgstr "تم التوصيل" + +#: core/models.py:28 +msgid "Cancelled" +msgstr "ملغي" + +#: core/models.py:31 +msgid "Tracking Number" +msgstr "رقم التتبع" + +#: core/models.py:33 +msgid "Carrier" +msgstr "الناقل" + +#: core/models.py:35 +msgid "Description" +msgstr "الوصف" + +#: core/models.py:36 +msgid "Weight (kg)" +msgstr "الوزن (كجم)" + +#: core/models.py:36 +msgid "Weight in kg" +msgstr "الوزن بالكيلوجرام" + +#: core/models.py:38 +msgid "Pickup Address" +msgstr "عنوان الاستلام" + +#: core/models.py:39 +msgid "Delivery Address" +msgstr "عنوان التوصيل" + +#: core/models.py:41 +msgid "Receiver Name" +msgstr "اسم المستلم" + +#: core/models.py:42 +msgid "Receiver Phone" +msgstr "هاتف المستلم" + +#: core/models.py:44 core/templates/core/index.html:30 +msgid "Status" +msgstr "الحالة" + +#: core/models.py:45 +msgid "Created At" +msgstr "أنشئ في" + +#: core/models.py:46 +msgid "Updated At" +msgstr "حدث في" + +#: core/models.py:57 +msgid "Parcel" +msgstr "طرد" + +#: core/models.py:58 +msgid "Parcels" +msgstr "طرود" + +#: core/templates/base.html:9 +msgid "Small Shipments, Smart Delivery" +msgstr "شحنات صغيرة، توصيل ذكي" + +#: core/templates/base.html:58 +msgid "How it Works" +msgstr "كيف يعمل" + +#: core/templates/base.html:62 +msgid "Hello" +msgstr "مرحباً" + +#: core/templates/base.html:67 +msgid "Logout" +msgstr "تسجيل الخروج" + +#: core/templates/base.html:72 core/templates/core/login.html:4 +#: core/templates/core/login.html:25 +msgid "Login" +msgstr "تسجيل الدخول" + +#: core/templates/base.html:75 core/templates/core/register.html:4 +msgid "Register" +msgstr "تسجيل" + +#: core/templates/base.html:101 core/templates/core/index.html:13 +msgid "Start Shipping" +msgstr "ابدأ الشحن" + +#: core/templates/base.html:114 +msgid "All rights reserved." +msgstr "جميع الحقوق محفوظة." + +#: core/templates/core/index.html:10 +msgid "Small Shipments," +msgstr "شحنات صغيرة،" + +#: core/templates/core/index.html:10 +msgid "Smart Delivery." +msgstr "توصيل ذكي." + +#: core/templates/core/index.html:11 +msgid "" +"masarX connects shippers with local car owners for fast, reliable, and " +"trackable deliveries. Your cargo, our priority." +msgstr "يربط مسارX بين الشاحنين وأصحاب السيارات المحليين لتوصيل سريع وموثوق وقابل للتتبع. شحنتك هي أولويتنا." + +#: core/templates/core/index.html:14 +msgid "Learn More" +msgstr "تعلم المزيد" + +#: core/templates/core/index.html:19 +msgid "Track your Parcel" +msgstr "تتبع طردك" + +#: core/templates/core/index.html:22 +msgid "Enter Tracking ID (e.g. 5A2B...)" +msgstr "أدخل رقم التتبع (مثال: 5A2B...)" + +#: core/templates/core/index.html:23 +msgid "Track" +msgstr "تتبع" + +#: core/templates/core/index.html:34 +msgid "From" +msgstr "من" + +#: core/templates/core/index.html:35 +msgid "To" +msgstr "إلى" + +#: core/templates/core/index.html:42 +msgid "Enter your 10-character tracking ID to see live updates." +msgstr "أدخل رقم التتبع المكون من 10 أرقام لرؤية التحديثات المباشرة." + +#: core/templates/core/index.html:54 +msgid "How masarX Works" +msgstr "كيف يعمل مسارX" + +#: core/templates/core/index.html:55 +msgid "Simple steps to get your shipment moving" +msgstr "خطوات بسيطة لبدء شحن طردك" + +#: core/templates/core/index.html:63 +msgid "List your Parcel" +msgstr "أدرج طردك" + +#: core/templates/core/index.html:64 +msgid "" +"Enter shipment details, weight, and delivery addresses. It's quick and easy." +msgstr "أدخل تفاصيل الشحنة والوزن وعناوين التوصيل. إنه سريع وسهل." + +#: core/templates/core/index.html:72 +msgid "Connect with Driver" +msgstr "تواصل مع السائق" + +#: core/templates/core/index.html:73 +msgid "" +"A verified car owner near you picks up the parcel and starts the journey." +msgstr "يقوم صاحب سيارة تم التحقق منه بالقرب منك باستلام الطرد وبدء الرحلة." + +#: core/templates/core/index.html:81 +msgid "Secure Delivery" +msgstr "توصيل آمن" + +#: core/templates/core/index.html:82 +msgid "Track your parcel in real-time until it reaches its destination safely." +msgstr "تتبع طردك في الوقت الفعلي حتى يصل إلى وجهته بأمان." + +#: core/templates/core/index.html:92 +msgid "Ready to join the movement?" +msgstr "مستعد للانضمام إلينا؟" + +#: core/templates/core/index.html:95 +msgid "I want to send a parcel" +msgstr "أريد إرسال طرد" + +#: core/templates/core/index.html:96 +msgid "Become a Shipper" +msgstr "كن شاحناً" + +#: core/templates/core/index.html:99 +msgid "I have a car and want to earn" +msgstr "لدي سيارة وأريد كسب المال" + +#: core/templates/core/index.html:100 +msgid "Become a Driver" +msgstr "كن سائقاً" + +#: core/templates/core/login.html:13 +msgid "Login to masarX" +msgstr "تسجيل الدخول إلى مسارX" + +#: core/templates/core/login.html:28 +msgid "Don't have an account?" +msgstr "ليس لديك حساب؟" + +#: core/templates/core/login.html:28 +msgid "Register here" +msgstr "سجل هنا" + +#: core/templates/core/register.html:13 +msgid "Join masarX" +msgstr "انضم إلى مسارX" + +#: core/templates/core/register.html:28 +msgid "Create Account" +msgstr "إنشاء حساب" + +#: core/templates/core/register.html:31 +msgid "Already have an account?" +msgstr "لديك حساب بالفعل؟" + +#: core/templates/core/register.html:31 +msgid "Login here" +msgstr "سجل دخولك هنا" + +#: core/views.py:17 +msgid "Parcel not found." +msgstr "الطرد غير موجود." \ No newline at end of file diff --git a/locale/en/LC_MESSAGES/django.mo b/locale/en/LC_MESSAGES/django.mo new file mode 100644 index 0000000..71cbdf3 Binary files /dev/null and b/locale/en/LC_MESSAGES/django.mo differ diff --git a/locale/en/LC_MESSAGES/django.po b/locale/en/LC_MESSAGES/django.po new file mode 100644 index 0000000..01f7466 --- /dev/null +++ b/locale/en/LC_MESSAGES/django.po @@ -0,0 +1,315 @@ +# 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 , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2026-01-25 07:13+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: core/forms.py:7 +msgid "Password" +msgstr "" + +#: core/forms.py:8 +msgid "Confirm Password" +msgstr "" + +#: core/forms.py:9 +msgid "Register as" +msgstr "" + +#: core/forms.py:10 core/models.py:13 +msgid "Phone Number" +msgstr "" + +#: core/forms.py:16 +msgid "Username" +msgstr "" + +#: core/forms.py:17 +msgid "Email" +msgstr "" + +#: core/forms.py:18 +msgid "First Name" +msgstr "" + +#: core/forms.py:19 +msgid "Last Name" +msgstr "" + +#: core/forms.py:26 +msgid "Passwords don't match" +msgstr "" + +#: core/models.py:8 core/models.py:32 +msgid "Shipper" +msgstr "" + +#: core/models.py:9 +msgid "Car Owner" +msgstr "" + +#: core/models.py:11 +msgid "User" +msgstr "" + +#: core/models.py:12 +msgid "Role" +msgstr "" + +#: core/models.py:19 +msgid "Profile" +msgstr "" + +#: core/models.py:20 +msgid "Profiles" +msgstr "" + +#: core/models.py:24 +msgid "Pending Pickup" +msgstr "" + +#: core/models.py:25 +msgid "Picked Up" +msgstr "" + +#: core/models.py:26 +msgid "In Transit" +msgstr "" + +#: core/models.py:27 +msgid "Delivered" +msgstr "" + +#: core/models.py:28 +msgid "Cancelled" +msgstr "" + +#: core/models.py:31 +msgid "Tracking Number" +msgstr "" + +#: core/models.py:33 +msgid "Carrier" +msgstr "" + +#: core/models.py:35 +msgid "Description" +msgstr "" + +#: core/models.py:36 +msgid "Weight (kg)" +msgstr "" + +#: core/models.py:36 +msgid "Weight in kg" +msgstr "" + +#: core/models.py:38 +msgid "Pickup Address" +msgstr "" + +#: core/models.py:39 +msgid "Delivery Address" +msgstr "" + +#: core/models.py:41 +msgid "Receiver Name" +msgstr "" + +#: core/models.py:42 +msgid "Receiver Phone" +msgstr "" + +#: core/models.py:44 core/templates/core/index.html:30 +msgid "Status" +msgstr "" + +#: core/models.py:45 +msgid "Created At" +msgstr "" + +#: core/models.py:46 +msgid "Updated At" +msgstr "" + +#: core/models.py:57 +msgid "Parcel" +msgstr "" + +#: core/models.py:58 +msgid "Parcels" +msgstr "" + +#: core/templates/base.html:9 +msgid "Small Shipments, Smart Delivery" +msgstr "" + +#: core/templates/base.html:58 +msgid "How it Works" +msgstr "" + +#: core/templates/base.html:62 +msgid "Hello" +msgstr "" + +#: core/templates/base.html:67 +msgid "Logout" +msgstr "" + +#: core/templates/base.html:72 core/templates/core/login.html:4 +#: core/templates/core/login.html:25 +msgid "Login" +msgstr "" + +#: core/templates/base.html:75 core/templates/core/register.html:4 +msgid "Register" +msgstr "" + +#: core/templates/base.html:101 core/templates/core/index.html:13 +msgid "Start Shipping" +msgstr "" + +#: core/templates/base.html:114 +msgid "All rights reserved." +msgstr "" + +#: core/templates/core/index.html:10 +msgid "Small Shipments," +msgstr "" + +#: core/templates/core/index.html:10 +msgid "Smart Delivery." +msgstr "" + +#: core/templates/core/index.html:11 +msgid "" +"masarX connects shippers with local car owners for fast, reliable, and " +"trackable deliveries. Your cargo, our priority." +msgstr "" + +#: core/templates/core/index.html:14 +msgid "Learn More" +msgstr "" + +#: core/templates/core/index.html:19 +msgid "Track your Parcel" +msgstr "" + +#: core/templates/core/index.html:22 +msgid "Enter Tracking ID (e.g. 5A2B...)" +msgstr "" + +#: core/templates/core/index.html:23 +msgid "Track" +msgstr "" + +#: core/templates/core/index.html:34 +msgid "From" +msgstr "" + +#: core/templates/core/index.html:35 +msgid "To" +msgstr "" + +#: core/templates/core/index.html:42 +msgid "Enter your 10-character tracking ID to see live updates." +msgstr "" + +#: core/templates/core/index.html:54 +msgid "How masarX Works" +msgstr "" + +#: core/templates/core/index.html:55 +msgid "Simple steps to get your shipment moving" +msgstr "" + +#: core/templates/core/index.html:63 +msgid "List your Parcel" +msgstr "" + +#: core/templates/core/index.html:64 +msgid "" +"Enter shipment details, weight, and delivery addresses. It's quick and easy." +msgstr "" + +#: core/templates/core/index.html:72 +msgid "Connect with Driver" +msgstr "" + +#: core/templates/core/index.html:73 +msgid "" +"A verified car owner near you picks up the parcel and starts the journey." +msgstr "" + +#: core/templates/core/index.html:81 +msgid "Secure Delivery" +msgstr "" + +#: core/templates/core/index.html:82 +msgid "Track your parcel in real-time until it reaches its destination safely." +msgstr "" + +#: core/templates/core/index.html:92 +msgid "Ready to join the movement?" +msgstr "" + +#: core/templates/core/index.html:95 +msgid "I want to send a parcel" +msgstr "" + +#: core/templates/core/index.html:96 +msgid "Become a Shipper" +msgstr "" + +#: core/templates/core/index.html:99 +msgid "I have a car and want to earn" +msgstr "" + +#: core/templates/core/index.html:100 +msgid "Become a Driver" +msgstr "" + +#: core/templates/core/login.html:13 +msgid "Login to masarX" +msgstr "" + +#: core/templates/core/login.html:28 +msgid "Don't have an account?" +msgstr "" + +#: core/templates/core/login.html:28 +msgid "Register here" +msgstr "" + +#: core/templates/core/register.html:13 +msgid "Join masarX" +msgstr "" + +#: core/templates/core/register.html:28 +msgid "Create Account" +msgstr "" + +#: core/templates/core/register.html:31 +msgid "Already have an account?" +msgstr "" + +#: core/templates/core/register.html:31 +msgid "Login here" +msgstr "" + +#: core/views.py:17 +msgid "Parcel not found." +msgstr "" diff --git a/static/css/custom.css b/static/css/custom.css index 925f6ed..f76f993 100644 --- a/static/css/custom.css +++ b/static/css/custom.css @@ -1,4 +1,106 @@ -/* Custom styles for the application */ -body { - font-family: system-ui, -apple-system, sans-serif; +/* masarX Custom Styles */ +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Outfit:wght@600;700&display=swap'); + +:root { + --primary-dark: #1A1A1D; + --accent-orange: #FF922B; + --soft-cloud: #F8F9FA; + --slate-blue: #4D96FF; + --glass-bg: rgba(255, 255, 255, 0.1); } + +body { + font-family: 'Inter', sans-serif; + background-color: var(--soft-cloud); + color: var(--primary-dark); +} + +h1, h2, h3, h4, h5, h6 { + font-family: 'Outfit', sans-serif; + font-weight: 700; +} + +.hero-section { + background: linear-gradient(135deg, var(--primary-dark) 0%, #2D2D30 100%); + padding: 100px 0; + color: white; + position: relative; + overflow: hidden; +} + +.hero-section::before { + content: ''; + position: absolute; + top: -50px; + right: -50px; + width: 200px; + height: 200px; + background: var(--accent-orange); + filter: blur(80px); + opacity: 0.2; +} + +.glass-card { + background: rgba(255, 255, 255, 0.05); + backdrop-filter: blur(15px); + -webkit-backdrop-filter: blur(15px); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 20px; + padding: 30px; +} + +.btn-masarx-primary { + background-color: var(--accent-orange); + color: white; + border: none; + padding: 12px 30px; + border-radius: 12px; + font-weight: 600; + transition: all 0.3s ease; +} + +.btn-masarx-primary:hover { + background-color: #E87E1B; + transform: translateY(-2px); + color: white; +} + +.tracking-input { + background: rgba(255, 255, 255, 0.1); + border: 1px solid rgba(255, 255, 255, 0.2); + color: white; + border-radius: 12px 0 0 12px; + padding: 15px 20px; +} + +.tracking-input:focus { + background: rgba(255, 255, 255, 0.15); + border-color: var(--accent-orange); + box-shadow: none; + color: white; +} + +.feature-icon { + width: 60px; + height: 60px; + background: var(--accent-orange); + border-radius: 15px; + display: flex; + align-items: center; + justify-content: center; + margin-bottom: 20px; + color: white; + font-size: 24px; +} + +.parcel-status-badge { + padding: 8px 16px; + border-radius: 50px; + font-size: 14px; + font-weight: 600; +} + +.status-pending { background: #FFE8CC; color: #D9480F; } +.status-picked_up { background: #E3FAFC; color: #0B7285; } +.status-in_transit { background: #E7F5FF; color: #1864AB; } +.status-delivered { background: #EBFBEE; color: #2B8A3E; } \ No newline at end of file diff --git a/staticfiles/css/custom.css b/staticfiles/css/custom.css index 108056f..f76f993 100644 --- a/staticfiles/css/custom.css +++ b/staticfiles/css/custom.css @@ -1,21 +1,106 @@ +/* masarX Custom Styles */ +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Outfit:wght@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-dark: #1A1A1D; + --accent-orange: #FF922B; + --soft-cloud: #F8F9FA; + --slate-blue: #4D96FF; + --glass-bg: rgba(255, 255, 255, 0.1); } + 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; + background-color: var(--soft-cloud); + color: var(--primary-dark); } + +h1, h2, h3, h4, h5, h6 { + font-family: 'Outfit', sans-serif; + font-weight: 700; +} + +.hero-section { + background: linear-gradient(135deg, var(--primary-dark) 0%, #2D2D30 100%); + padding: 100px 0; + color: white; + position: relative; + overflow: hidden; +} + +.hero-section::before { + content: ''; + position: absolute; + top: -50px; + right: -50px; + width: 200px; + height: 200px; + background: var(--accent-orange); + filter: blur(80px); + opacity: 0.2; +} + +.glass-card { + background: rgba(255, 255, 255, 0.05); + backdrop-filter: blur(15px); + -webkit-backdrop-filter: blur(15px); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 20px; + padding: 30px; +} + +.btn-masarx-primary { + background-color: var(--accent-orange); + color: white; + border: none; + padding: 12px 30px; + border-radius: 12px; + font-weight: 600; + transition: all 0.3s ease; +} + +.btn-masarx-primary:hover { + background-color: #E87E1B; + transform: translateY(-2px); + color: white; +} + +.tracking-input { + background: rgba(255, 255, 255, 0.1); + border: 1px solid rgba(255, 255, 255, 0.2); + color: white; + border-radius: 12px 0 0 12px; + padding: 15px 20px; +} + +.tracking-input:focus { + background: rgba(255, 255, 255, 0.15); + border-color: var(--accent-orange); + box-shadow: none; + color: white; +} + +.feature-icon { + width: 60px; + height: 60px; + background: var(--accent-orange); + border-radius: 15px; + display: flex; + align-items: center; + justify-content: center; + margin-bottom: 20px; + color: white; + font-size: 24px; +} + +.parcel-status-badge { + padding: 8px 16px; + border-radius: 50px; + font-size: 14px; + font-weight: 600; +} + +.status-pending { background: #FFE8CC; color: #D9480F; } +.status-picked_up { background: #E3FAFC; color: #0B7285; } +.status-in_transit { background: #E7F5FF; color: #1864AB; } +.status-delivered { background: #EBFBEE; color: #2B8A3E; } \ No newline at end of file