Autosave: 20260206-170242

This commit is contained in:
Flatlogic Bot 2026-02-06 17:02:42 +00:00
parent 81ab8ae93e
commit 95a1721315
50 changed files with 3318 additions and 667 deletions

35
add_reviews.py Normal file
View File

@ -0,0 +1,35 @@
import os
import django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
django.setup()
from core.models import Product, ProductReview
from django.contrib.auth.models import User
def add_reviews():
products = Product.objects.all()
if not products.exists():
print("No products found.")
return
reviews_data = [
{"product_idx": 0, "name": "Chala Jimma", "rating": 5, "comment": "Excellent quality! Highly recommended for anyone in Jimma."},
{"product_idx": 0, "name": "Aster K.", "rating": 4, "comment": "Very good service and the product is as described."},
{"product_idx": 1 if products.count() > 1 else 0, "name": "Dawit H.", "rating": 5, "comment": "Fast delivery to Kochi and great price."},
{"product_idx": 2 if products.count() > 2 else 0, "name": "Mulu B.", "rating": 3, "comment": "Decent product, but took a bit longer to arrive."},
]
for data in reviews_data:
p = products[data["product_idx"]]
ProductReview.objects.create(
product=p,
full_name=data["name"],
rating=data["rating"],
comment=data["comment"]
)
print(f"Created {len(reviews_data)} sample reviews.")
if __name__ == "__main__":
add_reviews()

View File

@ -176,3 +176,6 @@ if EMAIL_USE_SSL:
EMAIL_USE_TLS = False
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
LOGIN_REDIRECT_URL = 'index'
LOGOUT_REDIRECT_URL = 'index'

View File

@ -10,9 +10,10 @@ urlpatterns = [
urlpatterns += i18n_patterns(
path('admin/', admin.site.py_urls if hasattr(admin.site, 'py_urls') else admin.site.urls),
path('accounts/', include('django.contrib.auth.urls')), # Added auth urls
path('', include('core.urls')),
)
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

Binary file not shown.

View File

@ -1,6 +1,6 @@
from django.contrib import admin
from modeltranslation.admin import TranslationAdmin
from .models import Profile, Category, Vendor, Product, Order, OrderItem
from .models import Profile, Category, Vendor, Product, Order, OrderItem, Article
@admin.register(Category)
class CategoryAdmin(TranslationAdmin):
@ -30,4 +30,11 @@ class OrderAdmin(admin.ModelAdmin):
list_filter = ('status', 'payment_method', 'created_at')
inlines = [OrderItemInline]
admin.site.register(Profile)
@admin.register(Article)
class ArticleAdmin(TranslationAdmin):
list_display = ('title', 'author', 'is_published', 'created_at')
list_filter = ('is_published', 'created_at', 'author')
search_fields = ('title', 'content')
prepopulated_fields = {'slug': ('title',)}
admin.site.register(Profile)

View File

@ -1,5 +1,6 @@
import os
import time
from .models import Category
def project_context(request):
"""
@ -8,6 +9,6 @@ def project_context(request):
return {
"project_description": os.getenv("PROJECT_DESCRIPTION", ""),
"project_image_url": os.getenv("PROJECT_IMAGE_URL", ""),
# Used for cache-busting static assets
"deployment_timestamp": int(time.time()),
}
"categories_all": Category.objects.all(),
}

37
core/forms.py Normal file
View File

@ -0,0 +1,37 @@
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from .models import Product, ProductImage, Profile
class ProductForm(forms.ModelForm):
class Meta:
model = Product
fields = ['category', 'name', 'description', 'price', 'stock', 'image', 'is_available']
widgets = {
'category': forms.Select(attrs={'class': 'form-select'}),
'name': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Product Name'}),
'description': forms.Textarea(attrs={'class': 'form-control', 'rows': 4, 'placeholder': 'Detailed description of your product...'}),
'price': forms.NumberInput(attrs={'class': 'form-control', 'placeholder': '0.00'}),
'stock': forms.NumberInput(attrs={'class': 'form-control', 'placeholder': '0'}),
'image': forms.ClearableFileInput(attrs={'class': 'form-control'}),
'is_available': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
}
class SignUpForm(UserCreationForm):
email = forms.EmailField(required=True, widget=forms.EmailInput(attrs={'class': 'form-control', 'placeholder': 'Email Address'}))
first_name = forms.CharField(max_length=30, required=True, widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'First Name'}))
last_name = forms.CharField(max_length=30, required=True, widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Last Name'}))
class Meta(UserCreationForm.Meta):
model = User
fields = UserCreationForm.Meta.fields + ('email', 'first_name', 'last_name')
def save(self, commit=True):
user = super().save(commit=False)
user.email = self.cleaned_data["email"]
user.first_name = self.cleaned_data["first_name"]
user.last_name = self.cleaned_data["last_name"]
if commit:
user.save()
Profile.objects.get_or_create(user=user)
return user

View File

@ -0,0 +1,48 @@
# Generated by Django 5.2.7 on 2026-02-05 18:03
import django.core.validators
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0002_remove_vendor_logo_remove_vendor_slug_and_more'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AddField(
model_name='order',
name='delivery_time_slot',
field=models.CharField(choices=[('Morning', 'Morning (8:00 AM - 12:00 PM)'), ('Afternoon', 'Afternoon (12:00 PM - 5:00 PM)'), ('Evening', 'Evening (5:00 PM - 8:00 PM)')], default='Morning', max_length=50),
),
migrations.AddField(
model_name='order',
name='kebele',
field=models.CharField(blank=True, choices=[('Bosa Addis', 'Bosa Addis'), ('Bosa Kitto', 'Bosa Kitto'), ('Ginjo', 'Ginjo'), ('Ginjo Guduru', 'Ginjo Guduru'), ('Hermata', 'Hermata'), ('Hermata Merkato', 'Hermata Merkato'), ('Jiren', 'Jiren'), ('Kofe', 'Kofe'), ('Mendera Kochi', 'Mendera Kochi'), ('Seto Semero', 'Seto Semero')], max_length=100),
),
migrations.CreateModel(
name='ProductImage',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('image', models.ImageField(upload_to='products/gallery/')),
('alt_text', models.CharField(blank=True, max_length=255)),
('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='images', to='core.product')),
],
),
migrations.CreateModel(
name='ProductReview',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('full_name', models.CharField(max_length=255)),
('rating', models.PositiveIntegerField(validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(5)])),
('comment', models.TextField()),
('created_at', models.DateTimeField(auto_now_add=True)),
('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reviews', to='core.product')),
('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)),
],
),
]

View File

@ -0,0 +1,31 @@
# Generated by Django 5.2.7 on 2026-02-05 18:50
import django.db.models.deletion
import django.utils.timezone
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0003_order_delivery_time_slot_order_kebele_productimage_and_more'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Article',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=255)),
('slug', models.SlugField(blank=True, unique=True)),
('content', models.TextField()),
('image', models.ImageField(blank=True, null=True, upload_to='articles/')),
('is_published', models.BooleanField(default=False)),
('created_at', models.DateTimeField(default=django.utils.timezone.now)),
('updated_at', models.DateTimeField(auto_now=True)),
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='articles', to=settings.AUTH_USER_MODEL)),
],
),
]

View File

@ -0,0 +1,43 @@
# Generated by Django 5.2.7 on 2026-02-05 18:51
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0004_article'),
]
operations = [
migrations.AddField(
model_name='article',
name='content_am',
field=models.TextField(null=True),
),
migrations.AddField(
model_name='article',
name='content_en',
field=models.TextField(null=True),
),
migrations.AddField(
model_name='article',
name='content_om',
field=models.TextField(null=True),
),
migrations.AddField(
model_name='article',
name='title_am',
field=models.CharField(max_length=255, null=True),
),
migrations.AddField(
model_name='article',
name='title_en',
field=models.CharField(max_length=255, null=True),
),
migrations.AddField(
model_name='article',
name='title_om',
field=models.CharField(max_length=255, null=True),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 5.2.7 on 2026-02-05 19:22
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0005_article_content_am_article_content_en_and_more'),
]
operations = [
migrations.AddField(
model_name='vendor',
name='kebele',
field=models.CharField(blank=True, choices=[('Bosa Addis', 'Bosa Addis'), ('Bosa Kitto', 'Bosa Kitto'), ('Ginjo', 'Ginjo'), ('Ginjo Guduru', 'Ginjo Guduru'), ('Hermata', 'Hermata'), ('Hermata Merkato', 'Hermata Merkato'), ('Jiren', 'Jiren'), ('Kofe', 'Kofe'), ('Mendera Kochi', 'Mendera Kochi'), ('Seto Semero', 'Seto Semero')], max_length=100),
),
]

View File

@ -2,6 +2,8 @@ from django.db import models
from django.contrib.auth.models import User
from django.utils.text import slugify
from django.utils import timezone
from django.core.validators import MinValueValidator, MaxValueValidator
from django.db.models import Avg
class Category(models.Model):
name = models.CharField(max_length=100)
@ -21,10 +23,24 @@ class Category(models.Model):
super().save(*args, **kwargs)
class Vendor(models.Model):
JIMMA_KEBELES = (
('Bosa Addis', 'Bosa Addis'),
('Bosa Kitto', 'Bosa Kitto'),
('Ginjo', 'Ginjo'),
('Ginjo Guduru', 'Ginjo Guduru'),
('Hermata', 'Hermata'),
('Hermata Merkato', 'Hermata Merkato'),
('Jiren', 'Jiren'),
('Kofe', 'Kofe'),
('Mendera Kochi', 'Mendera Kochi'),
('Seto Semero', 'Seto Semero'),
)
user = models.OneToOneField(User, on_delete=models.CASCADE)
business_name = models.CharField(max_length=255)
description = models.TextField(blank=True)
address = models.CharField(max_length=255)
kebele = models.CharField(max_length=100, choices=JIMMA_KEBELES, blank=True)
phone = models.CharField(max_length=20)
is_verified = models.BooleanField(default=False)
created_at = models.DateTimeField(default=timezone.now)
@ -37,7 +53,7 @@ class Product(models.Model):
vendor = models.ForeignKey(Vendor, related_name='products', on_delete=models.CASCADE)
name = models.CharField(max_length=255)
slug = models.SlugField(unique=True, blank=True)
image = models.ImageField(upload_to='products/', blank=True, null=True)
image = models.ImageField(upload_to='products/', blank=True, null=True) # Main image
description = models.TextField()
price = models.DecimalField(max_digits=10, decimal_places=2)
stock = models.IntegerField(default=0)
@ -53,6 +69,34 @@ class Product(models.Model):
self.slug = slugify(self.name)
super().save(*args, **kwargs)
@property
def average_rating(self):
avg = self.reviews.aggregate(Avg('rating'))['rating__avg']
return round(avg, 1) if avg else 0
@property
def review_count(self):
return self.reviews.count()
class ProductImage(models.Model):
product = models.ForeignKey(Product, related_name='images', on_delete=models.CASCADE)
image = models.ImageField(upload_to='products/gallery/')
alt_text = models.CharField(max_length=255, blank=True)
def __str__(self):
return f"Image for {self.product.name}"
class ProductReview(models.Model):
product = models.ForeignKey(Product, related_name='reviews', on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True) # Optional user
full_name = models.CharField(max_length=255) # For guests
rating = models.PositiveIntegerField(validators=[MinValueValidator(1), MaxValueValidator(5)])
comment = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"Review for {self.product.name} by {self.full_name}"
class Profile(models.Model):
ROLE_CHOICES = (
('customer', 'Customer'),
@ -75,11 +119,35 @@ class Order(models.Model):
('Delivered', 'Delivered'),
('Cancelled', 'Cancelled'),
)
JIMMA_KEBELES = (
('Bosa Addis', 'Bosa Addis'),
('Bosa Kitto', 'Bosa Kitto'),
('Ginjo', 'Ginjo'),
('Ginjo Guduru', 'Ginjo Guduru'),
('Hermata', 'Hermata'),
('Hermata Merkato', 'Hermata Merkato'),
('Jiren', 'Jiren'),
('Kofe', 'Kofe'),
('Mendera Kochi', 'Mendera Kochi'),
('Seto Semero', 'Seto Semero'),
# Add more as needed
)
TIME_SLOTS = (
('Morning', 'Morning (8:00 AM - 12:00 PM)'),
('Afternoon', 'Afternoon (12:00 PM - 5:00 PM)'),
('Evening', 'Evening (5:00 PM - 8:00 PM)'),
)
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
full_name = models.CharField(max_length=255)
email = models.EmailField(blank=True)
phone = models.CharField(max_length=20)
address = models.TextField()
kebele = models.CharField(max_length=100, choices=JIMMA_KEBELES, blank=True)
delivery_time_slot = models.CharField(max_length=50, choices=TIME_SLOTS, default='Morning')
total_price = models.DecimalField(max_digits=10, decimal_places=2)
payment_method = models.CharField(max_length=50)
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='Pending')
@ -99,4 +167,22 @@ class OrderItem(models.Model):
@property
def total_price(self):
return self.price * self.quantity
return self.price * self.quantity
class Article(models.Model):
title = models.CharField(max_length=255)
slug = models.SlugField(unique=True, blank=True)
content = models.TextField()
image = models.ImageField(upload_to='articles/', blank=True, null=True)
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='articles')
is_published = models.BooleanField(default=False)
created_at = models.DateTimeField(default=timezone.now)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
super().save(*args, **kwargs)

View File

@ -1,169 +1,222 @@
{% load i18n static %}
<!DOCTYPE html>
<html lang="{{ LANGUAGE_CODE }}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}{% trans "Ethio-Marketplace" %}{% 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 }}">
{% endif %}
<!-- Bootstrap 5 CSS -->
<link rel="stylesheet" href="{% static 'bootstrap/dist/css/bootstrap.min.css' %}">
<!-- Bootstrap Icons -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css">
<!-- Custom CSS -->
<link rel="stylesheet" href="{% static 'css/custom.css' %}?v={{ deployment_timestamp }}">
<style>
:root {
--primary-color: #0d6efd;
--secondary-color: #6c757d;
}
body {
font-family: 'Inter', system-ui, -apple-system, sans-serif;
background-color: #f8f9fa;
color: #333;
}
.navbar {
box-shadow: 0 2px 10px rgba(0,0,0,.05);
}
.hero-section {
padding: 5rem 0;
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
}
.card {
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0,0,0,.08) !important;
}
.btn-primary {
padding: 0.6rem 1.5rem;
border-radius: 8px;
}
</style>
{% block head %}{% endblock %}
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}{% trans "Jimma Market - Your Local Online Marketplace" %}{% endblock %}</title>
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Bootstrap Icons -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css">
<!-- Google Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<!-- Custom CSS -->
<link rel="stylesheet" href="{% static 'css/custom.css' %}?v={{ deployment_timestamp }}">
<style>
body {
font-family: 'Inter', sans-serif;
background-color: #f8f9fa;
}
.navbar-brand {
font-weight: 700;
color: #0d6efd;
}
.btn-primary {
background-color: #0d6efd;
border-color: #0d6efd;
padding: 0.5rem 1.5rem;
border-radius: 8px;
}
.card {
border-radius: 12px;
overflow: hidden;
transition: transform 0.2s;
}
.card:hover {
transform: translateY(-5px);
}
.footer {
background-color: #f8f9fa;
padding: 4rem 0 2rem;
margin-top: 5rem;
border-top: 1px solid #dee2e6;
}
.lang-switcher .dropdown-toggle::after {
display: none;
}
</style>
{% block extra_css %}{% endblock %}
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-white sticky-top py-3">
<div class="container">
<a class="navbar-brand fw-bold text-primary fs-4" href="{% url 'index' %}">
<i class="bi bi-shop me-2"></i>{% trans "Ethio-Market" %}
</a>
<button class="navbar-toggler border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav me-auto">
<li class="nav-item">
<a class="nav-link px-3" href="{% url 'index' %}">{% trans "Home" %}</a>
</li>
<li class="nav-item">
<a class="nav-link px-3" href="{% url 'product_list' %}">{% trans "Products" %}</a>
</li>
</ul>
<div class="d-flex align-items-center">
<!-- Language Switcher -->
<form action="{% url 'set_language' %}" method="post" class="me-3">
{% csrf_token %}
<input name="next" type="hidden" value="{{ request.get_full_path }}">
<select name="language" onchange="this.form.submit()" class="form-select form-select-sm bg-light border-0">
{% get_current_language as CURRENT_LANGUAGE %}
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}
{% for language in languages %}
<option value="{{ language.code }}" {% if language.code == CURRENT_LANGUAGE %}selected{% endif %}>
{{ language.name_local }}
</option>
{% endfor %}
</select>
</form>
<!-- Cart -->
<a href="{% url 'cart_detail' %}" class="btn btn-link text-dark position-relative me-3">
<i class="bi bi-cart3 fs-5"></i>
{% if request.session.cart %}
<span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger" style="font-size: 0.6rem;">
{{ request.session.cart|length }}
</span>
{% endif %}
</a>
{% if user.is_authenticated %}
<div class="dropdown">
<a class="btn btn-outline-primary btn-sm dropdown-toggle d-flex align-items-center" href="#" role="button" id="userDropdown" data-bs-toggle="dropdown" aria-expanded="false">
<i class="bi bi-person-circle me-1"></i> {{ user.username }}
</a>
<ul class="dropdown-menu dropdown-menu-end border-0 shadow-sm" aria-labelledby="userDropdown">
{% if user.vendor %}
<li><a class="dropdown-item" href="{% url 'vendor_dashboard' %}"><i class="bi bi-speedometer2 me-2"></i>{% trans "Vendor Dashboard" %}</a></li>
{% else %}
<li><a class="dropdown-item" href="{% url 'vendor_register' %}"><i class="bi bi-shop-window me-2"></i>{% trans "Become a Seller" %}</a></li>
{% endif %}
<li><a class="dropdown-item" href="{% url 'admin:index' %}"><i class="bi bi-gear me-2"></i>{% trans "Admin" %}</a></li>
<li><hr class="dropdown-divider"></li>
<li>
<form action="{% url 'admin:logout' %}" method="post" class="d-inline">
{% csrf_token %}
<button type="submit" class="dropdown-item text-danger"><i class="bi bi-box-arrow-right me-2"></i>{% trans "Logout" %}</button>
</form>
</li>
</ul>
<!-- Top Bar (Optional, for Language Switcher) -->
<div class="bg-light py-1 border-bottom">
<div class="container d-flex justify-content-end">
<div class="dropdown lang-switcher">
<button class="btn btn-sm btn-link text-dark dropdown-toggle text-decoration-none py-0" type="button" data-bs-toggle="dropdown">
<i class="bi bi-translate me-1"></i>
{% get_current_language as CURRENT_LANG %}
{% for code, name in LANGUAGES %}
{% if code == CURRENT_LANG %}{{ name }}{% endif %}
{% endfor %}
</button>
<ul class="dropdown-menu dropdown-menu-end shadow-sm border-0">
{% for code, name in LANGUAGES %}
<li>
<form action="{% url 'set_language' %}" method="post">
{% csrf_token %}
<input name="next" type="hidden" value="{{ request.get_full_path|slice:'3:' }}">
<input name="language" type="hidden" value="{{ code }}">
<button type="submit" class="dropdown-item {% if code == CURRENT_LANG %}active{% endif %}">
{{ name }}
</button>
</form>
</li>
{% endfor %}
</ul>
</div>
{% else %}
<a href="{% url 'admin:index' %}" class="btn btn-primary btn-sm">{% trans "Login" %}</a>
{% endif %}
</div>
</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>
<!-- Navigation -->
<nav class="navbar navbar-expand-lg navbar-light bg-white sticky-top shadow-sm">
<div class="container">
<a class="navbar-brand d-flex align-items-center" href="{% url 'index' %}">
<i class="bi bi-shop-window me-2 text-primary"></i>
Jimma Market
</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 me-auto">
<li class="nav-item">
<a class="nav-link" href="{% url 'product_list' %}">{% trans "Shop" %}</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'about_us' %}">{% trans "About" %}</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'article_list' %}">{% trans "Blog" %}</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'contact_us' %}">{% trans "Contact" %}</a>
</li>
</ul>
<div class="d-flex align-items-center">
<a href="{% url 'track_order' %}" class="btn btn-outline-primary me-2 d-none d-md-inline-block rounded-pill">
<i class="bi bi-truck me-1"></i> {% trans "Track Order" %}
</a>
<a href="{% url 'cart_detail' %}" class="btn btn-link text-dark position-relative me-3">
<i class="bi bi-cart3 fs-5"></i>
<span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger" id="cart-count">
{{ request.session.cart|length|default:0 }}
</span>
</a>
{% if user.is_authenticated %}
<div class="dropdown">
<button class="btn btn-link text-dark dropdown-toggle text-decoration-none" type="button" id="userDropdown" data-bs-toggle="dropdown" aria-expanded="false">
<i class="bi bi-person-circle fs-5 me-1"></i>
{{ user.username }}
</button>
<ul class="dropdown-menu dropdown-menu-end shadow border-0" aria-labelledby="userDropdown">
{% if user.vendor %}
<li><a class="dropdown-item" href="{% url 'vendor_dashboard' %}"><i class="bi bi-speedometer2 me-2"></i>{% trans "Dashboard" %}</a></li>
{% else %}
<li><a class="dropdown-item" href="{% url 'vendor_register' %}"><i class="bi bi-shop me-2"></i>{% trans "Become a Seller" %}</a></li>
{% endif %}
<li><hr class="dropdown-divider"></li>
<li>
<form action="{% url 'logout' %}" method="post" class="d-inline">
{% csrf_token %}
<button type="submit" class="dropdown-item text-danger"><i class="bi bi-box-arrow-right me-2"></i>{% trans "Logout" %}</button>
</form>
</li>
</ul>
</div>
{% else %}
<a href="{% url 'login' %}" class="btn btn-outline-primary me-2 rounded-pill px-4">{% trans "Login" %}</a>
<a href="{% url 'signup' %}" class="btn btn-primary rounded-pill px-4">{% trans "Sign Up" %}</a>
{% endif %}
</div>
</div>
</div>
{% endfor %}
</div>
{% endif %}
</nav>
<main>
{% block content %}{% endblock %}
</main>
<!-- Main Content -->
<main>
{% 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 %}
<footer class="bg-white py-5 mt-5 border-top">
<div class="container">
<div class="row">
<div class="col-md-6 text-center text-md-start mb-3 mb-md-0">
<h5 class="fw-bold text-primary mb-3">{% trans "Ethio-Market" %}</h5>
<p class="text-muted small">{% trans "Connecting Ethiopian local vendors with customers everywhere." %}</p>
{% block content %}{% endblock %}
</main>
<!-- Footer -->
<footer class="footer">
<div class="container">
<div class="row g-4">
<div class="col-lg-4">
<h5 class="fw-bold mb-4">Jimma Market</h5>
<p class="text-muted mb-4">{% trans "The most trusted online marketplace in Jimma, connecting local vendors with customers across the city. Experience quality and convenience at your doorstep." %}</p>
<div class="social-links">
<a href="https://t.me/Bilnett" target="_blank" class="text-dark me-3 fs-5" title="Telegram"><i class="bi bi-telegram"></i></a>
<a href="https://github.com/Osman-1234" target="_blank" class="text-dark me-3 fs-5" title="GitHub"><i class="bi bi-github"></i></a>
<a href="#" class="text-dark me-3 fs-5"><i class="bi bi-facebook"></i></a>
<a href="#" class="text-dark me-3 fs-5"><i class="bi bi-instagram"></i></a>
</div>
</div>
<div class="col-6 col-lg-2">
<h6 class="fw-bold mb-4">{% trans "Quick Links" %}</h6>
<ul class="list-unstyled">
<li class="mb-2"><a href="{% url 'product_list' %}" class="text-muted text-decoration-none">{% trans "Shop Products" %}</a></li>
<li class="mb-2"><a href="{% url 'article_list' %}" class="text-muted text-decoration-none">{% trans "Market News" %}</a></li>
<li class="mb-2"><a href="{% url 'how_it_works' %}" class="text-muted text-decoration-none">{% trans "How it Works" %}</a></li>
<li class="mb-2"><a href="{% url 'track_order' %}" class="text-muted text-decoration-none">{% trans "Track Order" %}</a></li>
</ul>
</div>
<div class="col-6 col-lg-2">
<h6 class="fw-bold mb-4">{% trans "Support" %}</h6>
<ul class="list-unstyled">
<li class="mb-2"><a href="{% url 'about_us' %}" class="text-muted text-decoration-none">{% trans "About Us" %}</a></li>
<li class="mb-2"><a href="{% url 'contact_us' %}" class="text-muted text-decoration-none">{% trans "Contact Support" %}</a></li>
<li class="mb-2"><a href="{% url 'delivery_info' %}" class="text-muted text-decoration-none">{% trans "Delivery Info" %}</a></li>
<li class="mb-2"><a href="{% url 'seller_info' %}" class="text-muted text-decoration-none">{% trans "Sell on Jimma" %}</a></li>
</ul>
</div>
<div class="col-lg-4">
<h6 class="fw-bold mb-4">{% trans "Company Contact" %}</h6>
<p class="text-muted small mb-3">{% trans "For business inquiries, partnerships, or technical support, please reach out directly." %}</p>
<ul class="list-unstyled text-muted small">
<li class="mb-1"><i class="bi bi-person-fill me-2"></i> Bilal</li>
<li class="mb-1"><i class="bi bi-envelope-fill me-2"></i> bilalmaa614@gmail.com</li>
<li class="mb-1"><i class="bi bi-telephone-fill me-2"></i> +251 980 375 465</li>
<li class="mb-1"><i class="bi bi-telegram me-2"></i> <a href="https://t.me/Bilnett" target="_blank" class="text-muted text-decoration-none">@Bilnett</a></li>
<li class="mb-1"><i class="bi bi-github me-2"></i> <a href="https://github.com/Osman-1234" target="_blank" class="text-muted text-decoration-none">Osman-1234</a></li>
</ul>
</div>
</div>
<hr class="my-4">
<div class="row align-items-center">
<div class="col-md-6 text-center text-md-start">
<p class="text-muted mb-0 small">&copy; 2026 Jimma Market. {% trans "All rights reserved." %}</p>
</div>
<div class="col-md-6 text-center text-md-end">
<p class="text-muted mb-0 small">{% trans "Built by" %} <a href="https://github.com/Osman-1234" target="_blank" class="text-primary text-decoration-none fw-bold">Bilal</a></p>
</div>
</div>
</div>
<div class="col-md-6 text-center text-md-end">
<p class="text-muted mb-0">&copy; 2026 {% trans "Ethio-Marketplace" %}. {% trans "All rights reserved." %}</p>
</div>
</div>
</div>
</footer>
</footer>
<!-- Bootstrap 5 Bundle with Popper -->
<script src="{% static 'bootstrap/dist/js/bootstrap.bundle.min.js' %}"></script>
{% block scripts %}{% endblock %}
<!-- Bootstrap JS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
{% block extra_js %}{% endblock %}
</body>
</html>
</html>

View File

@ -0,0 +1,172 @@
{% extends 'base.html' %}
{% load i18n %}
{% load static %}
{% block content %}
<div class="container py-5">
<!-- Hero Section -->
<div class="row align-items-center mb-5">
<div class="col-md-6">
<h1 class="display-4 fw-bold mb-4">{% trans "Empowering Jimma's Local Commerce" %}</h1>
<p class="lead text-muted mb-4">
{% trans "Jimma Market is the city's premier digital marketplace, dedicated to connecting local businesses with their community through technology and seamless delivery." %}
</p>
<div class="d-flex gap-3">
<a href="{% url 'product_list' %}" class="btn btn-primary btn-lg px-4">{% trans "Shop Now" %}</a>
<a href="{% url 'contact_us' %}" class="btn btn-outline-secondary btn-lg px-4">{% trans "Contact Us" %}</a>
</div>
</div>
<div class="col-md-6">
<div class="position-relative">
<div class="bg-primary rounded-pill position-absolute top-50 start-50 translate-middle w-75 h-75 opacity-10 blur-3xl"></div>
<img src="https://images.pexels.com/photos/1637108/pexels-photo-1637108.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1" alt="Jimma Culture" class="img-fluid rounded-4 shadow-lg position-relative">
</div>
</div>
</div>
<!-- Story Section -->
<div class="row mb-5 py-5">
<div class="col-lg-8 mx-auto text-center">
<h2 class="fw-bold mb-4">{% trans "Our Story" %}</h2>
<p class="fs-5 text-secondary mb-0">
{% trans "Born in the heart of the world's coffee birthplace, Jimma Market started with a simple vision: to make everyday shopping effortless for every resident of Jimma. We believe that by digitizing local trade, we can support Jimma's economy while providing unmatched convenience to consumers." %}
</p>
</div>
</div>
<!-- Mission & Vision -->
<div class="row g-4 mb-5 pb-5">
<div class="col-md-6">
<div class="card border-0 bg-light h-100 p-4 p-lg-5">
<div class="mb-4">
<span class="badge bg-primary-subtle text-primary p-2 px-3 rounded-pill">{% trans "Our Mission" %}</span>
</div>
<h3 class="fw-bold mb-3">{% trans "Connecting Jimma" %}</h3>
<p class="text-secondary mb-0">
{% trans "To provide a reliable, fast, and user-friendly platform that bridges the gap between Jimma's diverse sellers and the digital consumer, ensuring quality products reach every Kebele within hours." %}
</p>
</div>
</div>
<div class="col-md-6">
<div class="card border-0 bg-light h-100 p-4 p-lg-5">
<div class="mb-4">
<span class="badge bg-success-subtle text-success p-2 px-3 rounded-pill">{% trans "Our Vision" %}</span>
</div>
<h3 class="fw-bold mb-3">{% trans "The Hub of Commerce" %}</h3>
<p class="text-secondary mb-0">
{% trans "To become the leading e-commerce ecosystem in Jimma and the Oromia region, setting the standard for local delivery networks and digital marketplace trust." %}
</p>
</div>
</div>
</div>
<!-- Why Us Section -->
<div class="text-center mb-5">
<h2 class="fw-bold mb-5">{% trans "Why Shop With Us?" %}</h2>
<div class="row g-4">
<div class="col-md-3">
<div class="p-4">
<div class="h1 text-primary mb-3"><i class="bi bi-shop"></i></div>
<h5 class="fw-bold">{% trans "Local Support" %}</h5>
<p class="small text-muted">{% trans "Directly supporting businesses in Jimma city." %}</p>
</div>
</div>
<div class="col-md-3">
<div class="p-4">
<div class="h1 text-primary mb-3"><i class="bi bi-truck"></i></div>
<h5 class="fw-bold">{% trans "Fast Delivery" %}</h5>
<p class="small text-muted">{% trans "Same-day delivery to all Jimma Kebeles." %}</p>
</div>
</div>
<div class="col-md-3">
<div class="p-4">
<div class="h1 text-primary mb-3"><i class="bi bi-shield-check"></i></div>
<h5 class="fw-bold">{% trans "Trusted Quality" %}</h5>
<p class="small text-muted">{% trans "Verified sellers and quality-checked products." %}</p>
</div>
</div>
<div class="col-md-3">
<div class="p-4">
<div class="h1 text-primary mb-3"><i class="bi bi-translate"></i></div>
<h5 class="fw-bold">{% trans "Multi-Language" %}</h5>
<p class="small text-muted">{% trans "Afaan Oromoo, Amharic, and English support." %}</p>
</div>
</div>
</div>
</div>
<!-- Team Section -->
<div class="bg-dark text-white rounded-4 p-5">
<div class="text-center mb-5">
<h2 class="fw-bold">{% trans "Meet Our Team" %}</h2>
<p class="text-white-50">{% trans "The people working behind the scenes to modernize Jimma's marketplace." %}</p>
</div>
<div class="row g-4 justify-content-center">
<!-- Lead Developer -->
<div class="col-md-5">
<div class="card bg-white bg-opacity-10 border-0 h-100 p-4">
<div class="d-flex align-items-center mb-4">
<div class="bg-primary rounded-circle d-flex align-items-center justify-content-center text-white fw-bold shadow" style="width: 80px; height: 80px; font-size: 2rem;">
B
</div>
<div class="ms-4">
<h4 class="fw-bold mb-1">Bilal</h4>
<span class="badge bg-primary text-uppercase">{% trans "Lead Developer" %}</span>
</div>
</div>
<p class="text-white-50 mb-4">
{% trans "Passionate about building scalable digital solutions that solve real-world problems for the Jimma community." %}
</p>
<div class="mt-auto">
<div class="d-flex flex-wrap gap-3">
<a href="mailto:bilalmaa614@gmail.com" class="btn btn-sm btn-outline-light rounded-pill">
<i class="bi bi-envelope me-1"></i> Email
</a>
<a href="https://t.me/Bilnett" target="_blank" class="btn btn-sm btn-outline-light rounded-pill">
<i class="bi bi-telegram me-1"></i> Telegram
</a>
<a href="https://github.com/Osman-1234" target="_blank" class="btn btn-sm btn-outline-light rounded-pill">
<i class="bi bi-github me-1"></i> GitHub
</a>
</div>
</div>
</div>
</div>
<!-- Other Teams -->
<div class="col-md-7">
<div class="row g-4">
<div class="col-sm-6">
<div class="bg-white bg-opacity-10 rounded-4 p-4 text-center h-100">
<div class="h2 mb-3"><i class="bi bi-truck"></i></div>
<h6 class="fw-bold mb-2">{% trans "Logistics & Ops" %}</h6>
<p class="small text-white-50 mb-0">{% trans "Managing delivery zones and rider networks across all Kebeles." %}</p>
</div>
</div>
<div class="col-sm-6">
<div class="bg-white bg-opacity-10 rounded-4 p-4 text-center h-100">
<div class="h2 mb-3"><i class="bi bi-headset"></i></div>
<h6 class="fw-bold mb-2">{% trans "Customer Success" %}</h6>
<p class="small text-white-50 mb-0">{% trans "Providing local support in Afaan Oromoo and Amharic." %}</p>
</div>
</div>
<div class="col-sm-6">
<div class="bg-white bg-opacity-10 rounded-4 p-4 text-center h-100">
<div class="h2 mb-3"><i class="bi bi-people"></i></div>
<h6 class="fw-bold mb-2">{% trans "Vendor Relations" %}</h6>
<p class="small text-white-50 mb-0">{% trans "Onboarding and supporting Jimma's local businesses." %}</p>
</div>
</div>
<div class="col-sm-6">
<div class="bg-white bg-opacity-10 rounded-4 p-4 text-center h-100 d-flex flex-column justify-content-center">
<p class="small text-white-50 mb-3">{% trans "Interested in joining our mission?" %}</p>
<a href="{% url 'contact_us' %}" class="btn btn-sm btn-primary">{% trans "Work with us" %}</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -1,14 +1,75 @@
{% extends 'base.html' %}
{% load static %}
{% block title %}{{ article.title }}{% endblock %}
{% block title %}{{ article.title }} - Jimma Market Blog{% endblock %}
{% block content %}
<div class="container mt-5">
<h1>{{ article.title }}</h1>
<p class="text-muted">Published on {{ article.created_at|date:"F d, Y" }}</p>
<hr>
<div>
{{ article.content|safe }}
<article class="py-5">
<div class="container">
<div class="row justify-content-center">
<div class="col-lg-8">
<!-- Article Header -->
<header class="mb-5 text-center">
<nav aria-label="breadcrumb">
<ol class="breadcrumb justify-content-center mb-4">
<li class="breadcrumb-item"><a href="{% url 'index' %}" class="text-decoration-none">Home</a></li>
<li class="breadcrumb-item"><a href="{% url 'article_list' %}" class="text-decoration-none">Blog</a></li>
<li class="breadcrumb-item active" aria-current="page">{{ article.title|truncatechars:30 }}</li>
</ol>
</nav>
<h1 class="display-4 fw-bold mb-4">{{ article.title }}</h1>
<div class="d-flex align-items-center justify-content-center text-muted">
<div class="me-3">
<i class="bi bi-person-circle me-1"></i>
{{ article.author.get_full_name|default:article.author.username }}
</div>
<div class="me-3">
<i class="bi bi-calendar3 me-1"></i>
{{ article.created_at|date:"F d, Y" }}
</div>
</div>
</header>
<!-- Featured Image -->
{% if article.image %}
<div class="mb-5">
<img src="{{ article.image.url }}" alt="{{ article.title }}" class="img-fluid rounded-4 shadow">
</div>
{% endif %}
<!-- Article Content -->
<div class="article-content lead mb-5">
{{ article.content|safe|linebreaks }}
</div>
<!-- Footer / Share -->
<hr class="my-5">
<div class="d-flex align-items-center justify-content-between flex-wrap gap-3">
<div class="d-flex align-items-center">
<span class="fw-bold me-3">Share this story:</span>
<div class="btn-group">
<a href="#" class="btn btn-outline-secondary btn-sm"><i class="bi bi-facebook"></i></a>
<a href="#" class="btn btn-outline-secondary btn-sm"><i class="bi bi-twitter-x"></i></a>
<a href="#" class="btn btn-outline-secondary btn-sm"><i class="bi bi-telegram"></i></a>
<a href="#" class="btn btn-outline-secondary btn-sm"><i class="bi bi-whatsapp"></i></a>
</div>
</div>
<a href="{% url 'article_list' %}" class="btn btn-light rounded-pill">
<i class="bi bi-arrow-left me-2"></i> Back to Blog
</a>
</div>
</div>
</div>
</div>
</div>
</article>
<style>
.article-content {
line-height: 1.8;
color: #333;
}
.article-content p {
margin-bottom: 1.5rem;
}
</style>
{% endblock %}

View File

@ -0,0 +1,70 @@
{% extends 'base.html' %}
{% load static %}
{% block title %}Market News & Blog - Jimma Market{% endblock %}
{% block content %}
<!-- Hero Section -->
<section class="py-5 bg-light border-bottom">
<div class="container py-4 text-center">
<h1 class="display-4 fw-bold">Market News & Blog</h1>
<p class="lead text-muted mb-0">Stay updated with the latest trends, vendor stories, and market updates in Jimma.</p>
</div>
</section>
<!-- Blog List Section -->
<section class="py-5">
<div class="container">
<div class="row g-4">
{% for article in articles %}
<div class="col-md-4">
<div class="card h-100 border-0 shadow-sm transition-hover">
{% if article.image %}
<img src="{{ article.image.url }}" class="card-img-top" alt="{{ article.title }}" style="height: 200px; object-fit: cover;">
{% else %}
<div class="bg-secondary text-white d-flex align-items-center justify-content-center" style="height: 200px;">
<i class="bi bi-journal-text display-4"></i>
</div>
{% endif %}
<div class="card-body">
<div class="d-flex align-items-center mb-2 text-muted small">
<span><i class="bi bi-calendar3 me-1"></i> {{ article.created_at|date:"M d, Y" }}</span>
<span class="mx-2">|</span>
<span><i class="bi bi-person me-1"></i> {{ article.author.get_full_name|default:article.author.username }}</span>
</div>
<h5 class="card-title fw-bold">
<a href="{% url 'article_detail' article.slug %}" class="text-dark text-decoration-none">
{{ article.title }}
</a>
</h5>
<p class="card-text text-muted">
{{ article.content|striptags|truncatewords:20 }}
</p>
</div>
<div class="card-footer bg-transparent border-0 pt-0 pb-4">
<a href="{% url 'article_detail' article.slug %}" class="btn btn-outline-primary btn-sm rounded-pill">Read More</a>
</div>
</div>
</div>
{% empty %}
<div class="col-12 text-center py-5">
<div class="mb-3">
<i class="bi bi-journal-x display-1 text-muted"></i>
</div>
<h3>No articles found</h3>
<p class="text-muted">Check back later for new updates and stories from Jimma Market.</p>
<a href="{% url 'index' %}" class="btn btn-primary rounded-pill px-4">Return Home</a>
</div>
{% endfor %}
</div>
</div>
</section>
<style>
.transition-hover:hover {
transform: translateY(-5px);
transition: transform 0.3s ease-in-out;
box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.1) !important;
}
</style>
{% endblock %}

View File

@ -1,81 +1,111 @@
{% extends "base.html" %}
{% load i18n static %}
{% block title %}{% trans "Shopping Cart" %}{% endblock %}
{% block title %}{% trans "Shopping Cart" %} | Jimma Market{% endblock %}
{% block content %}
<div class="container py-5">
<h1 class="fw-bold mb-4">{% trans "Your Shopping Cart" %}</h1>
<section class="py-5 bg-light min-vh-100">
<div class="container">
<h2 class="fw-bold mb-5">{% trans "Your Shopping Cart" %} 🛒</h2>
{% if cart_items %}
<div class="row g-5">
<div class="col-lg-8">
<div class="table-responsive">
<table class="table align-middle">
<thead>
<tr>
<th scope="col">{% trans "Product" %}</th>
<th scope="col">{% trans "Price" %}</th>
<th scope="col">{% trans "Quantity" %}</th>
<th scope="col">{% trans "Subtotal" %}</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
{% for item in cart_items %}
<tr>
<td>
<div class="d-flex align-items-center">
{% if item.product.image %}
<img src="{{ item.product.image.url }}" alt="{{ item.product.name }}" class="rounded me-3" style="width: 60px; height: 60px; object-fit: cover;">
{% endif %}
<div>
<h6 class="mb-0">{{ item.product.name }}</h6>
<small class="text-muted">{{ item.product.vendor.business_name }}</small>
</div>
</div>
</td>
<td>{{ item.product.price }} ETB</td>
<td>{{ item.quantity }}</td>
<td>{{ item.subtotal }} ETB</td>
<td>
<a href="{% url 'cart_remove' item.product.id %}" class="text-danger">
<i class="bi bi-trash"></i> {% trans "Remove" %}
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% if cart_items %}
<div class="row g-5">
<div class="col-lg-8">
<div class="card border-0 shadow-sm rounded-4 overflow-hidden">
<div class="table-responsive">
<table class="table table-borderless align-middle mb-0">
<thead class="bg-white border-bottom">
<tr>
<th class="px-4 py-3 text-secondary small fw-bold">{% trans "Product" %}</th>
<th class="py-3 text-secondary small fw-bold">{% trans "Quantity" %}</th>
<th class="py-3 text-secondary small fw-bold">{% trans "Subtotal" %}</th>
<th class="py-3"></th>
</tr>
</thead>
<tbody class="bg-white">
{% for item in cart_items %}
<tr class="border-bottom-light">
<td class="px-4 py-4">
<div class="d-flex align-items-center">
<div class="bg-light rounded-3 p-1 me-3" style="width: 70px; height: 70px;">
{% if item.product.image %}
<img src="{{ item.product.image.url }}" class="img-fluid rounded-2 h-100 w-100" style="object-fit: cover;">
{% else %}
<div class="h-100 w-100 d-flex align-items-center justify-content-center">
<i class="bi bi-image text-secondary"></i>
</div>
{% endif %}
</div>
<div>
<h6 class="fw-bold mb-1">
<a href="{% url 'product_detail' item.product.slug %}" class="text-decoration-none text-dark">{{ item.product.name }}</a>
</h6>
<small class="text-secondary">{{ item.product.category.name }}</small>
</div>
</div>
</td>
<td class="py-4">
<div class="d-flex align-items-center bg-light rounded-pill px-3 py-1" style="width: fit-content;">
<span class="fw-bold">{{ item.quantity }}</span>
</div>
</td>
<td class="py-4">
<span class="fw-bold text-primary">{{ item.subtotal }} ETB</span>
</td>
<td class="py-4 pe-4 text-end">
<a href="{% url 'cart_remove' item.product.id %}" class="btn btn-link text-danger p-0">
<i class="bi bi-trash fs-5"></i>
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<div class="mt-4">
<a href="{% url 'product_list' %}" class="btn btn-link text-secondary text-decoration-none">
<i class="bi bi-arrow-left me-2"></i> {% trans "Continue Shopping" %}
</a>
</div>
</div>
<div class="col-lg-4">
<div class="card border-0 shadow-sm p-4 rounded-4">
<h5 class="fw-bold mb-4">{% trans "Cart Total" %}</h5>
<div class="d-flex justify-content-between mb-3">
<span class="text-secondary">{% trans "Subtotal" %}</span>
<span class="fw-bold">{{ total }} ETB</span>
</div>
<div class="d-flex justify-content-between mb-4">
<span class="text-secondary">{% trans "Delivery" %}</span>
<span class="text-success small fw-bold">{% trans "Calculated at checkout" %}</span>
</div>
<hr class="my-4 border-light">
<div class="d-flex justify-content-between mb-5">
<span class="h5 fw-bold mb-0">{% trans "Total" %}</span>
<span class="h5 fw-bold mb-0 text-primary">{{ total }} ETB</span>
</div>
<a href="{% url 'checkout' %}" class="btn btn-primary btn-lg w-100 rounded-pill py-3 mb-3">
{% trans "Proceed to Checkout" %}
</a>
<p class="small text-secondary text-center mb-0">
{% trans "Secure & Easy Guest Checkout" %}
</p>
</div>
</div>
</div>
<div class="col-lg-4">
<div class="card border-0 shadow-sm p-4">
<h4 class="fw-bold mb-4">{% trans "Order Summary" %}</h4>
<div class="d-flex justify-content-between mb-2">
<span>{% trans "Subtotal" %}</span>
<span>{{ total }} ETB</span>
</div>
<div class="d-flex justify-content-between mb-4">
<span>{% trans "Shipping" %}</span>
<span class="text-success">{% trans "Free" %}</span>
</div>
<hr>
<div class="d-flex justify-content-between mb-4">
<span class="fw-bold">{% trans "Total" %}</span>
<span class="fw-bold text-primary fs-4">{{ total }} ETB</span>
</div>
<a href="{% url 'checkout' %}" class="btn btn-primary btn-lg w-100">
{% trans "Proceed to Checkout" %}
</a>
{% else %}
<div class="text-center py-5 bg-white rounded-5 shadow-sm">
<div class="bg-light rounded-circle d-flex align-items-center justify-content-center mx-auto mb-4" style="width: 120px; height: 120px;">
<i class="bi bi-cart-x display-1 text-secondary opacity-50"></i>
</div>
<h3 class="fw-bold">{% trans "Your cart is empty" %}</h3>
<p class="text-secondary mb-5">{% trans "Looks like you haven't added anything to your cart yet." %}</p>
<a href="{% url 'product_list' %}" class="btn btn-primary btn-lg rounded-pill px-5">{% trans "Start Shopping" %}</a>
</div>
{% endif %}
</div>
{% else %}
<div class="text-center py-5">
<p class="lead text-muted mb-4">{% trans "Your cart is empty." %}</p>
<a href="{% url 'product_list' %}" class="btn btn-primary">{% trans "Start Shopping" %}</a>
</div>
{% endif %}
</div>
{% endblock %}
</section>
{% endblock %}

View File

@ -1,46 +1,105 @@
{% extends "base.html" %}
{% load i18n static %}
{% block title %}{{ category.name }}{% endblock %}
{% block title %}{{ category.name }} | Jimma Market{% endblock %}
{% block content %}
<div class="container py-5">
<div class="mb-4">
<h1 class="fw-bold">{{ category.name }}</h1>
{% if category.description %}
<p class="lead text-muted">{{ category.description }}</p>
{% endif %}
</div>
<section class="py-5 bg-light min-vh-100">
<div class="container">
<nav aria-label="breadcrumb" class="mb-4">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="{% url 'index' %}" class="text-decoration-none">{% trans "Home" %}</a></li>
<li class="breadcrumb-item"><a href="{% url 'product_list' %}" class="text-decoration-none">{% trans "Shop" %}</a></li>
<li class="breadcrumb-item active" aria-current="page">{{ category.name }}</li>
</ol>
</nav>
<div class="row g-4">
{% for product in products %}
<div class="col-sm-6 col-md-4 col-lg-3">
<div class="card h-100 border-0 shadow-sm">
{% if product.image %}
<img src="{{ product.image.url }}" class="card-img-top" alt="{{ product.name }}" style="height: 200px; object-fit: cover;">
{% else %}
<div class="card-img-top bg-secondary d-flex align-items-center justify-content-center" style="height: 200px;">
<span class="text-white">{% trans "No Image" %}</span>
</div>
<div class="row align-items-end mb-5">
<div class="col-md-8">
<h1 class="fw-bold mb-2">{{ category.name }}</h1>
{% if category.description %}
<p class="lead text-secondary mb-2">{{ category.description }}</p>
{% endif %}
<div class="card-body">
<h5 class="card-title h6 mb-2">
<a href="{% url 'product_detail' product.slug %}" class="text-decoration-none text-dark">
{{ product.name }}
</a>
</h5>
<p class="fw-bold text-primary mb-3">{{ product.price }} ETB</p>
<a href="{% url 'cart_add' product.id %}" class="btn btn-outline-primary btn-sm w-100">
{% trans "Add to Cart" %}
</a>
</div>
<div class="badge bg-primary rounded-pill px-3">{{ products.count }} {% trans "Products" %}</div>
</div>
<div class="col-md-4 mt-3 mt-md-0">
<form method="GET" class="d-flex align-items-center">
<div class="input-group">
<span class="input-group-text bg-white border-0 shadow-sm"><i class="bi bi-geo-alt text-primary"></i></span>
<select name="kebele" onchange="this.form.submit()" class="form-select border-0 shadow-sm">
<option value="">{% trans "All Neighborhoods" %}</option>
{% for kebele in kebeles %}
<option value="{{ kebele }}" {% if current_kebele == kebele %}selected{% endif %}>{{ kebele }}</option>
{% endfor %}
</select>
</div>
</form>
</div>
</div>
{% empty %}
<div class="col-12 text-center py-5">
<p class="text-muted">{% trans "No products available in this category yet." %}</p>
{% if current_kebele %}
<div class="alert alert-info border-0 shadow-sm rounded-4 d-flex justify-content-between align-items-center mb-4">
<span>
<i class="bi bi-info-circle-fill me-2"></i>
{% trans "Showing" %} <strong>{{ category.name }}</strong> {% trans "from vendors in" %} <strong>{{ current_kebele }}</strong>
</span>
<a href="?" class="btn btn-sm btn-outline-info rounded-pill">{% trans "Clear Filter" %}</a>
</div>
{% endif %}
<div class="row g-4">
{% for product in products %}
<div class="col-sm-6 col-md-4 col-lg-3">
<div class="card h-100 border-0 shadow-sm position-relative hover-lift transition-hover">
{% if product.image %}
<img src="{{ product.image.url }}" class="card-img-top p-2 rounded-4" alt="{{ product.name }}" style="height: 200px; object-fit: cover;">
{% else %}
<div class="card-img-top bg-secondary-subtle d-flex align-items-center justify-content-center m-2 rounded-4" style="height: 200px;">
<i class="bi bi-image fs-1 text-secondary"></i>
</div>
{% endif %}
<div class="card-body pt-0">
<div class="d-flex justify-content-between align-items-start mb-2">
{% if product.review_count > 0 %}
<div class="text-warning small">
<i class="bi bi-star-fill"></i> {{ product.average_rating }}
</div>
{% else %}
<span class="small text-muted">{% trans "No reviews" %}</span>
{% endif %}
<small class="text-muted"><i class="bi bi-geo-alt me-1"></i>{{ product.vendor.kebele }}</small>
</div>
<h6 class="fw-bold mb-2">
<a href="{% url 'product_detail' product.slug %}" class="text-decoration-none text-dark">
{{ product.name }}
</a>
</h6>
<p class="text-secondary small mb-3 text-truncate">{{ product.description|striptags }}</p>
<div class="d-flex justify-content-between align-items-center mt-auto">
<span class="fw-bold text-primary">{{ product.price }} ETB</span>
<a href="{% url 'cart_add' product.id %}" class="btn btn-dark btn-sm rounded-pill px-3">
<i class="bi bi-plus-lg"></i>
</a>
</div>
</div>
</div>
</div>
{% empty %}
<div class="col-12 text-center py-5 bg-white rounded-5 shadow-sm">
<i class="bi bi-box-seam display-1 text-secondary opacity-50 mb-4"></i>
<h4 class="fw-bold">{% trans "No products found" %}</h4>
<p class="text-secondary">{% trans "Try adjusting your filters or check back later." %}</p>
<a href="?" class="btn btn-primary rounded-pill px-4 mt-3">{% trans "Show All Neighborhoods" %}</a>
</div>
{% endfor %}
</div>
{% endfor %}
</div>
</div>
{% endblock %}
</section>
<style>
.transition-hover:hover {
transform: translateY(-5px);
box-shadow: 0 1rem 3rem rgba(0,0,0,.1) !important;
}
</style>
{% endblock %}

View File

@ -1,73 +1,130 @@
{% extends "base.html" %}
{% load i18n static %}
{% block title %}{% trans "Checkout" %}{% endblock %}
{% block title %}{% trans "Checkout" %} | Jimma Market{% endblock %}
{% block content %}
<div class="container py-5">
<h1 class="fw-bold mb-4">{% trans "Checkout" %}</h1>
<form action="{% url 'checkout' %}" method="post">
{% csrf_token %}
<section class="py-5 bg-light min-vh-100">
<div class="container">
<div class="row g-5">
<div class="col-md-7 col-lg-8">
<h4 class="mb-3">{% trans "Shipping Address" %}</h4>
<div class="row g-3">
<div class="col-12">
<label for="full_name" class="form-label">{% trans "Full Name" %}</label>
<input type="text" class="form-control" id="full_name" name="full_name" required>
</div>
<!-- Checkout Form -->
<div class="col-lg-8">
<div class="card border-0 shadow-sm p-4 p-md-5 rounded-4">
<h2 class="fw-bold mb-4">{% trans "Delivery Information" %} 📍</h2>
<p class="text-secondary mb-5">{% trans "Complete your order by providing your delivery details. No registration required!" %}</p>
<div class="col-12">
<label for="email" class="form-label">{% trans "Email" %} <span class="text-muted">({% trans "Optional" %})</span></label>
<input type="email" class="form-control" id="email" name="email" placeholder="you@example.com">
</div>
<form action="{% url 'checkout' %}" method="post">
{% csrf_token %}
<div class="row g-4 mb-5">
<div class="col-md-6">
<label class="form-label small fw-bold">{% trans "Full Name" %}</label>
<input type="text" name="full_name" required class="form-control rounded-pill border-0 shadow-sm bg-white px-4 py-2" placeholder="{% trans "e.g. Abebe Kebede" %}">
</div>
<div class="col-md-6">
<label class="form-label small fw-bold">{% trans "Phone Number" %} ({% trans "Required for delivery" %})</label>
<input type="tel" name="phone" required class="form-control rounded-pill border-0 shadow-sm bg-white px-4 py-2" placeholder="{% trans "e.g. 0911223344" %}">
</div>
<div class="col-md-12">
<label class="form-label small fw-bold">{% trans "Email Address" %} ({% trans "Optional" %})</label>
<input type="email" name="email" class="form-control rounded-pill border-0 shadow-sm bg-white px-4 py-2" placeholder="{% trans "For order updates via email" %}">
</div>
</div>
<div class="col-12">
<label for="phone" class="form-label">{% trans "Phone Number" %}</label>
<input type="text" class="form-control" id="phone" name="phone" placeholder="+251..." required>
</div>
<h4 class="fw-bold mb-4">{% trans "Where should we deliver?" %}</h4>
<div class="row g-4 mb-5">
<div class="col-md-6">
<label class="form-label small fw-bold">{% trans "Select Kebele" %}</label>
<select name="kebele" required class="form-select rounded-pill border-0 shadow-sm bg-white px-4 py-2">
<option value="" disabled selected>{% trans "Choose your location..." %}</option>
{% for code, name in kebeles %}
<option value="{{ code }}">{{ name }}</option>
{% endfor %}
</select>
</div>
<div class="col-md-6">
<label class="form-label small fw-bold">{% trans "Delivery Time Slot" %}</label>
<select name="delivery_time_slot" required class="form-select rounded-pill border-0 shadow-sm bg-white px-4 py-2">
{% for code, name in time_slots %}
<option value="{{ code }}">{{ name }}</option>
{% endfor %}
</select>
</div>
<div class="col-12">
<label class="form-label small fw-bold">{% trans "Detailed Address" %}</label>
<textarea name="address" required class="form-control rounded-4 border-0 shadow-sm bg-white px-4 py-3" rows="3" placeholder="{% trans "e.g. Near Kochi Post Office, House No. 123" %}"></textarea>
</div>
</div>
<div class="col-12">
<label for="address" class="form-label">{% trans "Address" %}</label>
<textarea class="form-control" id="address" name="address" rows="3" required></textarea>
</div>
<h4 class="fw-bold mb-4">{% trans "Payment Method" %}</h4>
<div class="row g-3 mb-5">
<div class="col-md-6">
<div class="form-check card p-3 border-0 shadow-sm hover-lift">
<input class="form-check-input ms-0 me-3" type="radio" name="payment_method" id="pay1" value="Cash on Delivery" checked>
<label class="form-check-label fw-bold" for="pay1">
{% trans "Cash on Delivery" %} 💵
</label>
<p class="small text-secondary mb-0 mt-2 ms-4">{% trans "Pay when you receive your items." %}</p>
</div>
</div>
<div class="col-md-6">
<div class="form-check card p-3 border-0 shadow-sm hover-lift opacity-50">
<input class="form-check-input ms-0 me-3" type="radio" name="payment_method" id="pay2" value="Telebirr" disabled>
<label class="form-check-label fw-bold" for="pay2">
{% trans "Telebirr / CBE Birr" %} 📱
</label>
<p class="small text-secondary mb-0 mt-2 ms-4">{% trans "Coming soon!" %}</p>
</div>
</div>
</div>
{% if not user.is_authenticated %}
<div class="bg-primary-subtle p-4 rounded-4 mb-5 border-start border-primary border-4">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="create_account" id="saveDetails">
<label class="form-check-label fw-bold text-dark" for="saveDetails">
{% trans "Save my details for next time" %}
</label>
<p class="small text-secondary mb-0">{% trans "This will create a free account for you to track your order." %}</p>
</div>
</div>
{% endif %}
<button type="submit" class="btn btn-primary btn-lg w-100 rounded-pill py-3">
{% trans "Place Order Now" %} 🚀
</button>
</form>
</div>
<hr class="my-4">
<h4 class="mb-3">{% trans "Payment Method" %}</h4>
<div class="my-3">
<div class="form-check">
<input id="cod" name="payment_method" type="radio" class="form-check-input" value="COD" checked required>
<label class="form-check-label" for="cod">{% trans "Cash on Delivery" %}</label>
</div>
<div class="form-check">
<input id="telebirr" name="payment_method" type="radio" class="form-check-input" value="Telebirr" required>
<label class="form-check-label" for="telebirr">Telebirr</label>
</div>
<div class="form-check">
<input id="cbe" name="payment_method" type="radio" class="form-check-input" value="CBE" required>
<label class="form-check-label" for="cbe">CBE Birr</label>
</div>
</div>
<button class="w-100 btn btn-primary btn-lg" type="submit">{% trans "Place Order" %}</button>
</div>
<div class="col-md-5 col-lg-4 order-md-last">
<h4 class="d-flex justify-content-between align-items-center mb-3">
<span class="text-primary">{% trans "Your cart" %}</span>
</h4>
<ul class="list-group mb-3">
<li class="list-group-item d-flex justify-content-between">
<span>{% trans "Total (ETB)" %}</span>
<strong>{{ total }} ETB</strong>
</li>
</ul>
<!-- Order Summary -->
<div class="col-lg-4">
<div class="card border-0 shadow-sm p-4 rounded-4 sticky-top" style="top: 100px;">
<h5 class="fw-bold mb-4">{% trans "Order Summary" %}</h5>
<div class="mb-4">
<div class="d-flex justify-content-between mb-2">
<span class="text-secondary">{% trans "Subtotal" %}</span>
<span class="fw-bold">{{ total }} ETB</span>
</div>
<div class="d-flex justify-content-between mb-2">
<span class="text-secondary">{% trans "Delivery Fee" %}</span>
<span class="text-success fw-bold">{% trans "FREE" %}</span>
</div>
<hr class="my-3 border-light">
<div class="d-flex justify-content-between">
<span class="h5 fw-bold mb-0">{% trans "Total" %}</span>
<span class="h5 fw-bold mb-0 text-primary">{{ total }} ETB</span>
</div>
</div>
<div class="alert alert-light border-0 small mb-0 rounded-3">
<i class="bi bi-info-circle me-2 text-primary"></i>
{% trans "By placing this order, you agree to Jimma Market's terms of service and delivery policies." %}
</div>
</div>
</div>
</div>
</form>
</div>
{% endblock %}
</div>
</section>
{% endblock %}

View File

@ -0,0 +1,109 @@
{% extends 'base.html' %}
{% load i18n %}
{% load static %}
{% block content %}
<div class="container py-5">
<div class="row g-5">
<!-- Contact Info -->
<div class="col-lg-5">
<h1 class="display-4 fw-bold mb-4">{% trans "Get in Touch" %}</h1>
<p class="lead text-muted mb-5">
{% trans "Have questions about an order or want to partner with us? Our team in Jimma is ready to help you." %}
</p>
<div class="d-flex mb-4">
<div class="flex-shrink-0 me-3">
<div class="bg-primary-subtle text-primary rounded-circle d-flex align-items-center justify-content-center" style="width: 50px; height: 50px;">
<i class="bi bi-geo-alt-fill"></i>
</div>
</div>
<div>
<h5 class="fw-bold mb-1">{% trans "Our Office" %}</h5>
<p class="text-muted mb-0">{% trans "Jimma City Center, Near Hotel Central, Jimma, Ethiopia" %}</p>
</div>
</div>
<div class="d-flex mb-4">
<div class="flex-shrink-0 me-3">
<div class="bg-primary-subtle text-primary rounded-circle d-flex align-items-center justify-content-center" style="width: 50px; height: 50px;">
<i class="bi bi-telephone-fill"></i>
</div>
</div>
<div>
<h5 class="fw-bold mb-1">{% trans "Call Us" %}</h5>
<p class="text-muted mb-0">+251 980 375 465</p>
</div>
</div>
<div class="d-flex mb-4">
<div class="flex-shrink-0 me-3">
<div class="bg-primary-subtle text-primary rounded-circle d-flex align-items-center justify-content-center" style="width: 50px; height: 50px;">
<i class="bi bi-envelope-fill"></i>
</div>
</div>
<div>
<h5 class="fw-bold mb-1">{% trans "Email Us" %}</h5>
<p class="text-muted mb-0">bilalmaa614@gmail.com</p>
</div>
</div>
<div class="card border-0 bg-light rounded-4 p-4 mt-5 mb-4">
<h5 class="fw-bold mb-3"><i class="bi bi-code-slash me-2 text-primary"></i>{% trans "Developer Collaboration" %}</h5>
<p class="small text-muted mb-3">{% trans "Interested in the technical side or want to collaborate on the platform's development?" %}</p>
<div class="mb-2">
<p class="mb-0 fw-bold small text-dark">Bilal</p>
<p class="mb-1 small text-muted"><i class="bi bi-envelope me-2"></i>bilalmaa614@gmail.com</p>
<p class="mb-1 small text-muted"><i class="bi bi-telephone me-2"></i>+251 980 375 465</p>
<p class="mb-1 small text-muted"><i class="bi bi-telegram me-2"></i>@Bilnett</p>
<p class="mb-0 small text-muted"><i class="bi bi-github me-2"></i>Osman-1234</p>
</div>
</div>
<div class="d-flex gap-3 h4 mt-4">
<a href="#" class="text-primary"><i class="bi bi-facebook"></i></a>
<a href="https://t.me/Bilnett" class="text-primary" target="_blank"><i class="bi bi-telegram"></i></a>
<a href="#" class="text-primary"><i class="bi bi-instagram"></i></a>
<a href="https://github.com/Osman-1234" class="text-primary" target="_blank"><i class="bi bi-github"></i></a>
</div>
</div>
<!-- Contact Form -->
<div class="col-lg-7">
<div class="card border-0 shadow-lg p-4 p-lg-5 rounded-4">
<h3 class="fw-bold mb-4">{% trans "Send us a Message" %}</h3>
<form method="POST">
{% csrf_token %}
<div class="row g-3">
<div class="col-md-6">
<label class="form-label fw-bold small">{% trans "Your Name" %}</label>
<input type="text" name="name" class="form-control bg-light border-0 py-3" placeholder="Abebe Bikila" required>
</div>
<div class="col-md-6">
<label class="form-label fw-bold small">{% trans "Your Phone" %}</label>
<input type="tel" name="phone" class="form-control bg-light border-0 py-3" placeholder="+251 ..." required>
</div>
<div class="col-12">
<label class="form-label fw-bold small">{% trans "Subject" %}</label>
<select name="subject" class="form-select bg-light border-0 py-3">
<option value="general">{% trans "General Inquiry" %}</option>
<option value="order">{% trans "Order Support" %}</option>
<option value="vendor">{% trans "Become a Seller" %}</option>
<option value="delivery">{% trans "Delivery Question" %}</option>
<option value="dev">{% trans "Developer Collaboration" %}</option>
</select>
</div>
<div class="col-12">
<label class="form-label fw-bold small">{% trans "Message" %}</label>
<textarea name="message" class="form-control bg-light border-0 py-3" rows="5" placeholder="{% trans 'How can we help you today?' %}" required></textarea>
</div>
<div class="col-12">
<button type="submit" class="btn btn-primary btn-lg w-100 py-3 fw-bold rounded-3">{% trans "Send Message" %}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,115 @@
{% extends 'base.html' %}
{% load i18n %}
{% load static %}
{% block content %}
<div class="container py-5">
<div class="row mb-5">
<div class="col-lg-7">
<h1 class="display-4 fw-bold mb-4">{% trans "Delivery Information" %}</h1>
<p class="lead text-muted">
{% trans "We provide fast and reliable delivery service across all Kebeles in Jimma city. Our mission is to get your products to you within hours of ordering." %}
</p>
</div>
</div>
<!-- Delivery Map Placeholder -->
<div class="row mb-5">
<div class="col-12">
<div class="bg-light rounded-4 overflow-hidden position-relative" style="height: 400px;">
<div class="position-absolute top-50 start-50 translate-middle text-center">
<i class="bi bi-geo-alt fs-1 text-primary mb-3"></i>
<h3 class="fw-bold">{% trans "Jimma City Delivery Zones" %}</h3>
<p class="text-muted">{% trans "We cover Central, North, South, and Outskirts zones." %}</p>
<div class="mt-4">
<span class="badge bg-success mx-1">Zone A (Central)</span>
<span class="badge bg-primary mx-1">Zone B (Inner city)</span>
<span class="badge bg-warning text-dark mx-1">Zone C (Outskirts)</span>
</div>
</div>
<!-- Placeholder for an actual map -->
<div class="w-100 h-100 opacity-25" style="background-image: url('https://images.pexels.com/photos/1078850/pexels-photo-1078850.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1'); background-size: cover; background-position: center;"></div>
</div>
</div>
</div>
<div class="row g-5">
<!-- Delivery Fees -->
<div class="col-md-6">
<h3 class="fw-bold mb-4">{% trans "Delivery Fees by Zone" %}</h3>
<div class="card border-0 shadow-sm overflow-hidden rounded-4">
<ul class="list-group list-group-flush">
<li class="list-group-item d-flex justify-content-between align-items-center py-3 px-4">
<div>
<h6 class="mb-0 fw-bold">{% trans "Zone A" %}</h6>
<small class="text-muted">{% trans "Bosa, Mendera, Ginjo, Hermata" %}</small>
</div>
<span class="fw-bold text-primary">50 ETB</span>
</li>
<li class="list-group-item d-flex justify-content-between align-items-center py-3 px-4">
<div>
<h6 class="mb-0 fw-bold">{% trans "Zone B" %}</h6>
<small class="text-muted">{% trans "Kito Furdisa, Awetu, Ifa Bula" %}</small>
</div>
<span class="fw-bold text-primary">75 ETB</span>
</li>
<li class="list-group-item d-flex justify-content-between align-items-center py-3 px-4">
<div>
<h6 class="mb-0 fw-bold">{% trans "Zone C" %}</h6>
<small class="text-muted">{% trans "Bore, Hulle, Jimma University Outskirts" %}</small>
</div>
<span class="fw-bold text-primary">100 ETB</span>
</li>
</ul>
</div>
<p class="small text-muted mt-3">
* {% trans "Fees may vary slightly based on package weight and volume." %}
</p>
</div>
<!-- Delivery Slots -->
<div class="col-md-6">
<h3 class="fw-bold mb-4">{% trans "Available Delivery Slots" %}</h3>
<div class="row g-3">
<div class="col-6">
<div class="p-3 border rounded-3 bg-white text-center">
<div class="text-primary fw-bold">09:00 - 12:00</div>
<div class="small text-muted">{% trans "Morning Slot" %}</div>
</div>
</div>
<div class="col-6">
<div class="p-3 border rounded-3 bg-white text-center">
<div class="text-primary fw-bold">12:00 - 15:00</div>
<div class="small text-muted">{% trans "Afternoon Slot 1" %}</div>
</div>
</div>
<div class="col-6">
<div class="p-3 border rounded-3 bg-white text-center">
<div class="text-primary fw-bold">15:00 - 18:00</div>
<div class="small text-muted">{% trans "Afternoon Slot 2" %}</div>
</div>
</div>
<div class="col-6">
<div class="p-3 border rounded-3 bg-white text-center">
<div class="text-primary fw-bold">18:00 - 20:00</div>
<div class="small text-muted">{% trans "Evening Slot" %}</div>
</div>
</div>
</div>
<div class="mt-4 p-4 bg-primary text-white rounded-4">
<h5 class="fw-bold mb-2">{% trans "Express Delivery" %}</h5>
<p class="mb-0 small">
{% trans "Need it even faster? Choose 'Express' at checkout for delivery within 60 minutes for central Jimma locations (+30 ETB)." %}
</p>
</div>
</div>
</div>
<!-- Track Order Call to Action -->
<div class="mt-5 p-5 bg-dark text-white rounded-4 text-center">
<h2 class="fw-bold mb-3">{% trans "Track Your Order" %}</h2>
<p class="mb-4 text-white-50">{% trans "Check the real-time status of your package using your order number and phone number." %}</p>
<a href="{% url 'track_order' %}" class="btn btn-primary btn-lg px-5">{% trans "Track Now" %}</a>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,103 @@
{% extends 'base.html' %}
{% load i18n %}
{% load static %}
{% block content %}
<div class="container py-5">
<div class="text-center mb-5">
<h1 class="display-4 fw-bold">{% trans "How It Works" %}</h1>
<p class="lead text-muted">{% trans "Shopping at Jimma Market is simple, fast, and secure." %}</p>
</div>
<!-- Steps -->
<div class="row g-5 mb-5 align-items-center">
<div class="col-md-6">
<div class="d-flex mb-5">
<div class="flex-shrink-0 me-4">
<div class="bg-primary text-white rounded-circle d-flex align-items-center justify-content-center fw-bold fs-4" style="width: 60px; height: 60px;">1</div>
</div>
<div>
<h3 class="fw-bold">{% trans "Browse & Select" %}</h3>
<p class="text-muted">{% trans "Explore thousands of products from local Jimma vendors. Use our smart search or category filters to find exactly what you need. No account required to start shopping!" %}</p>
</div>
</div>
<div class="d-flex mb-5">
<div class="flex-shrink-0 me-4">
<div class="bg-primary text-white rounded-circle d-flex align-items-center justify-content-center fw-bold fs-4" style="width: 60px; height: 60px;">2</div>
</div>
<div>
<h3 class="fw-bold">{% trans "Add to Cart" %}</h3>
<p class="text-muted">{% trans "Found something you like? Click 'Add to Cart'. You can continue shopping for more items from different vendors and manage everything in one single cart." %}</p>
</div>
</div>
<div class="d-flex">
<div class="flex-shrink-0 me-4">
<div class="bg-primary text-white rounded-circle d-flex align-items-center justify-content-center fw-bold fs-4" style="width: 60px; height: 60px;">3</div>
</div>
<div>
<h3 class="fw-bold">{% trans "Guest Checkout" %}</h3>
<p class="text-muted">{% trans "Go to your cart and click 'Proceed to Checkout'. Simply provide your phone number, delivery address in Jimma, and choose a delivery time slot that works for you." %}</p>
</div>
</div>
</div>
<div class="col-md-6">
<div class="bg-light rounded-4 p-5">
<img src="https://images.pexels.com/photos/5632371/pexels-photo-5632371.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1" alt="Shopping Step" class="img-fluid rounded-4 shadow">
</div>
</div>
</div>
<div class="row g-5 mb-5 align-items-center flex-md-row-reverse">
<div class="col-md-6">
<div class="d-flex mb-5">
<div class="flex-shrink-0 me-4">
<div class="bg-primary text-white rounded-circle d-flex align-items-center justify-content-center fw-bold fs-4" style="width: 60px; height: 60px;">4</div>
</div>
<div>
<h3 class="fw-bold">{% trans "Fast Delivery" %}</h3>
<p class="text-muted">{% trans "Our dedicated delivery team will pick up your items from the vendors and bring them directly to your door during your selected time slot." %}</p>
</div>
</div>
<div class="d-flex">
<div class="flex-shrink-0 me-4">
<div class="bg-primary text-white rounded-circle d-flex align-items-center justify-content-center fw-bold fs-4" style="width: 60px; height: 60px;">5</div>
</div>
<div>
<h3 class="fw-bold">{% trans "Pay & Enjoy" %}</h3>
<p class="text-muted">{% trans "Pay securely using Telebirr, CBE Birr, or Cash on Delivery. Receive your items, check the quality, and enjoy your purchase!" %}</p>
</div>
</div>
</div>
<div class="col-md-6">
<div class="bg-light rounded-4 p-5">
<img src="https://images.pexels.com/photos/6169033/pexels-photo-6169033.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1" alt="Delivery Step" class="img-fluid rounded-4 shadow">
</div>
</div>
</div>
<!-- Additional Info Sections -->
<div class="row g-4 pt-5 border-top">
<div class="col-md-4">
<h4 class="fw-bold mb-3"><i class="bi bi-wallet2 text-primary me-2"></i> {% trans "Payment Methods" %}</h4>
<ul class="list-unstyled text-muted">
<li><i class="bi bi-check2 text-success me-2"></i> Telebirr</li>
<li><i class="bi bi-check2 text-success me-2"></i> CBE Birr</li>
<li><i class="bi bi-check2 text-success me-2"></i> Cash on Delivery</li>
<li><i class="bi bi-check2 text-success me-2"></i> Bank Transfer (CBE, Awash, etc.)</li>
</ul>
</div>
<div class="col-md-4">
<h4 class="fw-bold mb-3"><i class="bi bi-arrow-left-right text-primary me-2"></i> {% trans "Return Policy" %}</h4>
<p class="text-muted">
{% trans "If a product is damaged or doesn't match the description, you can return it within 24 hours of delivery. Contact our support team immediately for assistance." %}
</p>
</div>
<div class="col-md-4">
<h4 class="fw-bold mb-3"><i class="bi bi-shield-lock text-primary me-2"></i> {% trans "Privacy & Security" %}</h4>
<p class="text-muted">
{% trans "Your personal data and transaction history are protected using industry-standard encryption. We never share your phone number with third parties." %}
</p>
</div>
</div>
</div>
{% endblock %}

View File

@ -1,17 +1,61 @@
{% extends "base.html" %}
{% load i18n static %}
{% block title %}{% trans "Ethio-Marketplace | Home" %}{% endblock %}
{% block content %}
<!-- Hero Section -->
<section class="hero-section text-center">
<section class="position-relative overflow-hidden py-5 mb-5" style="background: linear-gradient(135deg, #FFF5F0 0%, #FFF 100%); min-height: 500px; display: flex; align-items: center;">
<div class="container">
<h1 class="display-4 fw-bold mb-3">{% trans "Welcome to Ethio-Marketplace" %}</h1>
<p class="lead mb-4">{% trans "Discover amazing products from local vendors across Ethiopia." %}</p>
<div class="d-flex justify-content-center">
<a href="{% url 'product_list' %}" class="btn btn-primary btn-lg px-4 me-md-2">{% trans "Shop Now" %}</a>
<a href="{% url 'vendor_register' %}" class="btn btn-outline-secondary btn-lg px-4">{% trans "Become a Seller" %}</a>
<div class="row align-items-center g-5">
<div class="col-lg-6">
<span class="badge bg-primary-subtle text-primary rounded-pill px-3 py-2 mb-3 fw-bold">{% trans "Jimma's #1 Marketplace" %}</span>
<h1 class="display-3 fw-bold mb-4" style="line-height: 1.1;">
{% trans "Shop Local," %} <br>
<span class="text-primary">{% trans "Live Better." %}</span>
</h1>
<p class="lead text-secondary mb-5 pe-lg-5">
{% trans "Discover fresh produce, electronics, and daily essentials from trusted Jimma vendors. Find sellers in your neighborhood!" %}
</p>
<!-- Search by Product and Kebele Filter -->
<div class="card border-0 shadow-lg p-3 rounded-4 mb-5 bg-white" style="max-width: 600px; width: 100%;">
<form action="{% url 'product_list' %}" method="GET" class="row g-2 align-items-center">
<div class="col-md-5">
<div class="input-group">
<span class="input-group-text bg-transparent border-0"><i class="bi bi-search text-primary"></i></span>
<input type="text" name="q" class="form-control border-0 bg-transparent shadow-none" placeholder="{% trans "What are you looking for?" %}">
</div>
</div>
<div class="col-md-4 border-start d-none d-md-block">
<div class="input-group">
<span class="input-group-text bg-transparent border-0"><i class="bi bi-geo-alt text-primary"></i></span>
<select name="kebele" class="form-select border-0 bg-transparent shadow-none" aria-label="Select Kebele">
<option value="">{% trans "All Areas" %}</option>
{% for kebele in kebeles %}
<option value="{{ kebele }}" {% if kebele == selected_kebele %}selected{% endif %}>{{ kebele }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="col-md-3">
<button type="submit" class="btn btn-primary rounded-pill w-100 py-2">{% trans "Search" %}</button>
</div>
</form>
</div>
<div class="d-flex flex-wrap gap-3">
<a href="{% url 'product_list' %}" class="btn btn-outline-dark btn-lg rounded-pill px-4">{% trans "Explore All Shop" %} 🛍️</a>
<a href="{% url 'vendor_register' %}" class="btn btn-link text-primary text-decoration-none fw-bold px-4">{% trans "Become a Seller" %}</a>
</div>
</div>
<div class="col-lg-6">
<div class="position-relative">
<div class="bg-primary rounded-circle position-absolute top-50 start-50 translate-middle opacity-10" style="width: 500px; height: 500px;"></div>
<!-- Placeholder for Hero Image -->
<div class="card border-0 shadow-lg p-3 hover-lift rounded-4">
<img src="https://images.pexels.com/photos/1549702/pexels-photo-1549702.jpeg?auto=compress&cs=tinysrgb&w=800" class="img-fluid rounded-4" alt="Jimma Market">
</div>
</div>
</div>
</div>
</div>
</section>
@ -19,80 +63,193 @@
<!-- Categories Section -->
<section class="py-5">
<div class="container">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2 class="fw-bold">{% trans "Shop by Category" %}</h2>
<a href="#" class="text-decoration-none">{% trans "View All" %}</a>
<div class="d-flex justify-content-between align-items-end mb-5">
<div>
<h2 class="fw-bold mb-0">{% trans "Browse Categories" %}</h2>
<p class="text-secondary">{% trans "Find exactly what you need" %}</p>
</div>
<a href="{% url 'product_list' %}" class="btn btn-link text-primary fw-bold text-decoration-none">
{% trans "View All" %} <i class="bi bi-arrow-right"></i>
</a>
</div>
<div class="row g-4">
{% for category in categories %}
<div class="col-6 col-md-4 col-lg-2">
<a href="{% url 'category_products' category.slug %}" class="text-decoration-none text-dark">
<div class="card h-100 text-center border-0 shadow-sm transition-hover">
<div class="card-body">
<div class="card h-100 text-center p-3 border-0 shadow-sm transition-hover">
<div class="mb-3 mx-auto d-flex align-items-center justify-content-center bg-light rounded-circle" style="width: 80px; height: 80px;">
{% if category.image %}
<img src="{{ category.image.url }}" alt="{{ category.name }}" class="img-fluid mb-2" style="height: 60px; object-fit: contain;">
<img src="{{ category.image.url }}" alt="{{ category.name }}" class="img-fluid" style="width: 40px;">
{% else %}
<div class="bg-light rounded-circle mx-auto mb-2 d-flex align-items-center justify-content-center" style="width: 60px; height: 60px;">
<i class="bi bi-tag fs-3 text-primary"></i>
</div>
<i class="bi bi-box-seam fs-2 text-primary"></i>
{% endif %}
<h6 class="card-title mb-0">{{ category.name }}</h6>
</div>
<h6 class="fw-bold mb-0">{{ category.name }}</h6>
<small class="text-secondary">{{ category.products.count }} {% trans "Items" %}</small>
</div>
</a>
</div>
{% empty %}
<p class="text-center text-muted">{% trans "No categories found." %}</p>
{% endfor %}
</div>
</div>
</section>
<!-- Featured Products Section -->
<section class="py-5 bg-light">
<!-- Featured Products -->
<section class="py-5 bg-light rounded-5 mx-2 mx-md-5">
<div class="container">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2 class="fw-bold">{% trans "Featured Products" %}</h2>
<a href="{% url 'product_list' %}" class="text-decoration-none">{% trans "View All" %}</a>
<div class="d-flex justify-content-between align-items-end mb-5">
<div>
<h2 class="fw-bold mb-0">{% trans "Featured Products" %}</h2>
<p class="text-secondary">{% trans "Handpicked for you by our team" %}</p>
</div>
<a href="{% url 'product_list' %}" class="btn btn-outline-primary rounded-pill px-4">{% trans "Shop All" %}</a>
</div>
<div class="row g-4">
{% for product in featured_products %}
<div class="col-sm-6 col-md-4 col-lg-3">
<div class="card h-100 border-0 shadow-sm">
<div class="card h-100 border-0 shadow-sm position-relative transition-hover">
{% if product.image %}
<img src="{{ product.image.url }}" class="card-img-top" alt="{{ product.name }}" style="height: 200px; object-fit: cover;">
<img src="{{ product.image.url }}" class="card-img-top p-2 rounded-4" alt="{{ product.name }}" style="height: 250px; object-fit: cover;">
{% else %}
<div class="card-img-top bg-secondary d-flex align-items-center justify-content-center" style="height: 200px;">
<span class="text-white">{% trans "No Image" %}</span>
<div class="card-img-top bg-secondary-subtle d-flex align-items-center justify-content-center m-2 rounded-4" style="height: 250px;">
<i class="bi bi-image fs-1 text-secondary"></i>
</div>
{% endif %}
<div class="card-body">
<p class="text-muted small mb-1">{{ product.category.name }}</p>
<h5 class="card-title h6 mb-2">
<div class="card-body pt-0">
<div class="d-flex justify-content-between align-items-start mb-2">
<span class="badge bg-light text-primary d-inline-block rounded-pill small fw-bold">{{ product.category.name }}</span>
{% if product.review_count > 0 %}
<div class="text-warning small">
<i class="bi bi-star-fill"></i> {{ product.average_rating }}
</div>
{% endif %}
</div>
<h5 class="card-title h6 fw-bold mb-2">
<a href="{% url 'product_detail' product.slug %}" class="text-decoration-none text-dark">
{{ product.name }}
</a>
</h5>
<p class="fw-bold text-primary mb-3">{{ product.price }} ETB</p>
<a href="{% url 'cart_add' product.id %}" class="btn btn-outline-primary btn-sm w-100">
{% trans "Add to Cart" %}
</a>
<div class="d-flex justify-content-between align-items-center mt-3">
<span class="fs-5 fw-bold text-primary">{{ product.price }} <small class="fs-6">ETB</small></span>
<a href="{% url 'cart_add' product.id %}" class="btn btn-dark btn-sm rounded-pill px-3">
<i class="bi bi-plus-lg"></i>
</a>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
</section>
<!-- Top Vendors Section -->
<section class="py-5">
<div class="container">
<div class="d-flex justify-content-between align-items-end mb-5">
<div>
<h2 class="fw-bold mb-0">{% trans "Top Jimma Vendors" %}</h2>
<p class="text-secondary">{% trans "The people bringing Jimma's best to your door" %}</p>
</div>
<div class="dropdown">
<button class="btn btn-outline-secondary btn-sm dropdown-toggle rounded-pill px-3" type="button" data-bs-toggle="dropdown">
{% if selected_kebele %}{{ selected_kebele }}{% else %}{% trans "Filter by Kebele" %}{% endif %}
</button>
<ul class="dropdown-menu shadow border-0">
<li><a class="dropdown-item" href="{% url 'home' %}">{% trans "All Areas" %}</a></li>
{% for kebele in kebeles %}
<li><a class="dropdown-item" href="{% url 'home' %}?kebele={{ kebele }}">{{ kebele }}</a></li>
{% endfor %}
</ul>
</div>
</div>
<div class="row g-4">
{% for vendor in local_vendors %}
<div class="col-md-6 col-lg-3">
<div class="card h-100 border-0 shadow-sm text-center p-4 transition-hover rounded-4">
<div class="bg-primary-subtle text-primary rounded-circle mx-auto mb-3 d-flex align-items-center justify-content-center" style="width: 80px; height: 80px;">
<span class="fs-2 fw-bold">{{ vendor.business_name|slice:":1" }}</span>
</div>
<h5 class="fw-bold mb-1">{{ vendor.business_name }}</h5>
<div class="text-warning mb-2 small">
<i class="bi bi-star-fill"></i>
<i class="bi bi-star-fill"></i>
<i class="bi bi-star-fill"></i>
<i class="bi bi-star-fill"></i>
<i class="bi bi-star-fill text-muted opacity-25"></i>
</div>
<p class="small text-secondary mb-3">{{ vendor.description|default:"Jimma's trusted local seller providing quality products."|truncatewords:10 }}</p>
<div class="mt-auto">
<span class="badge bg-primary-subtle text-primary rounded-pill px-3 py-2 border-0 mb-2 d-inline-block">
<i class="bi bi-geo-alt-fill me-1"></i>{{ vendor.kebele|default:vendor.address }}
</span>
<div class="text-muted small">
<i class="bi bi-patch-check-fill text-primary me-1"></i>{% trans "Verified Seller" %}
</div>
</div>
</div>
</div>
{% empty %}
<div class="col-12 text-center py-5">
<p class="text-muted">{% trans "No featured products available." %}</p>
<i class="bi bi-shop fs-1 text-muted opacity-25"></i>
<p class="text-muted mt-3">{% trans "No vendors found in this neighborhood yet." %}</p>
<a href="{% url 'home' %}" class="btn btn-link">{% trans "Show all vendors" %}</a>
</div>
{% endfor %}
</div>
</div>
</section>
<!-- Market News & Blog Section -->
{% if latest_articles %}
<section class="py-5 bg-white">
<div class="container">
<div class="d-flex justify-content-between align-items-end mb-5">
<div>
<h2 class="fw-bold mb-0">{% trans "Market News & Stories" %}</h2>
<p class="text-secondary">{% trans "Stay updated with Jimma's local market" %}</p>
</div>
<a href="{% url 'article_list' %}" class="btn btn-link text-primary fw-bold text-decoration-none">
{% trans "Read All Stories" %} <i class="bi bi-arrow-right"></i>
</a>
</div>
<div class="row g-4">
{% for article in latest_articles %}
<div class="col-md-4">
<div class="card h-100 border-0 shadow-sm transition-hover">
{% if article.image %}
<img src="{{ article.image.url }}" class="card-img-top" alt="{{ article.title }}" style="height: 200px; object-fit: cover;">
{% else %}
<div class="bg-primary-subtle text-primary d-flex align-items-center justify-content-center" style="height: 200px;">
<i class="bi bi-journal-text display-4"></i>
</div>
{% endif %}
<div class="card-body">
<small class="text-muted d-block mb-2">{{ article.created_at|date:"M d, Y" }}</small>
<h5 class="card-title fw-bold">
<a href="{% url 'article_detail' article.slug %}" class="text-dark text-decoration-none">
{{ article.title }}
</a>
</h5>
<p class="card-text text-muted small">
{{ article.content|striptags|truncatewords:15 }}
</p>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
</section>
{% endif %}
<style>
.transition-hover:hover {
transform: translateY(-5px);
transition: transform 0.3s ease;
}
.transition-hover {
transition: all 0.3s ease-in-out;
}
.transition-hover:hover {
transform: translateY(-5px);
box-shadow: 0 1rem 3rem rgba(0,0,0,.1) !important;
}
</style>
{% endblock %}

View File

@ -1,31 +1,54 @@
{% extends "base.html" %}
{% load i18n static %}
{% block title %}{% trans "Order Successful" %}{% endblock %}
{% block title %}{% trans "Order Successful" %} | Jimma Market{% endblock %}
{% block content %}
<div class="container py-5 text-center">
<div class="mb-4">
<i class="bi bi-check-circle-fill text-success" style="font-size: 5rem;"></i>
</div>
<h1 class="fw-bold mb-3">{% trans "Thank you for your order!" %}</h1>
<p class="lead mb-4">{% trans "Your order ID is" %} #{{ order.id }}. {% trans "We have received your request and will contact you shortly for delivery." %}</p>
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card border-0 shadow-sm p-4 text-start">
<h5 class="fw-bold mb-3">{% trans "Order Details" %}</h5>
<p class="mb-1"><strong>{% trans "Name" %}:</strong> {{ order.full_name }}</p>
<p class="mb-1"><strong>{% trans "Phone" %}:</strong> {{ order.phone }}</p>
<p class="mb-1"><strong>{% trans "Address" %}:</strong> {{ order.address }}</p>
<p class="mb-1"><strong>{% trans "Total" %}:</strong> {{ order.total_price }} ETB</p>
<p class="mb-0"><strong>{% trans "Payment" %}:</strong> {{ order.get_payment_method_display }}</p>
<section class="py-5 bg-light min-vh-100 d-flex align-items-center">
<div class="container">
<div class="row justify-content-center">
<div class="col-lg-6 text-center">
<div class="card border-0 shadow-lg p-5 rounded-5">
<div class="bg-success-subtle rounded-circle d-flex align-items-center justify-content-center mx-auto mb-4" style="width: 120px; height: 120px;">
<i class="bi bi-check-circle-fill display-1 text-success"></i>
</div>
<h1 class="fw-bold mb-3">{% trans "Order Placed Successfully!" %}</h1>
<p class="lead text-secondary mb-5">
{% trans "Thank you for shopping with us, " %} <strong>{{ order.full_name }}</strong>!
{% trans "Your order" %} <span class="text-primary fw-bold">#{{ order.id }}</span> {% trans "has been received and is being processed." %}
</p>
<div class="bg-light rounded-4 p-4 text-start mb-5">
<h6 class="fw-bold mb-3">{% trans "Delivery Details" %}</h6>
<div class="d-flex align-items-center mb-2">
<i class="bi bi-geo-alt me-3 text-primary"></i>
<span>{{ order.address }}, {{ order.get_kebele_display }}</span>
</div>
<div class="d-flex align-items-center mb-2">
<i class="bi bi-clock me-3 text-primary"></i>
<span>{{ order.get_delivery_time_slot_display }}</span>
</div>
<div class="d-flex align-items-center">
<i class="bi bi-telephone me-3 text-primary"></i>
<span>{{ order.phone }}</span>
</div>
</div>
<p class="text-secondary small mb-5">
{% trans "A delivery agent will contact you shortly to confirm your location in Jimma. Please have your phone ready!" %} 📱
</p>
<div class="d-grid gap-3">
<a href="{% url 'index' %}" class="btn btn-primary btn-lg rounded-pill">{% trans "Continue Shopping" %}</a>
{% if not user.is_authenticated %}
<a href="{% url 'admin:index' %}" class="btn btn-link text-secondary text-decoration-none small">
{% trans "Create an account to track your orders" %}
</a>
{% endif %}
</div>
</div>
</div>
</div>
</div>
<div class="mt-5">
<a href="{% url 'index' %}" class="btn btn-primary px-4">{% trans "Return to Shop" %}</a>
</div>
</div>
{% endblock %}
</section>
{% endblock %}

View File

@ -1,49 +1,280 @@
{% extends "base.html" %}
{% load i18n static %}
{% block title %}{{ product.name }}{% endblock %}
{% block title %}{{ product.name }} | Jimma Market{% endblock %}
{% block content %}
<div class="container py-5">
<nav aria-label="breadcrumb" class="mb-4">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="{% url 'index' %}">{% trans "Home" %}</a></li>
<li class="breadcrumb-item"><a href="{% url 'category_products' product.category.slug %}">{{ product.category.name }}</a></li>
<li class="breadcrumb-item active" aria-current="page">{{ product.name }}</li>
</ol>
</nav>
<section class="py-5">
<div class="container">
<nav aria-label="breadcrumb" class="mb-4">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="{% url 'index' %}" class="text-decoration-none">{% trans "Home" %}</a></li>
<li class="breadcrumb-item"><a href="{% url 'category_products' product.category.slug %}" class="text-decoration-none">{{ product.category.name }}</a></li>
<li class="breadcrumb-item active" aria-current="page">{{ product.name }}</li>
</ol>
</nav>
<div class="row g-5">
<div class="col-md-6">
{% if product.image %}
<img src="{{ product.image.url }}" class="img-fluid rounded shadow-sm" alt="{{ product.name }}">
{% else %}
<div class="bg-light d-flex align-items-center justify-content-center rounded" style="min-height: 400px;">
<span class="text-muted">{% trans "No Image Available" %}</span>
<div class="row g-5">
<!-- Product Images -->
<div class="col-lg-6">
<div class="card border-0 shadow-sm p-2 rounded-4">
<div id="productCarousel" class="carousel slide" data-bs-ride="carousel">
<div class="carousel-inner rounded-3">
<div class="carousel-item active">
{% if product.image %}
<img src="{{ product.image.url }}" class="d-block w-100" alt="{{ product.name }}" style="max-height: 500px; object-fit: contain;">
{% else %}
<div class="bg-secondary-subtle d-flex align-items-center justify-content-center" style="height: 500px;">
<i class="bi bi-image fs-1 text-secondary"></i>
</div>
{% endif %}
</div>
{% for img in product.images.all %}
<div class="carousel-item">
<img src="{{ img.image.url }}" class="d-block w-100" alt="{{ img.alt_text|default:product.name }}" style="max-height: 500px; object-fit: contain;">
</div>
{% endfor %}
</div>
{% if product.images.count > 0 %}
<button class="carousel-control-prev" type="button" data-bs-target="#productCarousel" data-bs-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="visually-hidden">Previous</span>
</button>
<button class="carousel-control-next" type="button" data-bs-target="#productCarousel" data-bs-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="visually-hidden">Next</span>
</button>
{% endif %}
</div>
</div>
<!-- Thumbnails -->
<div class="d-flex gap-2 mt-3 overflow-auto">
{% if product.image %}
<div class="border rounded-3 p-1" style="width: 80px; cursor: pointer;" onclick="bootstrap.Carousel.getOrCreateInstance(document.getElementById('productCarousel')).to(0)">
<img src="{{ product.image.url }}" class="img-fluid rounded-2" alt="Main">
</div>
{% endif %}
{% for img in product.images.all %}
<div class="border rounded-3 p-1" style="width: 80px; cursor: pointer;" onclick="bootstrap.Carousel.getOrCreateInstance(document.getElementById('productCarousel')).to({{ forloop.counter }})">
<img src="{{ img.image.url }}" class="img-fluid rounded-2" alt="Thumb">
</div>
{% endfor %}
</div>
{% endif %}
</div>
<div class="col-md-6">
<h1 class="fw-bold mb-3">{{ product.name }}</h1>
<p class="text-muted mb-4">{{ product.category.name }}</p>
<h2 class="text-primary fw-bold mb-4">{{ product.price }} ETB</h2>
<div class="mb-4">
<h5 class="fw-bold">{% trans "Description" %}</h5>
<p class="text-secondary">{{ product.description }}</p>
</div>
<div class="mb-4 p-3 bg-light rounded">
<h6 class="fw-bold mb-1">{% trans "Sold by" %}: {{ product.vendor.business_name }}</h6>
<p class="small text-muted mb-0">{% trans "Located in" %}: {{ product.vendor.address }}</p>
</div>
<!-- Product Info -->
<div class="col-lg-6">
<div class="ps-lg-4">
<span class="badge bg-light text-primary mb-2 d-inline-block rounded-pill small fw-bold">{{ product.category.name }}</span>
<h1 class="fw-bold mb-3">{{ product.name }}</h1>
<div class="d-flex align-items-center gap-3 mb-4">
<div class="text-warning">
{% with ''|center:5 as range %}
{% for _ in range %}
{% if forloop.counter <= product.average_rating %}
<i class="bi bi-star-fill"></i>
{% elif forloop.counter|add:"-0.5" <= product.average_rating %}
<i class="bi bi-star-half"></i>
{% else %}
<i class="bi bi-star"></i>
{% endif %}
{% endfor %}
{% endwith %}
</div>
<span class="text-secondary small">({{ reviews.count }} {% trans "reviews" %})</span>
<span class="text-success small fw-bold"><i class="bi bi-check-circle-fill me-1"></i>{% trans "In Stock" %} ({{ product.stock }})</span>
</div>
<div class="d-grid gap-2">
<a href="{% url 'cart_add' product.id %}" class="btn btn-primary btn-lg">
{% trans "Add to Cart" %}
</a>
<div class="mb-4">
<span class="display-5 fw-bold text-primary">{{ product.price }}</span>
<span class="h4 text-secondary ms-1">ETB</span>
</div>
<div class="card bg-light border-0 p-4 rounded-4 mb-4">
<h6 class="fw-bold mb-3">{% trans "Description" %}</h6>
<div class="text-secondary">
{{ product.description|linebreaks }}
</div>
</div>
<!-- Add to Cart Form -->
<form action="{% url 'cart_add' product.id %}" method="post" class="mb-5">
{% csrf_token %}
<div class="row g-3">
<div class="col-md-4">
<label class="form-label small fw-bold">{% trans "Quantity" %}</label>
<input type="number" name="quantity" value="1" min="1" max="{{ product.stock }}" class="form-control rounded-pill border-0 shadow-sm px-4">
</div>
<div class="col-md-8 d-flex align-items-end">
<button type="submit" class="btn btn-primary btn-lg w-100 rounded-pill">
<i class="bi bi-cart-plus me-2"></i> {% trans "Add to Cart" %}
</button>
</div>
</div>
</form>
<div class="d-flex flex-wrap gap-4 border-top pt-4">
<div class="d-flex align-items-center">
<div class="bg-primary-subtle p-2 rounded-circle me-3">
<i class="bi bi-shop text-primary"></i>
</div>
<div>
<small class="text-secondary d-block">{% trans "Sold by" %}</small>
<a href="#" class="fw-bold text-dark text-decoration-none">{{ product.vendor.business_name }}</a>
</div>
</div>
<div class="d-flex align-items-center">
<div class="bg-primary-subtle p-2 rounded-circle me-3">
<i class="bi bi-truck text-primary"></i>
</div>
<div>
<small class="text-secondary d-block">{% trans "Delivery" %}</small>
<span class="fw-bold text-dark">{% trans "Free in Jimma" %}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Reviews Section -->
<section class="py-5 bg-white">
<div class="container">
<div class="row">
<div class="col-lg-8">
<h3 class="fw-bold mb-5">{% trans "Customer Reviews" %}</h3>
{% for review in reviews %}
<div class="d-flex mb-5 pb-5 border-bottom">
<div class="flex-shrink-0 me-4">
<div class="bg-primary text-white rounded-circle d-flex align-items-center justify-content-center fw-bold" style="width: 50px; height: 50px;">
{{ review.full_name|slice:":1" }}
</div>
</div>
<div>
<div class="d-flex align-items-center gap-3 mb-2">
<h6 class="fw-bold mb-0">{{ review.full_name }}</h6>
<span class="text-secondary small">{{ review.created_at|date }}</span>
</div>
<div class="text-warning mb-3 small">
{% with ''|center:5 as range %}
{% for _ in range %}
<i class="bi bi-star{% if forloop.counter <= review.rating %}-fill{% endif %}"></i>
{% endfor %}
{% endwith %}
</div>
<p class="text-secondary">{{ review.comment }}</p>
</div>
</div>
{% empty %}
<div class="text-center py-5 bg-light rounded-4 mb-5">
<i class="bi bi-chat-dots display-4 text-secondary mb-3"></i>
<p class="text-secondary">{% trans "No reviews yet. Be the first to review!" %}</p>
</div>
{% endfor %}
</div>
<div class="col-lg-4">
<div class="card border-0 shadow-sm p-4 sticky-top rounded-4" style="top: 100px;">
<h5 class="fw-bold mb-4">{% trans "Add a Review" %}</h5>
<p class="text-secondary small mb-4">{% trans "Share your experience with this product to help other shoppers in Jimma." %}</p>
<form action="{% url 'product_review_submit' product.id %}" method="post">
{% csrf_token %}
<div class="mb-3">
<label class="form-label small fw-bold">{% trans "Rating" %}</label>
<div class="rating-stars text-warning fs-4" style="cursor: pointer;">
<input type="hidden" name="rating" id="id_rating" value="5">
<i class="bi bi-star-fill star-input" data-value="1"></i>
<i class="bi bi-star-fill star-input" data-value="2"></i>
<i class="bi bi-star-fill star-input" data-value="3"></i>
<i class="bi bi-star-fill star-input" data-value="4"></i>
<i class="bi bi-star-fill star-input" data-value="5"></i>
</div>
</div>
{% if not user.is_authenticated %}
<div class="mb-3">
<label class="form-label small fw-bold">{% trans "Full Name" %}</label>
<input type="text" name="full_name" class="form-control rounded-3 border-light" placeholder="{% trans "Your name" %}" required>
</div>
{% endif %}
<div class="mb-4">
<label class="form-label small fw-bold">{% trans "Review" %}</label>
<textarea name="comment" class="form-control rounded-3 border-light" rows="4" placeholder="{% trans "What did you like or dislike?" %}" required></textarea>
</div>
<button type="submit" class="btn btn-primary w-100 rounded-pill">{% trans "Submit Review" %}</button>
</form>
</div>
</div>
</div>
</div>
</section>
<!-- Related Products -->
<section class="py-5">
<div class="container">
<h3 class="fw-bold mb-5">{% trans "You Might Also Like" %}</h3>
<div class="row g-4">
{% for rel in related_products %}
<div class="col-6 col-md-3">
<div class="card h-100 border-0 shadow-sm transition-hover">
{% if rel.image %}
<img src="{{ rel.image.url }}" class="card-img-top p-2 rounded-4" alt="{{ rel.name }}" style="height: 200px; object-fit: cover;">
{% else %}
<div class="card-img-top bg-secondary-subtle d-flex align-items-center justify-content-center m-2 rounded-4" style="height: 200px;">
<i class="bi bi-image fs-4 text-secondary"></i>
</div>
{% endif %}
<div class="card-body pt-0">
<h6 class="fw-bold mb-2">
<a href="{% url 'product_detail' rel.slug %}" class="text-decoration-none text-dark">{{ rel.name }}</a>
</h6>
<div class="text-warning small mb-2">
<i class="bi bi-star-fill"></i> {{ rel.average_rating }}
</div>
<span class="fw-bold text-primary">{{ rel.price }} ETB</span>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
</section>
<script>
document.addEventListener('DOMContentLoaded', function() {
const stars = document.querySelectorAll('.star-input');
const ratingInput = document.getElementById('id_rating');
stars.forEach(star => {
star.addEventListener('click', function() {
const value = this.getAttribute('data-value');
ratingInput.value = value;
stars.forEach(s => {
if (parseInt(s.getAttribute('data-value')) <= parseInt(value)) {
s.classList.remove('bi-star');
s.classList.add('bi-star-fill');
} else {
s.classList.remove('bi-star-fill');
s.classList.add('bi-star');
}
});
});
});
});
</script>
<style>
.transition-hover {
transition: all 0.3s ease;
}
.transition-hover:hover {
transform: translateY(-5px);
}
</style>
{% endblock %}

View File

@ -1,52 +1,155 @@
{% extends "base.html" %}
{% load i18n static %}
{% block title %}{% trans "All Products" %}{% endblock %}
{% block title %}{% trans "Shop All Products" %} | Jimma Market{% endblock %}
{% block content %}
<div class="container py-5">
<div class="row mb-4">
<div class="col-md-8">
<h1 class="fw-bold">{% trans "Our Products" %}</h1>
</div>
<div class="col-md-4">
<form action="{% url 'product_list' %}" method="get" class="d-flex">
<input type="text" name="q" class="form-control me-2" placeholder="{% trans 'Search products...' %}" value="{{ request.GET.q }}">
<button type="submit" class="btn btn-primary">{% trans "Search" %}</button>
</form>
</div>
</div>
<div class="row g-4">
{% for product in products %}
<div class="col-sm-6 col-md-4 col-lg-3">
<div class="card h-100 border-0 shadow-sm">
{% if product.image %}
<img src="{{ product.image.url }}" class="card-img-top" alt="{{ product.name }}" style="height: 200px; object-fit: cover;">
{% else %}
<div class="card-img-top bg-secondary d-flex align-items-center justify-content-center" style="height: 200px;">
<span class="text-white">{% trans "No Image" %}</span>
<section class="py-5 bg-light min-vh-100">
<div class="container">
<div class="row g-4 align-items-center mb-5">
<div class="col-md-6">
<h2 class="fw-bold mb-0">{% trans "Explore Our Shop" %} 🏬</h2>
<p class="text-secondary mb-0">{% trans "Discover the best products from Jimma's finest vendors." %}</p>
</div>
<div class="col-md-6">
<form action="{% url 'product_list' %}" method="get" class="d-flex gap-2">
{% if current_category %}
<input type="hidden" name="category" value="{{ current_category }}">
{% endif %}
{% if current_kebele %}
<input type="hidden" name="kebele" value="{{ current_kebele }}">
{% endif %}
<div class="input-group rounded-pill overflow-hidden border-0 shadow-sm flex-grow-1">
<span class="input-group-text bg-white border-0"><i class="bi bi-search"></i></span>
<input type="text" name="q" value="{{ request.GET.q|default:'' }}" class="form-control border-0 shadow-none px-3" placeholder="{% trans "Search products..." %}">
</div>
<button type="submit" class="btn btn-primary rounded-pill px-4">{% trans "Search" %}</button>
</form>
</div>
</div>
<div class="row g-4">
<!-- Filters Sidebar -->
<div class="col-lg-3">
<div class="card border-0 shadow-sm p-4 rounded-4 sticky-top" style="top: 100px;">
<h5 class="fw-bold mb-4">{% trans "Filters" %}</h5>
<form action="{% url 'product_list' %}" method="get">
{% if request.GET.q %}
<input type="hidden" name="q" value="{{ request.GET.q }}">
{% endif %}
<div class="mb-4">
<label class="form-label small fw-bold">{% trans "Neighborhood (Kebele)" %}</label>
<select name="kebele" onchange="this.form.submit()" class="form-select form-select-sm rounded-3 border-light bg-light">
<option value="">{% trans "All Areas" %}</option>
{% for kebele in kebeles %}
<option value="{{ kebele }}" {% if current_kebele == kebele %}selected{% endif %}>{{ kebele }}</option>
{% endfor %}
</select>
</div>
<div class="mb-4">
<label class="form-label small fw-bold">{% trans "Category" %}</label>
<div class="d-flex flex-column gap-2 mt-2">
<a href="?{% if request.GET.q %}q={{ request.GET.q }}&{% endif %}{% if current_kebele %}kebele={{ current_kebele }}&{% endif %}" class="text-decoration-none {% if not current_category %}fw-bold text-primary{% else %}text-secondary{% endif %} small">
{% trans "All Categories" %}
</a>
{% for cat in categories %}
<a href="?category={{ cat.slug }}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}{% if current_kebele %}&kebele={{ current_kebele }}{% endif %}" class="text-decoration-none {% if current_category == cat.slug %}fw-bold text-primary{% else %}text-secondary{% endif %} small">
{{ cat.name }}
</a>
{% endfor %}
</div>
</div>
<div class="mb-4">
<label class="form-label small fw-bold">{% trans "Sort By" %}</label>
<select name="sort" onchange="this.form.submit()" class="form-select form-select-sm rounded-3 border-light bg-light">
<option value="newest" {% if current_sort == 'newest' %}selected{% endif %}>{% trans "Newest Arrivals" %}</option>
<option value="price_low" {% if current_sort == 'price_low' %}selected{% endif %}>{% trans "Price: Low to High" %}</option>
<option value="price_high" {% if current_sort == 'price_high' %}selected{% endif %}>{% trans "Price: High to Low" %}</option>
</select>
</div>
<div class="pt-3 border-top mt-4">
<button type="button" class="btn btn-outline-dark btn-sm w-100 rounded-pill" onclick="window.location.href='{% url 'product_list' %}'">
{% trans "Clear All Filters" %}
</button>
</div>
</form>
</div>
</div>
<!-- Products Grid -->
<div class="col-lg-9">
{% if current_kebele %}
<div class="alert alert-primary bg-primary-subtle border-0 rounded-4 mb-4 d-flex align-items-center">
<i class="bi bi-geo-alt-fill me-2 fs-5"></i>
<div>
{% trans "Showing products from vendors in" %} <strong>{{ current_kebele }}</strong>
</div>
<a href="?{% if request.GET.q %}q={{ request.GET.q }}&{% endif %}{% if current_category %}category={{ current_category }}&{% endif %}" class="btn-close ms-auto" aria-label="Close"></a>
</div>
{% endif %}
<div class="card-body">
<p class="text-muted small mb-1">{{ product.category.name }}</p>
<h5 class="card-title h6 mb-2">
<a href="{% url 'product_detail' product.slug %}" class="text-decoration-none text-dark">
{{ product.name }}
</a>
</h5>
<p class="fw-bold text-primary mb-3">{{ product.price }} ETB</p>
<a href="{% url 'cart_add' product.id %}" class="btn btn-outline-primary btn-sm w-100">
{% trans "Add to Cart" %}
</a>
<div class="row g-4">
{% for product in products %}
<div class="col-sm-6 col-md-4">
<div class="card h-100 border-0 shadow-sm position-relative hover-lift transition-hover">
{% if product.image %}
<img src="{{ product.image.url }}" class="card-img-top p-2 rounded-4" alt="{{ product.name }}" style="height: 200px; object-fit: cover;">
{% else %}
<div class="card-img-top bg-secondary-subtle d-flex align-items-center justify-content-center m-2 rounded-4" style="height: 200px;">
<i class="bi bi-image fs-1 text-secondary"></i>
</div>
{% endif %}
<div class="card-body pt-0">
<div class="d-flex justify-content-between align-items-start mb-2">
<span class="badge bg-light text-primary d-inline-block rounded-pill small fw-bold">{{ product.category.name }}</span>
{% if product.review_count > 0 %}
<div class="text-warning small">
<i class="bi bi-star-fill"></i> {{ product.average_rating }}
</div>
{% endif %}
</div>
<h6 class="fw-bold mb-2">
<a href="{% url 'product_detail' product.slug %}" class="text-decoration-none text-dark">
{{ product.name }}
</a>
</h6>
<div class="mb-2">
<small class="text-muted"><i class="bi bi-shop me-1"></i>{{ product.vendor.business_name }}</small>
<br>
<small class="text-muted small"><i class="bi bi-geo-alt me-1"></i>{{ product.vendor.kebele }}</small>
</div>
<div class="d-flex justify-content-between align-items-center mt-auto">
<span class="fw-bold text-primary">{{ product.price }} ETB</span>
<a href="{% url 'cart_add' product.id %}" class="btn btn-dark btn-sm rounded-pill px-3">
<i class="bi bi-plus-lg"></i>
</a>
</div>
</div>
</div>
</div>
{% empty %}
<div class="col-12 text-center py-5 bg-white rounded-5 shadow-sm">
<i class="bi bi-search display-1 text-secondary opacity-50 mb-4"></i>
<h4 class="fw-bold">{% trans "No products found" %}</h4>
<p class="text-secondary">{% trans "Try adjusting your filters or search query." %}</p>
<a href="{% url 'product_list' %}" class="btn btn-primary rounded-pill px-4 mt-3">{% trans "Clear Filters" %}</a>
</div>
{% endfor %}
</div>
</div>
</div>
{% empty %}
<div class="col-12 text-center py-5">
<p class="text-muted">{% trans "No products found matching your search." %}</p>
</div>
{% endfor %}
</div>
</div>
</section>
<style>
.transition-hover:hover {
transform: translateY(-5px);
box-shadow: 0 1rem 3rem rgba(0,0,0,.1) !important;
}
</style>
{% endblock %}

View File

@ -0,0 +1,153 @@
{% extends 'base.html' %}
{% load i18n %}
{% load static %}
{% block content %}
<div class="bg-primary-subtle py-5 mb-5">
<div class="container py-lg-5">
<div class="row align-items-center">
<div class="col-lg-6">
<h1 class="display-3 fw-bold mb-4">{% trans "Grow Your Business in Jimma" %}</h1>
<p class="lead mb-4">
{% trans "Join Jimma Market and start selling your products to thousands of customers across the city today." %}
</p>
<div class="d-flex gap-3">
<a href="{% url 'vendor_register' %}" class="btn btn-primary btn-lg px-5 py-3 rounded-pill fw-bold">{% trans "Register Now" %}</a>
<a href="#benefits" class="btn btn-outline-primary btn-lg px-5 py-3 rounded-pill fw-bold">{% trans "Learn More" %}</a>
</div>
</div>
<div class="col-lg-6 d-none d-lg-block">
<img src="https://images.pexels.com/photos/5920775/pexels-photo-5920775.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1" alt="Seller Success" class="img-fluid rounded-4 shadow-lg">
</div>
</div>
</div>
</div>
<div class="container pb-5" id="benefits">
<!-- Stats Section -->
<div class="row g-4 mb-5 text-center">
<div class="col-md-4">
<div class="p-4 border rounded-4 bg-white shadow-sm">
<div class="h2 fw-bold text-primary mb-1">500+</div>
<div class="text-muted text-uppercase small tracking-widest">{% trans "Active Sellers" %}</div>
</div>
</div>
<div class="col-md-4">
<div class="p-4 border rounded-4 bg-white shadow-sm">
<div class="h2 fw-bold text-primary mb-1">10,000+</div>
<div class="text-muted text-uppercase small tracking-widest">{% trans "Customers" %}</div>
</div>
</div>
<div class="col-md-4">
<div class="p-4 border rounded-4 bg-white shadow-sm">
<div class="h2 fw-bold text-primary mb-1">24/7</div>
<div class="text-muted text-uppercase small tracking-widest">{% trans "Support" %}</div>
</div>
</div>
</div>
<!-- Benefits Section -->
<h2 class="text-center fw-bold mb-5">{% trans "Why Sell on Jimma Market?" %}</h2>
<div class="row g-4 mb-5">
<div class="col-md-4">
<div class="card h-100 border-0 shadow-sm p-4">
<div class="bg-primary-subtle text-primary rounded-3 d-flex align-items-center justify-content-center mb-4" style="width: 60px; height: 60px;">
<i class="bi bi-graph-up-arrow fs-3"></i>
</div>
<h4 class="fw-bold">{% trans "Increase Sales" %}</h4>
<p class="text-muted mb-0">{% trans "Reach customers outside your immediate neighborhood. Your shop will be open 24/7 to everyone in Jimma." %}</p>
</div>
</div>
<div class="col-md-4">
<div class="card h-100 border-0 shadow-sm p-4">
<div class="bg-success-subtle text-success rounded-3 d-flex align-items-center justify-content-center mb-4" style="width: 60px; height: 60px;">
<i class="bi bi-truck fs-3"></i>
</div>
<h4 class="fw-bold">{% trans "Hassle-Free Logistics" %}</h4>
<p class="text-muted mb-0">{% trans "Focus on your products; we handle the delivery. Our riders pick up from your shop and deliver to the customer." %}</p>
</div>
</div>
<div class="col-md-4">
<div class="card h-100 border-0 shadow-sm p-4">
<div class="bg-warning-subtle text-warning rounded-3 d-flex align-items-center justify-content-center mb-4" style="width: 60px; height: 60px;">
<i class="bi bi-megaphone fs-3"></i>
</div>
<h4 class="fw-bold">{% trans "Free Marketing" %}</h4>
<p class="text-muted mb-0">{% trans "We promote your products on social media and our app, giving your brand the visibility it deserves in Jimma." %}</p>
</div>
</div>
</div>
<!-- How to become a seller -->
<div class="row align-items-center py-5">
<div class="col-lg-6 order-lg-2 mb-4 mb-lg-0">
<h2 class="fw-bold mb-4">{% trans "Become a Seller in 3 Simple Steps" %}</h2>
<div class="space-y-4">
<div class="d-flex mb-4">
<div class="flex-shrink-0 me-3">
<div class="bg-dark text-white rounded-circle d-flex align-items-center justify-content-center fw-bold" style="width: 32px; height: 32px;">1</div>
</div>
<div>
<h5 class="fw-bold mb-1">{% trans "Sign Up" %}</h5>
<p class="text-muted">{% trans "Create a seller account with your business details and contact information." %}</p>
</div>
</div>
<div class="d-flex mb-4">
<div class="flex-shrink-0 me-3">
<div class="bg-dark text-white rounded-circle d-flex align-items-center justify-content-center fw-bold" style="width: 32px; height: 32px;">2</div>
</div>
<div>
<h5 class="fw-bold mb-1">{% trans "Upload Products" %}</h5>
<p class="text-muted">{% trans "Add photos and descriptions of your products. Our team will verify and approve them quickly." %}</p>
</div>
</div>
<div class="d-flex">
<div class="flex-shrink-0 me-3">
<div class="bg-dark text-white rounded-circle d-flex align-items-center justify-content-center fw-bold" style="width: 32px; height: 32px;">3</div>
</div>
<div>
<h5 class="fw-bold mb-1">{% trans "Start Earning" %}</h5>
<p class="text-muted">{% trans "Receive orders, package the items, and hand them over to our rider. We transfer your earnings weekly." %}</p>
</div>
</div>
</div>
<div class="mt-5">
<a href="{% url 'vendor_register' %}" class="btn btn-primary btn-lg px-4">{% trans "Start Selling Now" %}</a>
</div>
</div>
<div class="col-lg-6 order-lg-1">
<div class="bg-light p-4 rounded-4">
<h4 class="fw-bold mb-4">{% trans "Simple Commission Structure" %}</h4>
<table class="table table-borderless align-middle">
<tbody>
<tr class="border-bottom">
<td class="py-3">
<h6 class="mb-0 fw-bold">{% trans "Registration Fee" %}</h6>
<p class="small text-muted mb-0">{% trans "Start for free" %}</p>
</td>
<td class="py-3 text-end text-success fw-bold">{% trans "0 ETB" %}</td>
</tr>
<tr class="border-bottom">
<td class="py-3">
<h6 class="mb-0 fw-bold">{% trans "Monthly Subscription" %}</h6>
<p class="small text-muted mb-0">{% trans "No fixed costs" %}</p>
</td>
<td class="py-3 text-end text-success fw-bold">{% trans "0 ETB" %}</td>
</tr>
<tr>
<td class="py-3">
<h6 class="mb-0 fw-bold">{% trans "Sales Commission" %}</h6>
<p class="small text-muted mb-0">{% trans "Only pay when you sell" %}</p>
</td>
<td class="py-3 text-end text-primary fw-bold">{% trans "5% - 15%" %}</td>
</tr>
</tbody>
</table>
<p class="small text-muted mt-3 mb-0">
* {% trans "Commission varies by category. Contact us for bulk or special category rates." %}
</p>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,91 @@
{% extends 'base.html' %}
{% load i18n %}
{% load static %}
{% block content %}
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-lg-6">
<div class="text-center mb-5">
<h1 class="fw-bold">{% trans "Track Your Order" %}</h1>
<p class="text-muted">{% trans "Enter your order details below to see the current status of your delivery in Jimma." %}</p>
</div>
<div class="card border-0 shadow-sm p-4 p-lg-5 rounded-4 mb-5">
<form method="POST">
{% csrf_token %}
<div class="mb-4">
<label class="form-label fw-bold small">{% trans "Order ID" %}</label>
<input type="text" name="order_id" class="form-control bg-light border-0 py-3" placeholder="e.g. 1045" required>
</div>
<div class="mb-4">
<label class="form-label fw-bold small">{% trans "Phone Number" %}</label>
<input type="tel" name="phone" class="form-control bg-light border-0 py-3" placeholder="+251 ..." required>
</div>
<button type="submit" class="btn btn-primary btn-lg w-100 py-3 fw-bold rounded-3">{% trans "Check Status" %}</button>
</form>
</div>
{% if order %}
<div class="card border-primary border-2 shadow-lg p-4 p-lg-5 rounded-4 animate__animated animate__fadeIn">
<div class="d-flex justify-content-between align-items-center mb-4">
<h3 class="fw-bold mb-0">{% trans "Order" %} #{{ order.id }}</h3>
<span class="badge bg-primary fs-6 px-3">
{% if order.status == 'pending' %}{% trans "Pending" %}
{% elif order.status == 'processing' %}{% trans "Processing" %}
{% elif order.status == 'shipped' %}{% trans "In Transit" %}
{% elif order.status == 'delivered' %}{% trans "Delivered" %}
{% else %}{{ order.status|capfirst }}{% endif %}
</span>
</div>
<div class="timeline-status mb-5">
<div class="d-flex justify-content-between position-relative">
<div class="text-center" style="z-index: 1;">
<div class="bg-primary text-white rounded-circle d-flex align-items-center justify-content-center mx-auto mb-2" style="width: 40px; height: 40px;">
<i class="bi bi-receipt"></i>
</div>
<small class="fw-bold">{% trans "Placed" %}</small>
</div>
<div class="text-center" style="z-index: 1;">
<div class="{% if order.status != 'pending' %}bg-primary{% else %}bg-secondary{% endif %} text-white rounded-circle d-flex align-items-center justify-content-center mx-auto mb-2" style="width: 40px; height: 40px;">
<i class="bi bi-box-seam"></i>
</div>
<small class="fw-bold">{% trans "Packaged" %}</small>
</div>
<div class="text-center" style="z-index: 1;">
<div class="{% if order.status == 'shipped' or order.status == 'delivered' %}bg-primary{% else %}bg-secondary{% endif %} text-white rounded-circle d-flex align-items-center justify-content-center mx-auto mb-2" style="width: 40px; height: 40px;">
<i class="bi bi-truck"></i>
</div>
<small class="fw-bold">{% trans "In Transit" %}</small>
</div>
<div class="text-center" style="z-index: 1;">
<div class="{% if order.status == 'delivered' %}bg-primary{% else %}bg-secondary{% endif %} text-white rounded-circle d-flex align-items-center justify-content-center mx-auto mb-2" style="width: 40px; height: 40px;">
<i class="bi bi-house-check"></i>
</div>
<small class="fw-bold">{% trans "Delivered" %}</small>
</div>
<!-- Line -->
<div class="position-absolute top-50 start-0 translate-middle-y w-100 bg-light" style="height: 2px; z-index: 0;"></div>
</div>
</div>
<div class="bg-light p-4 rounded-3">
<h6 class="fw-bold mb-3">{% trans "Delivery Details" %}</h6>
<p class="mb-1 small"><strong>{% trans "Customer:" %}</strong> {{ order.full_name }}</p>
<p class="mb-1 small"><strong>{% trans "Kebele:" %}</strong> {{ order.get_kebele_display }}</p>
<p class="mb-1 small"><strong>{% trans "Address:" %}</strong> {{ order.address }}</p>
<p class="mb-0 small"><strong>{% trans "Time Slot:" %}</strong> {{ order.get_delivery_time_slot_display }}</p>
</div>
</div>
{% endif %}
</div>
</div>
</div>
<style>
.timeline-status {
padding: 0 10px;
}
</style>
{% endblock %}

View File

@ -1,128 +1,242 @@
{% extends "base.html" %}
{% load i18n static %}
{% extends 'base.html' %}
{% load static %}
{% block title %}{% trans "Vendor Dashboard" %}{% endblock %}
{% block title %}Vendor Dashboard - {{ vendor.business_name }}{% endblock %}
{% block content %}
<div class="container py-5">
<div class="d-flex justify-content-between align-items-center mb-5">
<div>
<h1 class="fw-bold mb-1">{{ vendor.business_name }}</h1>
<p class="text-muted mb-0">{% trans "Manage your products and orders" %}</p>
<div class="row mb-5 align-items-center">
<div class="col-md-8">
<h1 class="fw-bold mb-0">Welcome, {{ vendor.business_name }}</h1>
<p class="text-muted">Manage your products and track your orders from one place.</p>
</div>
<div class="col-md-4 text-md-end">
<a href="{% url 'vendor_product_add' %}" class="btn btn-primary rounded-pill px-4">
<i class="bi bi-plus-lg me-2"></i> Add New Product
</a>
</div>
</div>
<a href="{% url 'admin:core_product_add' %}" class="btn btn-primary">
<i class="bi bi-plus-lg"></i> {% trans "Add New Product" %}
</a>
</div>
<div class="row g-4">
<!-- Products Summary -->
<div class="col-md-4">
<div class="card border-0 shadow-sm p-4 text-center">
<h6 class="text-muted text-uppercase small fw-bold mb-2">{% trans "Total Products" %}</h6>
<h2 class="fw-bold mb-0">{{ products.count }}</h2>
</div>
<!-- Stats Row -->
<div class="row g-4 mb-5">
<div class="col-md-3">
<div class="card border-0 shadow-sm p-4">
<div class="d-flex align-items-center">
<div class="bg-primary-subtle text-primary rounded-circle p-3 me-3">
<i class="bi bi-box-seam fs-4"></i>
</div>
<div>
<h3 class="fw-bold mb-0">{{ products.count }}</h3>
<small class="text-muted">Active Products</small>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card border-0 shadow-sm p-4">
<div class="d-flex align-items-center">
<div class="bg-success-subtle text-success rounded-circle p-3 me-3">
<i class="bi bi-cart-check fs-4"></i>
</div>
<div>
<h3 class="fw-bold mb-0">{{ order_items.count }}</h3>
<small class="text-muted">Total Sales</small>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card border-0 shadow-sm p-4">
<div class="d-flex align-items-center">
<div class="bg-warning-subtle text-warning rounded-circle p-3 me-3">
<i class="bi bi-clock-history fs-4"></i>
</div>
<div>
<h3 class="fw-bold mb-0">{% if not vendor.is_verified %}Pending{% else %}Verified{% endif %}</h3>
<small class="text-muted">Account Status</small>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card border-0 shadow-sm p-4">
<div class="d-flex align-items-center">
<div class="bg-info-subtle text-info rounded-circle p-3 me-3">
<i class="bi bi-geo-alt fs-4"></i>
</div>
<div>
<h6 class="fw-bold mb-0 text-truncate">{{ vendor.address }}</h6>
<small class="text-muted">Business Location</small>
</div>
</div>
</div>
</div>
</div>
<!-- Orders Summary -->
<div class="col-md-4">
<div class="card border-0 shadow-sm p-4 text-center">
<h6 class="text-muted text-uppercase small fw-bold mb-2">{% trans "Total Orders" %}</h6>
<h2 class="fw-bold mb-0">{{ orders.count }}</h2>
</div>
</div>
<!-- Status -->
<div class="col-md-4">
<div class="card border-0 shadow-sm p-4 text-center">
<h6 class="text-muted text-uppercase small fw-bold mb-2">{% trans "Status" %}</h6>
{% if vendor.is_verified %}
<span class="badge bg-success py-2 px-3">{% trans "Verified" %}</span>
{% else %}
<span class="badge bg-warning text-dark py-2 px-3">{% trans "Pending Verification" %}</span>
{% endif %}
</div>
</div>
</div>
<div class="mt-5">
<ul class="nav nav-tabs mb-4" id="dashboardTabs" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="products-tab" data-bs-toggle="tab" data-bs-target="#products" type="button" role="tab">{% trans "Your Products" %}</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="orders-tab" data-bs-toggle="tab" data-bs-target="#orders" type="button" role="tab">{% trans "Recent Orders" %}</button>
</li>
<!-- Tabs for Products and Orders -->
<ul class="nav nav-tabs border-0 mb-4" id="dashboardTabs" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active fw-bold border-0 bg-transparent text-dark px-4 py-3 border-bottom-primary" id="products-tab" data-bs-toggle="tab" data-bs-target="#products" type="button" role="tab">
My Products
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link fw-bold border-0 bg-transparent text-dark px-4 py-3" id="orders-tab" data-bs-toggle="tab" data-bs-target="#orders" type="button" role="tab">
Recent Orders
</button>
</li>
</ul>
<div class="tab-content" id="dashboardTabsContent">
<div class="tab-pane fade show active" id="products" role="tabpanel">
<div class="table-responsive">
<table class="table align-middle">
<thead>
<tr>
<th>{% trans "Product" %}</th>
<th>{% trans "Category" %}</th>
<th>{% trans "Price" %}</th>
<th>{% trans "Status" %}</th>
<th>{% trans "Actions" %}</th>
</tr>
</thead>
<tbody>
{% for product in products %}
<tr>
<td>{{ product.name }}</td>
<td>{{ product.category.name }}</td>
<td>{{ product.price }} ETB</td>
<td>
{% if product.is_available %}
<span class="badge bg-success">{% trans "Available" %}</span>
{% else %}
<span class="badge bg-danger">{% trans "Out of Stock" %}</span>
{% endif %}
</td>
<td>
<a href="{% url 'admin:core_product_change' product.id %}" class="btn btn-sm btn-outline-secondary">{% trans "Edit" %}</a>
</td>
</tr>
{% empty %}
<tr>
<td colspan="5" class="text-center py-4">{% trans "No products found." %}</td>
</tr>
{% endfor %}
</tbody>
</table>
<!-- Products Tab -->
<div class="tab-pane fade show active" id="products" role="tabpanel">
<div class="card border-0 shadow-sm overflow-hidden">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="bg-light text-muted small text-uppercase">
<tr>
<th class="px-4 py-3">Product</th>
<th class="py-3">Category</th>
<th class="py-3">Price</th>
<th class="py-3">Stock</th>
<th class="py-3">Status</th>
<th class="py-3 text-end px-4">Actions</th>
</tr>
</thead>
<tbody>
{% for product in products %}
<tr>
<td class="px-4 py-3">
<div class="d-flex align-items-center">
{% if product.image %}
<img src="{{ product.image.url }}" alt="{{ product.name }}" class="rounded-3 me-3" style="width: 48px; height: 48px; object-fit: cover;">
{% else %}
<div class="bg-light rounded-3 me-3 d-flex align-items-center justify-content-center" style="width: 48px; height: 48px;">
<i class="bi bi-image text-muted"></i>
</div>
{% endif %}
<div>
<h6 class="fw-bold mb-0">{{ product.name }}</h6>
<small class="text-muted">Added {{ product.created_at|date:"M d, Y" }}</small>
</div>
</div>
</td>
<td class="py-3 text-muted">{{ product.category.name }}</td>
<td class="py-3 fw-bold text-primary">{{ product.price }} ETB</td>
<td class="py-3">
<span class="badge {% if product.stock > 10 %}bg-success-subtle text-success{% elif product.stock > 0 %}bg-warning-subtle text-warning{% else %}bg-danger-subtle text-danger{% endif %} rounded-pill px-3">
{{ product.stock }} in stock
</span>
</td>
<td class="py-3">
{% if product.is_available %}
<span class="badge bg-success rounded-pill px-2">Visible</span>
{% else %}
<span class="badge bg-secondary rounded-pill px-2">Hidden</span>
{% endif %}
</td>
<td class="py-3 text-end px-4">
<div class="btn-group">
<a href="{% url 'vendor_product_edit' product.pk %}" class="btn btn-outline-secondary btn-sm rounded-pill px-3 me-2">
<i class="bi bi-pencil me-1"></i> Edit
</a>
<a href="{% url 'vendor_product_delete' product.pk %}" class="btn btn-outline-danger btn-sm rounded-pill px-3">
<i class="bi bi-trash"></i>
</a>
</div>
</td>
</tr>
{% empty %}
<tr>
<td colspan="6" class="text-center py-5">
<div class="mb-3 text-muted">
<i class="bi bi-box-seam display-1"></i>
</div>
<h5>No products added yet</h5>
<p class="text-muted">Start selling by adding your first product to the marketplace.</p>
<a href="{% url 'vendor_product_add' %}" class="btn btn-primary rounded-pill">Add Product</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class="tab-pane fade" id="orders" role="tabpanel">
<div class="table-responsive">
<table class="table align-middle">
<thead>
<tr>
<th>{% trans "Order ID" %}</th>
<th>{% trans "Product" %}</th>
<th>{% trans "Customer" %}</th>
<th>{% trans "Total" %}</th>
<th>{% trans "Status" %}</th>
</tr>
</thead>
<tbody>
{% for item in orders %}
<tr>
<td>#{{ item.order.id }}</td>
<td>{{ item.product.name }}</td>
<td>{{ item.order.full_name }}</td>
<td>{{ item.total_price }} ETB</td>
<td>{{ item.order.status }}</td>
</tr>
{% empty %}
<tr>
<td colspan="5" class="text-center py-4">{% trans "No orders found." %}</td>
</tr>
{% endfor %}
</tbody>
</table>
<!-- Orders Tab -->
<div class="tab-pane fade" id="orders" role="tabpanel">
<div class="card border-0 shadow-sm overflow-hidden">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="bg-light text-muted small text-uppercase">
<tr>
<th class="px-4 py-3">Order ID</th>
<th class="py-3">Customer</th>
<th class="py-3">Product</th>
<th class="py-3">Total</th>
<th class="py-3">Status</th>
<th class="py-3 text-end px-4">Update Status</th>
</tr>
</thead>
<tbody>
{% for item in order_items %}
<tr>
<td class="px-4 py-3 fw-bold">#ORD-{{ item.order.id }}</td>
<td class="py-3">
<div class="fw-bold">{{ item.order.full_name }}</div>
<small class="text-muted">{{ item.order.phone }}</small>
</td>
<td class="py-3">
<div class="text-truncate" style="max-width: 200px;">{{ item.product.name }}</div>
<small class="text-muted">Qty: {{ item.quantity }}</small>
</td>
<td class="py-3 fw-bold text-primary">{{ item.total_price }} ETB</td>
<td class="py-3">
<span class="badge rounded-pill px-3 {% if item.order.status == 'Delivered' %}bg-success{% elif item.order.status == 'Processing' %}bg-info{% elif item.order.status == 'Shipped' %}bg-primary{% elif item.order.status == 'Cancelled' %}bg-danger{% else %}bg-warning{% endif %}">
{{ item.order.status }}
</span>
</td>
<td class="py-3 text-end px-4">
<form action="{% url 'vendor_order_status_update' item.order.id %}" method="POST" class="d-inline-flex gap-2">
{% csrf_token %}
<select name="status" class="form-select form-select-sm rounded-pill" style="width: auto;">
<option value="Pending" {% if item.order.status == 'Pending' %}selected{% endif %}>Pending</option>
<option value="Processing" {% if item.order.status == 'Processing' %}selected{% endif %}>Processing</option>
<option value="Shipped" {% if item.order.status == 'Shipped' %}selected{% endif %}>Shipped</option>
<option value="Delivered" {% if item.order.status == 'Delivered' %}selected{% endif %}>Delivered</option>
<option value="Cancelled" {% if item.order.status == 'Cancelled' %}selected{% endif %}>Cancelled</option>
</select>
<button type="submit" class="btn btn-sm btn-dark rounded-pill px-3">Update</button>
</form>
</td>
</tr>
{% empty %}
<tr>
<td colspan="6" class="text-center py-5">
<div class="mb-3 text-muted">
<i class="bi bi-cart-x display-1"></i>
</div>
<h5>No orders yet</h5>
<p class="text-muted">Once customers purchase your products, they will appear here.</p>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
<style>
.border-bottom-primary {
border-bottom: 3px solid #0d6efd !important;
}
.nav-tabs .nav-link:hover {
border-color: transparent;
color: #0d6efd !important;
}
</style>
{% endblock %}

View File

@ -0,0 +1,34 @@
{% extends 'base.html' %}
{% block title %}Delete Product - {{ product.name }}{% endblock %}
{% block content %}
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card border-0 shadow-sm rounded-4 text-center p-5">
<div class="mb-4">
<div class="bg-danger-subtle text-danger rounded-circle p-4 d-inline-block">
<i class="bi bi-exclamation-triangle display-4"></i>
</div>
</div>
<h2 class="fw-bold mb-3">Delete Product?</h2>
<p class="text-muted mb-5">
Are you sure you want to delete <strong>{{ product.name }}</strong>? This action cannot be undone and will remove the product from the marketplace.
</p>
<form method="POST">
{% csrf_token %}
<div class="d-grid gap-3">
<button type="submit" class="btn btn-danger rounded-pill py-3 fw-bold">
Yes, Delete Permanently
</button>
<a href="{% url 'vendor_dashboard' %}" class="btn btn-light rounded-pill py-3 fw-bold">
No, Keep Product
</a>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,132 @@
{% extends 'base.html' %}
{% block title %}{{ title }} - Jimma Market{% endblock %}
{% block content %}
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-lg-8">
<div class="card border-0 shadow-sm rounded-4">
<div class="card-body p-5">
<nav aria-label="breadcrumb" class="mb-4">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="{% url 'vendor_dashboard' %}" class="text-decoration-none">Dashboard</a></li>
<li class="breadcrumb-item active" aria-current="page">{{ title }}</li>
</ol>
</nav>
<h2 class="fw-bold mb-4 text-center">{{ title }}</h2>
<p class="text-muted text-center mb-5">Provide accurate details for your product to attract more customers.</p>
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<div class="row g-4">
<!-- Product Name -->
<div class="col-12">
<label class="form-label fw-bold small text-uppercase">Product Name</label>
{{ form.name }}
{% if form.name.errors %}
<div class="text-danger small mt-1">{{ form.name.errors }}</div>
{% endif %}
</div>
<!-- Category -->
<div class="col-md-6">
<label class="form-label fw-bold small text-uppercase">Category</label>
{{ form.category }}
{% if form.category.errors %}
<div class="text-danger small mt-1">{{ form.category.errors }}</div>
{% endif %}
</div>
<!-- Price -->
<div class="col-md-6">
<label class="form-label fw-bold small text-uppercase">Price (ETB)</label>
<div class="input-group">
<span class="input-group-text bg-light border-end-0">ETB</span>
{{ form.price }}
</div>
{% if form.price.errors %}
<div class="text-danger small mt-1">{{ form.price.errors }}</div>
{% endif %}
</div>
<!-- Stock -->
<div class="col-md-6">
<label class="form-label fw-bold small text-uppercase">Stock Quantity</label>
{{ form.stock }}
{% if form.stock.errors %}
<div class="text-danger small mt-1">{{ form.stock.errors }}</div>
{% endif %}
</div>
<!-- Image -->
<div class="col-md-6">
<label class="form-label fw-bold small text-uppercase">Product Image</label>
{{ form.image }}
{% if form.image.errors %}
<div class="text-danger small mt-1">{{ form.image.errors }}</div>
{% endif %}
<div class="form-text small">Recommended size: 800x800px</div>
</div>
<!-- Description -->
<div class="col-12">
<label class="form-label fw-bold small text-uppercase">Description</label>
{{ form.description }}
{% if form.description.errors %}
<div class="text-danger small mt-1">{{ form.description.errors }}</div>
{% endif %}
</div>
<!-- Availability -->
<div class="col-12">
<div class="form-check form-switch p-3 bg-light rounded-3 d-flex align-items-center">
<div class="flex-grow-1">
<label class="form-check-label fw-bold mb-0" for="{{ form.is_available.id_for_label }}">Available for Sale</label>
<div class="form-text small mt-0">Toggle off to temporarily hide this product from customers.</div>
</div>
<div class="ms-3">
{{ form.is_available }}
</div>
</div>
</div>
<!-- Buttons -->
<div class="col-12 mt-5">
<div class="d-flex gap-3">
<button type="submit" class="btn btn-primary rounded-pill px-5 py-3 fw-bold flex-grow-1">
Save Product
</button>
<a href="{% url 'vendor_dashboard' %}" class="btn btn-light rounded-pill px-4 py-3 fw-bold">
Cancel
</a>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<style>
.form-control, .form-select {
padding: 0.75rem 1rem;
border-radius: 10px;
border: 1px solid #dee2e6;
}
.form-control:focus, .form-select:focus {
border-color: #0d6efd;
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.1);
}
.input-group-text {
border-radius: 10px 0 0 10px;
}
.input-group .form-control {
border-radius: 0 10px 10px 0;
}
</style>
{% endblock %}

View File

@ -7,38 +7,48 @@
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-md-8 col-lg-6">
<div class="card border-0 shadow-sm p-4 p-md-5">
<div class="card border-0 shadow-sm p-4 p-md-5 rounded-4">
<h1 class="fw-bold text-center mb-4">{% trans "Register as a Vendor" %}</h1>
<p class="text-center text-muted mb-5">{% trans "Join our community and start selling your products to thousands of customers." %}</p>
<form action="{% url 'vendor_register' %}" method="post">
{% csrf_token %}
<div class="mb-3">
<label for="business_name" class="form-label">{% trans "Business Name" %}</label>
<input type="text" class="form-control" id="business_name" name="business_name" required>
<label for="business_name" class="form-label fw-bold small">{% trans "Business Name" %}</label>
<input type="text" class="form-control bg-light border-0 py-2" id="business_name" name="business_name" placeholder="{% trans 'e.g. Jimma Tech Hub' %}" required>
</div>
<div class="mb-3">
<label for="phone" class="form-label">{% trans "Business Phone" %}</label>
<input type="text" class="form-control" id="phone" name="phone" required>
<label for="phone" class="form-label fw-bold small">{% trans "Business Phone" %}</label>
<input type="text" class="form-control bg-light border-0 py-2" id="phone" name="phone" placeholder="{% trans 'e.g. 0911223344' %}" required>
</div>
<div class="mb-3">
<label for="address" class="form-label">{% trans "Business Address" %}</label>
<input type="text" class="form-control" id="address" name="address" required>
<label for="kebele" class="form-label fw-bold small">{% trans "Neighborhood (Kebele)" %}</label>
<select class="form-select bg-light border-0 py-2" id="kebele" name="kebele" required>
<option value="">{% trans "Select your Kebele" %}</option>
{% for code, name in kebeles %}
<option value="{{ code }}">{{ name }}</option>
{% endfor %}
</select>
</div>
<div class="mb-3">
<label for="address" class="form-label fw-bold small">{% trans "Specific Address" %}</label>
<input type="text" class="form-control bg-light border-0 py-2" id="address" name="address" placeholder="{% trans 'e.g. Near Hotel Central' %}" required>
</div>
<div class="mb-4">
<label for="description" class="form-label">{% trans "Business Description" %}</label>
<textarea class="form-control" id="description" name="description" rows="4"></textarea>
<label for="description" class="form-label fw-bold small">{% trans "Business Description" %}</label>
<textarea class="form-control bg-light border-0" id="description" name="description" rows="4" placeholder="{% trans 'Tell us about your products and services...' %}"></textarea>
</div>
<div class="d-grid">
<button type="submit" class="btn btn-primary btn-lg">{% trans "Submit Application" %}</button>
<button type="submit" class="btn btn-primary btn-lg rounded-pill fw-bold">{% trans "Submit Application" %}</button>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock %}
{% endblock %}

View File

@ -0,0 +1,63 @@
{% extends "base.html" %}
{% load i18n %}
{% block title %}{% trans "Login" %} | Jimma Market{% endblock %}
{% block content %}
<section class="py-5 bg-light min-vh-100 d-flex align-items-center">
<div class="container">
<div class="row justify-content-center">
<div class="col-md-5">
<div class="card border-0 shadow-lg rounded-4 overflow-hidden">
<div class="bg-primary p-4 text-white text-center">
<i class="bi bi-shop-window fs-1 mb-2"></i>
<h3 class="fw-bold mb-0">{% trans "Welcome Back!" %}</h3>
<p class="small opacity-75 mb-0">{% trans "Login to your Jimma Market account" %}</p>
</div>
<div class="card-body p-4 p-md-5 bg-white">
{% if form.errors %}
<div class="alert alert-danger border-0 rounded-3 small">
{% trans "Your username and password didn't match. Please try again." %}
</div>
{% endif %}
<form method="post" action="{% url 'login' %}">
{% csrf_token %}
<div class="mb-4">
<label for="id_username" class="form-label small fw-bold">{% trans "Username" %}</label>
<div class="input-group">
<span class="input-group-text bg-light border-0"><i class="bi bi-person"></i></span>
<input type="text" name="username" autofocus maxlength="150" required id="id_username" class="form-control bg-light border-0 shadow-none px-3 py-2" placeholder="{% trans "Enter your username" %}">
</div>
</div>
<div class="mb-4">
<label for="id_password" class="form-label small fw-bold">{% trans "Password" %}</label>
<div class="input-group">
<span class="input-group-text bg-light border-0"><i class="bi bi-lock"></i></span>
<input type="password" name="password" required id="id_password" class="form-control bg-light border-0 shadow-none px-3 py-2" placeholder="{% trans "Enter your password" %}">
</div>
</div>
<input type="hidden" name="next" value="{{ next }}">
<button type="submit" class="btn btn-primary btn-lg w-100 rounded-pill py-3 mb-4">
{% trans "Login" %}
</button>
<div class="text-center small text-secondary">
{% trans "Don't have an account?" %}
<a href="/accounts/signup/" class="text-primary fw-bold text-decoration-none">{% trans "Sign Up" %}</a>
</div>
</form>
</div>
</div>
<div class="text-center mt-4">
<a href="{% url 'index' %}" class="text-secondary text-decoration-none small">
<i class="bi bi-arrow-left me-1"></i> {% trans "Back to Home" %}
</a>
</div>
</div>
</div>
</div>
</section>
{% endblock %}

View File

@ -0,0 +1,70 @@
{% extends "base.html" %}
{% load i18n %}
{% block title %}{% trans "Sign Up" %} | Jimma Market{% endblock %}
{% block content %}
<section class="py-5 bg-light min-vh-100 d-flex align-items-center">
<div class="container">
<div class="row justify-content-center">
<div class="col-md-6 col-lg-5">
<div class="card border-0 shadow-lg rounded-4 overflow-hidden">
<div class="bg-primary p-4 text-white text-center">
<i class="bi bi-person-plus fs-1 mb-2"></i>
<h3 class="fw-bold mb-0">{% trans "Join Jimma Market" %}</h3>
<p class="small opacity-75 mb-0">{% trans "Create your account to start shopping" %}</p>
</div>
<div class="card-body p-4 p-md-5 bg-white">
<form method="post">
{% csrf_token %}
{% for field in form %}
<div class="mb-3">
<label for="{{ field.id_for_label }}" class="form-label small fw-bold">{{ field.label }}</label>
{{ field }}
{% if field.help_text %}
<div class="form-text small text-muted">{{ field.help_text }}</div>
{% endif %}
{% if field.errors %}
<div class="text-danger small mt-1">
{{ field.errors|striptags }}
</div>
{% endif %}
</div>
{% endfor %}
<button type="submit" class="btn btn-primary btn-lg w-100 rounded-pill py-3 mt-4 mb-4">
{% trans "Create Account" %}
</button>
<div class="text-center small text-secondary">
{% trans "Already have an account?" %}
<a href="{% url 'login' %}" class="text-primary fw-bold text-decoration-none">{% trans "Login" %}</a>
</div>
</form>
</div>
</div>
<div class="text-center mt-4">
<a href="{% url 'index' %}" class="text-secondary text-decoration-none small">
<i class="bi bi-arrow-left me-1"></i> {% trans "Back to Home" %}
</a>
</div>
</div>
</div>
</div>
</section>
<style>
form input {
border-radius: 8px !important;
padding: 10px 15px !important;
border: 1px solid #dee2e6 !important;
background-color: #f8f9fa !important;
}
form input:focus {
background-color: #fff !important;
border-color: #0d6efd !important;
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25) !important;
}
</style>
{% endblock %}

View File

@ -1,5 +1,5 @@
from modeltranslation.translator import register, TranslationOptions
from .models import Category, Product, Vendor
from .models import Category, Product, Vendor, Article
@register(Category)
class CategoryTranslationOptions(TranslationOptions):
@ -12,3 +12,7 @@ class ProductTranslationOptions(TranslationOptions):
@register(Vendor)
class VendorTranslationOptions(TranslationOptions):
fields = ('business_name', 'description')
@register(Article)
class ArticleTranslationOptions(TranslationOptions):
fields = ('title', 'content')

View File

@ -3,14 +3,34 @@ from . import views
urlpatterns = [
path('', views.home, name='index'),
path('signup/', views.signup, name='signup'), # Added signup url
path('products/', views.product_list, name='product_list'),
path('product/<slug:slug>/', views.product_detail, name='product_detail'),
path('product/review/<int:product_id>/', views.product_review_submit, name='product_review_submit'),
path('category/<slug:slug>/', views.category_products, name='category_products'),
path('cart/', views.cart_detail, name='cart_detail'),
path('cart/add/<int:product_id>/', views.cart_add, name='cart_add'),
path('cart/remove/<int:product_id>/', views.cart_remove, name='cart_remove'),
path('checkout/', views.checkout, name='checkout'),
path('order/success/<int:order_id>/', views.order_success, name='order_success'),
# Vendor URLs
path('vendor/register/', views.vendor_register, name='vendor_register'),
path('vendor/dashboard/', views.vendor_dashboard, name='vendor_dashboard'),
path('vendor/product/add/', views.vendor_product_add, name='vendor_product_add'),
path('vendor/product/edit/<int:pk>/', views.vendor_product_edit, name='vendor_product_edit'),
path('vendor/product/delete/<int:pk>/', views.vendor_product_delete, name='vendor_product_delete'),
path('vendor/order/status/<int:order_id>/', views.vendor_order_status_update, name='vendor_order_status_update'),
# Essential Pages
path('about/', views.about_us, name='about_us'),
path('how-it-works/', views.how_it_works, name='how_it_works'),
path('seller-info/', views.seller_info, name='seller_info'),
path('delivery-info/', views.delivery_info, name='delivery_info'),
path('contact/', views.contact_us, name='contact_us'),
path('track-order/', views.track_order, name='track_order'),
# Blog/Articles
path('blog/', views.article_list, name='article_list'),
path('blog/<slug:slug>/', views.article_detail, name='article_detail'),
]

View File

@ -1,35 +1,133 @@
from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required
from .models import Category, Product, Vendor, Order, OrderItem, Profile
from django.contrib.auth import login
from .models import Category, Product, Vendor, Order, OrderItem, Profile, ProductReview, ProductImage, Article
from .forms import ProductForm, SignUpForm # Added SignUpForm
from django.contrib import messages
from django.db.models import Q
from django.db.models import Q, Avg
def home(request):
categories = Category.objects.all()[:6]
featured_products = Product.objects.filter(is_available=True)[:8]
new_arrivals = Product.objects.filter(is_available=True).order_by('-created_at')[:8]
selected_kebele = request.GET.get('kebele')
local_vendors = Vendor.objects.filter(is_verified=True)
if selected_kebele:
local_vendors = local_vendors.filter(kebele=selected_kebele)
local_vendors = local_vendors[:4]
latest_articles = Article.objects.filter(is_published=True).order_by('-created_at')[:3]
kebeles = [k[0] for k in Vendor.JIMMA_KEBELES]
return render(request, 'core/index.html', {
'categories': categories,
'featured_products': featured_products,
'new_arrivals': new_arrivals,
'local_vendors': local_vendors,
'latest_articles': latest_articles,
'kebeles': kebeles,
'selected_kebele': selected_kebele,
})
def signup(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
user = form.save()
login(request, user)
messages.success(request, "Registration successful. Welcome to Jimma Market!")
return redirect('index')
else:
form = SignUpForm()
return render(request, 'registration/signup.html', {'form': form})
def product_list(request):
query = request.GET.get('q')
category_slug = request.GET.get('category')
sort = request.GET.get('sort')
kebele = request.GET.get('kebele')
products = Product.objects.filter(is_available=True)
if query:
products = products.filter(
Q(name__icontains=query) |
Q(description__icontains=query)
)
return render(request, 'core/product_list.html', {'products': products})
if category_slug:
products = products.filter(category__slug=category_slug)
if kebele:
products = products.filter(vendor__kebele=kebele)
if sort == 'price_low':
products = products.order_by('price')
elif sort == 'price_high':
products = products.order_by('-price')
elif sort == 'newest':
products = products.order_by('-created_at')
categories = Category.objects.all()
kebeles = [k[0] for k in Vendor.JIMMA_KEBELES]
return render(request, 'core/product_list.html', {
'products': products,
'categories': categories,
'kebeles': kebeles,
'current_category': category_slug,
'current_sort': sort,
'current_kebele': kebele,
})
def product_detail(request, slug):
product = get_object_or_404(Product, slug=slug, is_available=True)
return render(request, 'core/product_detail.html', {'product': product})
related_products = Product.objects.filter(category=product.category).exclude(id=product.id)[:4]
reviews = product.reviews.all().order_by('-created_at')
return render(request, 'core/product_detail.html', {
'product': product,
'related_products': related_products,
'reviews': reviews,
})
def product_review_submit(request, product_id):
if request.method == 'POST':
product = get_object_or_404(Product, id=product_id)
rating = request.POST.get('rating')
comment = request.POST.get('comment')
full_name = request.POST.get('full_name', 'Anonymous')
if request.user.is_authenticated:
full_name = f"{request.user.first_name} {request.user.last_name}".strip() or request.user.username
ProductReview.objects.create(
product=product,
user=request.user if request.user.is_authenticated else None,
full_name=full_name,
rating=rating,
comment=comment
)
messages.success(request, "Thank you for your review!")
return redirect('product_detail', slug=product.slug)
def category_products(request, slug):
category = get_object_or_404(Category, slug=slug)
products = category.products.filter(is_available=True)
return render(request, 'core/category_products.html', {'category': category, 'products': products})
kebele = request.GET.get('kebele')
if kebele:
products = products.filter(vendor__kebele=kebele)
kebeles = [k[0] for k in Vendor.JIMMA_KEBELES]
return render(request, 'core/category_products.html', {
'category': category,
'products': products,
'kebeles': kebeles,
'current_kebele': kebele
})
# Basic Cart System using Session
def get_cart(request):
@ -39,10 +137,13 @@ def get_cart(request):
def cart_add(request, product_id):
cart = get_cart(request)
product_id_str = str(product_id)
quantity = int(request.POST.get('quantity', 1))
if product_id_str in cart:
cart[product_id_str] += 1
cart[product_id_str] += quantity
else:
cart[product_id_str] = 1
cart[product_id_str] = quantity
request.session['cart'] = cart
messages.success(request, "Product added to cart")
return redirect('cart_detail')
@ -60,10 +161,13 @@ def cart_detail(request):
cart_items = []
total = 0
for product_id, quantity in cart.items():
product = get_object_or_404(Product, id=product_id)
subtotal = product.price * quantity
total += subtotal
cart_items.append({'product': product, 'quantity': quantity, 'subtotal': subtotal})
try:
product = Product.objects.get(id=product_id)
subtotal = product.price * quantity
total += subtotal
cart_items.append({'product': product, 'quantity': quantity, 'subtotal': subtotal})
except Product.DoesNotExist:
continue
return render(request, 'core/cart_detail.html', {'cart_items': cart_items, 'total': total})
def checkout(request):
@ -76,14 +180,16 @@ def checkout(request):
email = request.POST.get('email')
phone = request.POST.get('phone')
address = request.POST.get('address')
kebele = request.POST.get('kebele')
delivery_time_slot = request.POST.get('delivery_time_slot')
payment_method = request.POST.get('payment_method')
total = 0
order_items = []
order_items_data = []
for product_id, quantity in cart.items():
product = get_object_or_404(Product, id=product_id)
total += product.price * quantity
order_items.append((product, quantity, product.price))
order_items_data.append((product, quantity, product.price))
order = Order.objects.create(
user=request.user if request.user.is_authenticated else None,
@ -91,17 +197,32 @@ def checkout(request):
email=email,
phone=phone,
address=address,
kebele=kebele,
delivery_time_slot=delivery_time_slot,
total_price=total,
payment_method=payment_method
)
for product, quantity, price in order_items:
for product, quantity, price in order_items_data:
OrderItem.objects.create(order=order, product=product, quantity=quantity, price=price)
request.session['cart'] = {}
messages.success(request, "Order placed successfully!")
return redirect('order_success', order_id=order.id)
return render(request, 'core/checkout.html')
kebeles = Order.JIMMA_KEBELES
time_slots = Order.TIME_SLOTS
total = 0
for product_id, quantity in cart.items():
product = get_object_or_404(Product, id=product_id)
total += product.price * quantity
return render(request, 'core/checkout.html', {
'kebeles': kebeles,
'time_slots': time_slots,
'total': total,
})
def order_success(request, order_id):
order = get_object_or_404(Order, id=order_id)
@ -116,6 +237,7 @@ def vendor_register(request):
business_name = request.POST.get('business_name')
description = request.POST.get('description')
address = request.POST.get('address')
kebele = request.POST.get('kebele')
phone = request.POST.get('phone')
Vendor.objects.create(
@ -123,6 +245,7 @@ def vendor_register(request):
business_name=business_name,
description=description,
address=address,
kebele=kebele,
phone=phone
)
# Update user role
@ -133,11 +256,122 @@ def vendor_register(request):
messages.success(request, "Vendor registration successful. Wait for admin verification.")
return redirect('vendor_dashboard')
return render(request, 'core/vendor_register.html')
return render(request, 'core/vendor_register.html', {'kebeles': Vendor.JIMMA_KEBELES})
@login_required
def vendor_dashboard(request):
vendor = get_object_or_404(Vendor, user=request.user)
products = vendor.products.all()
orders = OrderItem.objects.filter(product__vendor=vendor).select_related('order')
return render(request, 'core/vendor_dashboard.html', {'vendor': vendor, 'products': products, 'orders': orders})
products = vendor.products.all().order_by('-created_at')
# Get all orders that contain products from this vendor
# We use a set of order IDs to avoid duplicates if multiple products from same vendor in one order
vendor_order_items = OrderItem.objects.filter(product__vendor=vendor).select_related('order', 'product').order_by('-order__created_at')
return render(request, 'core/vendor_dashboard.html', {
'vendor': vendor,
'products': products,
'order_items': vendor_order_items
})
@login_required
def vendor_product_add(request):
vendor = get_object_or_404(Vendor, user=request.user)
if request.method == 'POST':
form = ProductForm(request.POST, request.FILES)
if form.is_valid():
product = form.save(commit=False)
product.vendor = vendor
product.save()
messages.success(request, "Product added successfully!")
return redirect('vendor_dashboard')
else:
form = ProductForm()
return render(request, 'core/vendor_product_form.html', {'form': form, 'title': 'Add New Product'})
@login_required
def vendor_product_edit(request, pk):
vendor = get_object_or_404(Vendor, user=request.user)
product = get_object_or_404(Product, pk=pk, vendor=vendor)
if request.method == 'POST':
form = ProductForm(request.POST, request.FILES, instance=product)
if form.is_valid():
form.save()
messages.success(request, "Product updated successfully!")
return redirect('vendor_dashboard')
else:
form = ProductForm(instance=product)
return render(request, 'core/vendor_product_form.html', {'form': form, 'title': f'Edit {product.name}'})
@login_required
def vendor_product_delete(request, pk):
vendor = get_object_or_404(Vendor, user=request.user)
product = get_object_or_404(Product, pk=pk, vendor=vendor)
if request.method == 'POST':
product.delete()
messages.success(request, "Product deleted successfully!")
return redirect('vendor_dashboard')
return render(request, 'core/vendor_product_confirm_delete.html', {'product': product})
@login_required
def vendor_order_status_update(request, order_id):
vendor = get_object_or_404(Vendor, user=request.user)
order = get_object_or_404(Order, id=order_id)
# Check if this vendor has products in this order
if not OrderItem.objects.filter(order=order, product__vendor=vendor).exists():
messages.error(request, "You don't have permission to update this order.")
return redirect('vendor_dashboard')
if request.method == 'POST':
new_status = request.POST.get('status')
if new_status in dict(Order.STATUS_CHOICES):
order.status = new_status
order.save()
messages.success(request, f"Order status updated to {new_status}")
return redirect('vendor_dashboard')
# Essential Pages
def about_us(request):
return render(request, 'core/about_us.html')
def how_it_works(request):
return render(request, 'core/how_it_works.html')
def seller_info(request):
return render(request, 'core/seller_info.html')
def delivery_info(request):
return render(request, 'core/delivery_info.html')
def contact_us(request):
if request.method == 'POST':
messages.success(request, "Thank you for your message. We will get back to you soon!")
return redirect('contact_us')
return render(request, 'core/contact_us.html')
def track_order(request):
order = None
if request.method == 'POST':
order_id = request.POST.get('order_id')
phone = request.POST.get('phone')
try:
order = Order.objects.get(id=order_id, phone=phone)
except (Order.DoesNotExist, ValueError):
messages.error(request, "Order not found. Please check your order ID and phone number.")
return render(request, 'core/track_order.html', {'order': order})
# Blog/Article Views
def article_list(request):
articles = Article.objects.filter(is_published=True).order_by('-created_at')
return render(request, 'core/article_list.html', {'articles': articles})
def article_detail(request, slug):
article = get_object_or_404(Article, slug=slug, is_published=True)
return render(request, 'core/article_detail.html', {'article': article})

View File

@ -4,24 +4,27 @@ import django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
django.setup()
from core.models import Category, Product, Vendor, Profile
from core.models import Category, Product, Vendor, Profile, Article
from django.contrib.auth.models import User
from django.utils.text import slugify
def populate():
# Create Superuser if not exists
if not User.objects.filter(username='admin').exists():
User.objects.create_superuser('admin', 'admin@example.com', 'adminpass')
admin_user, created = User.objects.get_or_create(username='admin', defaults={'email': 'admin@example.com'})
if created:
admin_user.set_password('adminpass')
admin_user.save()
print("Superuser created: admin / adminpass")
else:
admin_user = User.objects.get(username='admin')
# Categories
categories_data = [
{'name': 'Electronics', 'name_om': 'Meeshaalee Elektirooniksii', 'name_am': 'የኤሌክትሮኒክስ ዕቃዎች'},
{'name': 'Clothing', 'name_om': 'Uffata', 'name_am': 'ልብስ'},
{'name': 'Home & Garden', 'name_om': 'Mana fi Muka', 'name_am': 'ቤት እና የአትክልት ቦታ'},
{'name': 'Food & Groceries', 'name_om': 'Nyaataa fi Meeshaalee Nyaataa', 'name_am': 'ምግብ እና ግሮሰሪ'},
{'name': 'Handmade Crafts', 'name_om': 'Hojii Harkaa', 'name_am': 'በእጅ የተሰሩ ስራዎች'},
{'name': 'Books', 'name_om': 'Kitaabota', 'name_am': 'መጽሐፍት'},
{'name': 'Fashion', 'name_om': 'Faashinii', 'name_am': 'ፋሽን'},
{'name': 'Groceries', 'name_om': 'Meeshaalee Nyaataa', 'name_am': 'ግሮሰሪ'},
{'name': 'Home & Living', 'name_om': 'Meeshaa Manaa', 'name_am': 'ቤት እና ኑሮ'},
{'name': 'Agriculture', 'name_om': 'Qonnaa', 'name_am': 'ግብርና'},
]
categories = []
@ -29,8 +32,8 @@ def populate():
category, created = Category.objects.get_or_create(
name=cat['name'],
defaults={
'name_om': cat['name_om'],
'name_am': cat['name_am'],
'name_om': cat.get('name_om', cat['name']),
'name_am': cat.get('name_am', cat['name']),
'slug': slugify(cat['name'])
}
)
@ -38,74 +41,144 @@ def populate():
if created:
print(f"Category created: {cat['name']}")
# Create a Vendor
vendor_user, created = User.objects.get_or_create(username='vendor1', email='vendor1@example.com')
if created:
vendor_user.set_password('vendorpass')
vendor_user.save()
Profile.objects.get_or_create(user=vendor_user, role='seller')
print("Vendor user created: vendor1")
vendor, created = Vendor.objects.get_or_create(
user=vendor_user,
defaults={
'business_name': 'Ethio Tech Solutions',
'business_name_om': 'Furmaata Teeknoojii Itiyoophiyaa',
'description': 'Leading provider of tech gadgets in Addis.',
'address': 'Bole, Addis Ababa',
'phone': '+251911000000'
# Create Jimma Vendors
vendors_data = [
{
'username': 'jimma_electronics',
'business_name': 'Jimma Tech Hub',
'business_name_om': 'Giddu-gala Teeknoojii Jimmaa',
'address': 'Hermata Merkato, Jimma',
'kebele': 'Hermata Merkato',
'phone': '0911223344'
},
{
'username': 'aba_jifar_honey',
'business_name': 'Abba Jifar Honey',
'business_name_om': 'Damma Abbaa Jifaar',
'address': 'Jiren, Jimma',
'kebele': 'Jiren',
'phone': '0922334455'
},
{
'username': 'kochi_furniture',
'business_name': 'Kochi Modern Furniture',
'business_name_om': 'Meeshaa Manaa Kochi',
'address': 'Mendera Kochi, Jimma',
'kebele': 'Mendera Kochi',
'phone': '0933445566'
}
)
if created:
print("Vendor created: Ethio Tech Solutions")
]
for v_data in vendors_data:
user, created = User.objects.get_or_create(username=v_data['username'], email=f"{v_data['username']}@example.com")
if created:
user.set_password('vendorpass')
user.save()
Profile.objects.get_or_create(user=user, role='seller')
vendor, created = Vendor.objects.get_or_create(
user=user,
defaults={
'business_name': v_data['business_name'],
'business_name_om': v_data['business_name_om'],
'address': v_data['address'],
'kebele': v_data['kebele'],
'phone': v_data['phone'],
'is_verified': True
}
)
if not created:
vendor.kebele = v_data['kebele']
vendor.save()
print(f"Updated Vendor kebele: {v_data['business_name']} -> {v_data['kebele']}")
else:
print(f"Vendor created: {v_data['business_name']}")
# Products
products_data = [
{
'name': 'Smartphone X1',
'name_om': 'Bilbila Ammayya X1',
'name': 'Samsung Galaxy A54',
'name_om': 'Saamsangi Gaalaaksii A54',
'category': categories[0],
'price': 25000,
'description': 'High performance smartphone.'
'price': 45000,
'description': 'Latest Samsung smartphone with great camera.',
'vendor_username': 'jimma_electronics'
},
{
'name': 'Traditional Coffee Pot (Jebena)',
'name_om': 'Jabanaa',
'category': categories[4],
'price': 500,
'description': 'Handmade traditional clay pot.'
},
{
'name': 'Cotton Scarf',
'name_om': 'Shaashii',
'category': categories[1],
'name': 'Pure Jimma Forest Honey',
'name_om': 'Damma Bosona Jimmaa qulqulluu',
'category': categories[2],
'price': 1200,
'description': 'Pure Ethiopian cotton.'
'description': '100% organic honey from the forests of Jimma.',
'vendor_username': 'aba_jifar_honey'
},
{
'name': 'Organic Honey',
'name_om': 'Damma',
'name': 'Jimma Coffee Beans (1kg)',
'name_om': 'Bunna Jimmaa (kg 1)',
'category': categories[2],
'price': 900,
'description': 'World famous Jimma coffee beans, roasted to perfection.',
'vendor_username': 'aba_jifar_honey'
},
{
'name': 'Modern Sofa Set',
'name_om': 'Sofaa Ammayya',
'category': categories[3],
'price': 800,
'description': 'Pure honey from Gojam.'
'price': 85000,
'description': 'High quality sofa set for your living room.',
'vendor_username': 'kochi_furniture'
},
]
for prod in products_data:
vendor = Vendor.objects.get(user__username=prod['vendor_username'])
product, created = Product.objects.get_or_create(
name=prod['name'],
defaults={
'name_om': prod['name_om'],
'name_om': prod.get('name_om', prod['name']),
'category': prod['category'],
'vendor': vendor,
'price': prod['price'],
'description': prod['description'],
'slug': slugify(prod['name']),
'is_available': True
'is_available': True,
'stock': 10
}
)
if created:
print(f"Product created: {prod['name']}")
# Articles
articles_data = [
{
'title': 'The Rise of E-commerce in Jimma',
'content': 'Jimma is witnessing a digital transformation in how people shop. With the launch of Jimma Market, local residents can now access a wide range of products from their favorite local vendors with just a few clicks. This shift is not only providing convenience but also opening new opportunities for small businesses in the region.',
'author': admin_user
},
{
'title': 'Vendor Spotlight: Abba Jifar Honey',
'content': 'Meet the people behind the finest honey in Jimma. Abba Jifar Honey has been a staple in the local market for years, and now they are bringing their 100% organic forest honey to the digital space. Discover their journey from traditional beekeeping to becoming a top-selling vendor on Jimma Market.',
'author': admin_user
},
{
'title': 'Jimma Coffee: From Farm to Your Cup',
'content': 'Jimma is world-renowned for its exceptional coffee. In this article, we explore the rich heritage of coffee farming in the region and how Jimma Market is helping local farmers reach a broader audience. Learn about the unique flavors of Jimma coffee and why it remains a favorite among coffee enthusiasts worldwide.',
'author': admin_user
}
]
for art_data in articles_data:
article, created = Article.objects.get_or_create(
title=art_data['title'],
defaults={
'content': art_data['content'],
'author': art_data['author'],
'is_published': True,
'slug': slugify(art_data['title'])
}
)
if created:
print(f"Article created: {art_data['title']}")
if __name__ == '__main__':
populate()
populate()