Autosave: 20260126-043309

This commit is contained in:
Flatlogic Bot 2026-01-26 04:33:09 +00:00
parent 7e8ed2b3cb
commit a3174399c8
21 changed files with 527 additions and 30 deletions

View File

@ -149,6 +149,10 @@ class PlatformProfileAdmin(admin.ModelAdmin):
fieldsets += ((_('Tools'), {'fields': ('test_connection_link',)}),)
return fieldsets
class CountryAdmin(admin.ModelAdmin):
list_display = ('name_en', 'name_ar', 'phone_code')
search_fields = ('name_en', 'name_ar', 'phone_code')
class TestimonialAdmin(admin.ModelAdmin):
list_display = ('name_en', 'role_en', 'is_active', 'created_at')
list_filter = ('is_active', 'created_at')
@ -158,7 +162,7 @@ class TestimonialAdmin(admin.ModelAdmin):
admin.site.unregister(User)
admin.site.register(User, CustomUserAdmin)
admin.site.register(Parcel, ParcelAdmin)
admin.site.register(Country)
admin.site.register(Country, CountryAdmin)
admin.site.register(Governate)
admin.site.register(City)
admin.site.register(PlatformProfile, PlatformProfileAdmin)

View File

@ -14,7 +14,10 @@ class UserRegistrationForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput, label=_("Password"))
password_confirm = forms.CharField(widget=forms.PasswordInput, label=_("Confirm Password"))
role = forms.ChoiceField(choices=Profile.ROLE_CHOICES, label=_("Register as"))
phone_code = forms.ModelChoiceField(queryset=Country.objects.none(), label=_("Code"), required=False, widget=forms.Select(attrs={'class': 'form-control'}))
phone_number = forms.CharField(max_length=20, label=_("Phone Number"))
verification_method = forms.ChoiceField(choices=[('email', _('Email')), ('whatsapp', _('WhatsApp'))], label=_("Verify via"), widget=forms.RadioSelect, initial='email')
country = forms.ModelChoiceField(queryset=Country.objects.all(), required=False, label=_("Country"))
@ -36,12 +39,17 @@ class UserRegistrationForm(forms.ModelForm):
lang = get_language()
name_field = 'name_ar' if lang == 'ar' else 'name_en'
# Phone Code setup
self.fields['phone_code'].queryset = Country.objects.exclude(phone_code='').order_by(name_field)
self.fields['phone_code'].label_from_instance = lambda obj: f"{obj.phone_code} ({obj.name})"
self.fields['country'].queryset = Country.objects.all().order_by(name_field)
# Default Country logic
oman = Country.objects.filter(name_en='Oman').first()
if oman:
self.fields['country'].initial = oman
self.fields['phone_code'].initial = oman
if 'country' in self.data:
try:
@ -70,6 +78,17 @@ class UserRegistrationForm(forms.ModelForm):
raise forms.ValidationError(_("Passwords don't match"))
return password_confirm
def clean(self):
cleaned_data = super().clean()
phone_code = cleaned_data.get('phone_code')
phone_number = cleaned_data.get('phone_number')
if phone_code and phone_number:
# If user didn't type the code in the phone number input, prepend it
if not phone_number.startswith(phone_code.phone_code):
cleaned_data['phone_number'] = f"{phone_code.phone_code}{phone_number}"
return cleaned_data
def save(self, commit=True):
user = super().save(commit=False)
user.set_password(self.cleaned_data['password'])
@ -90,7 +109,9 @@ class UserProfileForm(forms.ModelForm):
last_name = forms.CharField(label=_("Last Name"), max_length=150, widget=forms.TextInput(attrs={'class': 'form-control'}))
email = forms.EmailField(label=_("Email"), widget=forms.EmailInput(attrs={'class': 'form-control'}))
phone_code = forms.ModelChoiceField(queryset=Country.objects.none(), label=_("Code"), required=False, widget=forms.Select(attrs={'class': 'form-control'}))
phone_number = forms.CharField(label=_("Phone Number"), max_length=20, widget=forms.TextInput(attrs={'class': 'form-control'}))
address = forms.CharField(label=_("Address"), required=False, widget=forms.TextInput(attrs={'class': 'form-control'}))
profile_picture = forms.ImageField(label=_("Profile Picture"), required=False, widget=forms.FileInput(attrs={'class': 'form-control'}))
@ -125,10 +146,25 @@ class UserProfileForm(forms.ModelForm):
lang = get_language()
name_field = 'name_ar' if lang == 'ar' else 'name_en'
self.fields['country'].queryset = Country.objects.all().order_by(name_field)
# Phone Code setup
self.fields['phone_code'].queryset = Country.objects.exclude(phone_code='').order_by(name_field)
self.fields['phone_code'].label_from_instance = lambda obj: f"{obj.phone_code} ({obj.name})"
# Default Country logic (Oman)
oman = Country.objects.filter(name_en='Oman').first()
if oman:
self.fields['phone_code'].initial = oman
# Initial splitting of phone number
if self.instance.pk and self.instance.phone_number:
for country in Country.objects.exclude(phone_code=''):
if self.instance.phone_number.startswith(country.phone_code):
self.fields['phone_code'].initial = country
# Strip code from display
self.fields['phone_number'].initial = self.instance.phone_number[len(country.phone_code):]
break
self.fields['country'].queryset = Country.objects.all().order_by(name_field)
# Initial QS setup
self.fields['governate'].queryset = Governate.objects.none()
@ -154,7 +190,19 @@ class UserProfileForm(forms.ModelForm):
elif self.instance.pk and self.instance.governate:
self.fields['city'].queryset = self.instance.governate.city_set.order_by(name_field)
def clean(self):
cleaned_data = super().clean()
phone_code = cleaned_data.get('phone_code')
phone_number = cleaned_data.get('phone_number')
if phone_code and phone_number:
if not phone_number.startswith(phone_code.phone_code):
cleaned_data['phone_number'] = f"{phone_code.phone_code}{phone_number}"
return cleaned_data
class ParcelForm(forms.ModelForm):
receiver_phone_code = forms.ModelChoiceField(queryset=Country.objects.none(), label=_("Receiver Code"), required=False, widget=forms.Select(attrs={'class': 'form-control'}))
class Meta:
model = Parcel
fields = [
@ -202,16 +250,29 @@ class ParcelForm(forms.ModelForm):
lang = get_language()
name_field = 'name_ar' if lang == 'ar' else 'name_en'
# Set querysets for countries
self.fields['pickup_country'].queryset = Country.objects.all().order_by(name_field)
self.fields['delivery_country'].queryset = Country.objects.all().order_by(name_field)
# Phone Code setup
self.fields['receiver_phone_code'].queryset = Country.objects.exclude(phone_code='').order_by(name_field)
self.fields['receiver_phone_code'].label_from_instance = lambda obj: f"{obj.phone_code} ({obj.name})"
# Default Country logic
oman = Country.objects.filter(name_en='Oman').first()
if oman:
self.fields['receiver_phone_code'].initial = oman
self.fields['pickup_country'].initial = oman
self.fields['delivery_country'].initial = oman
# Initial splitting of phone number (if editing)
if self.instance.pk and self.instance.receiver_phone:
for country in Country.objects.exclude(phone_code=''):
if self.instance.receiver_phone.startswith(country.phone_code):
self.fields['receiver_phone_code'].initial = country
self.fields['receiver_phone'].initial = self.instance.receiver_phone[len(country.phone_code):]
break
# Set querysets for countries
self.fields['pickup_country'].queryset = Country.objects.all().order_by(name_field)
self.fields['delivery_country'].queryset = Country.objects.all().order_by(name_field)
# Pickup
self.fields['pickup_governate'].queryset = Governate.objects.none()
self.fields['pickup_city'].queryset = City.objects.none()
@ -251,3 +312,13 @@ class ParcelForm(forms.ModelForm):
self.fields['delivery_city'].queryset = City.objects.filter(governate_id=gov_id).order_by(name_field)
except (ValueError, TypeError):
pass
def clean(self):
cleaned_data = super().clean()
phone_code = cleaned_data.get('receiver_phone_code')
phone_number = cleaned_data.get('receiver_phone')
if phone_code and phone_number:
if not phone_number.startswith(phone_code.phone_code):
cleaned_data['receiver_phone'] = f"{phone_code.phone_code}{phone_number}"
return cleaned_data

View File

@ -0,0 +1,18 @@
# Generated by Django 5.2.7 on 2026-01-25 17:22
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0015_testimonial'),
]
operations = [
migrations.AddField(
model_name='country',
name='phone_code',
field=models.CharField(blank=True, help_text='e.g. +968', max_length=10, verbose_name='Phone Code'),
),
]

View File

@ -11,6 +11,7 @@ import uuid
class Country(models.Model):
name_en = models.CharField(_('Name (English)'), max_length=100)
name_ar = models.CharField(_('Name (Arabic)'), max_length=100)
phone_code = models.CharField(_('Phone Code'), max_length=10, blank=True, help_text=_("e.g. +968"))
@property
def name(self):
@ -19,7 +20,7 @@ class Country(models.Model):
return self.name_en
def __str__(self):
return self.name
return f"{self.name} ({self.phone_code})" if self.phone_code else self.name
class Meta:
verbose_name = _('Country')
@ -240,4 +241,4 @@ class Testimonial(models.Model):
class Meta:
verbose_name = _('Testimonial')
verbose_name_plural = _('Testimonials')
ordering = ['-created_at']
ordering = ['-created_at']

View File

@ -0,0 +1,93 @@
{% load i18n core_tags %}
{% get_platform_profile as platform %}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
background-color: #f4f6f8;
margin: 0;
padding: 0;
color: #333333;
}
.container {
max-width: 600px;
margin: 0 auto;
background-color: #ffffff;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
margin-top: 40px;
margin-bottom: 40px;
}
.header {
background-color: #ffffff;
padding: 30px;
text-align: center;
border-bottom: 1px solid #eeeeee;
}
.logo {
max-height: 60px;
width: auto;
}
.content {
padding: 40px 30px;
line-height: 1.6;
}
.footer {
background-color: #f8f9fa;
padding: 20px;
text-align: center;
font-size: 12px;
color: #888888;
}
.button {
display: inline-block;
padding: 12px 24px;
background-color: #e67e22; /* Orange accent */
color: #ffffff !important;
text-decoration: none;
border-radius: 6px;
font-weight: bold;
margin-top: 20px;
margin-bottom: 20px;
}
h1 {
color: #333333;
font-size: 24px;
margin-bottom: 20px;
margin-top: 0;
}
p {
margin-bottom: 15px;
}
.link-text {
color: #e67e22;
word-break: break-all;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
{% if platform and platform.logo %}
<img src="{{ protocol }}://{{ domain }}{{ platform.logo.url }}" alt="{{ platform.name }}" class="logo">
{% else %}
<h2>{{ site_name }}</h2>
{% endif %}
</div>
<div class="content">
{% block content %}{% endblock %}
</div>
<div class="footer">
<p>&copy; {% now "Y" %} {{ site_name }}. {% trans "All rights reserved." %}</p>
{% if platform and platform.address %}
<p>{{ platform.address }}</p>
{% endif %}
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,26 @@
{% extends "core/emails/base_email.html" %}
{% load i18n %}
{% block content %}
<h1>{% trans "Reset Your Password" %}</h1>
<p>{% trans "Hello," %}</p>
<p>{% trans "You are receiving this email because you requested a password reset for your account at" %} <strong>{{ site_name }}</strong>.</p>
<p>{% trans "Please click the button below to choose a new password:" %}</p>
<div style="text-align: center;">
<a href="{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}" class="button">{% trans "Reset Password" %}</a>
</div>
<p>{% trans "If the button above doesn't work, verify that you entered your username correctly and try pasting this link into your browser:" %}</p>
<p><a href="{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}" class="link-text">{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}</a></p>
<p>{% trans "Your username is:" %} <strong>{{ user.get_username }}</strong></p>
<p>{% trans "If you did not request this, please ignore this email." %}</p>
<p>{% trans "Thanks," %}<br>{% trans "The" %} {{ site_name }} {% trans "Team" %}</p>
{% endblock %}

View File

@ -0,0 +1 @@
{% trans "Password reset on" %} {{ site_name }}

View File

@ -4,36 +4,52 @@
{% block title %}{% trans "Login" %} | masarX{% endblock %}
{% block content %}
<section class="py-5 bg-light" style="min-height: 80vh;">
<div class="container py-5">
<section class="py-5 bg-light" style="min-height: 80vh; display: flex; align-items: center;">
<div class="container">
<div class="row justify-content-center">
<div class="col-md-5">
<!-- Back to Home -->
<div class="mb-4">
<a href="{% url 'index' %}" class="btn btn-link text-decoration-none text-muted ps-0">
<i class="bi bi-arrow-left me-2"></i>{% trans "Back to Home" %}
</a>
</div>
<div class="col-md-6 col-lg-5">
<div class="card shadow-sm border-0 rounded-4">
<div class="card-body p-4 p-md-5">
<!-- Logo or Brand Name -->
<div class="text-center mb-4">
{% if platform_profile.logo %}
<img src="{{ platform_profile.logo.url }}" alt="{{ platform_profile.name }}" height="70" class="mb-3">
{% else %}
<h2 class="fw-bold text-masarx-primary mb-3">{{ platform_profile.name|default:"masarX" }}</h2>
{% endif %}
<h4 class="fw-bold">{% trans "Welcome Back" %}</h4>
<p class="text-muted small">{% trans "Please login to your account" %}</p>
</div>
<div class="card shadow-sm border-0">
<div class="card-body p-5">
<h2 class="fw-bold mb-4 text-center">{% trans "Login to masarX" %}</h2>
<form method="post">
{% csrf_token %}
{% for field in form %}
<div class="mb-3">
<label class="form-label">{{ field.label }}</label>
<label class="form-label fw-medium">{{ field.label }}</label>
{{ field }}
{% if field.errors %}
<div class="text-danger small">{{ field.errors }}</div>
<div class="text-danger small mt-1">{{ field.errors }}</div>
{% endif %}
</div>
{% endfor %}
<button type="submit" class="btn btn-masarx-primary w-100 py-2 mt-3">{% trans "Login" %}</button>
<div class="d-flex justify-content-between align-items-center mb-4">
<div class="form-check">
<!-- Optional: Remember Me logic could go here later -->
</div>
<a href="{% url 'password_reset' %}" class="text-decoration-none text-muted small hover-orange">
{% trans "Forgot Password?" %}
</a>
</div>
<button type="submit" class="btn btn-masarx-primary w-100 py-2 fw-bold mb-3">{% trans "Login" %}</button>
<div class="text-center">
<span class="text-muted small">{% trans "Don't have an account?" %}</span>
<a href="{% url 'register' %}" class="text-masarx-orange text-decoration-none fw-bold ms-1">{% trans "Register" %}</a>
</div>
</form>
<div class="text-center mt-4">
<p class="mb-0 text-muted">{% trans "Don't have an account?" %} <a href="{% url 'register' %}" class="text-masarx-orange">{% trans "Register here" %}</a></p>
</div>
</div>
</div>
</div>
@ -44,14 +60,30 @@
<style>
.form-control {
border-radius: 8px;
padding: 10px 15px;
padding: 12px 15px;
border-color: #dee2e6;
}
.form-control:focus {
border-color: var(--accent-orange);
box-shadow: 0 0 0 0.25rem rgba(255, 126, 21, 0.15);
}
.btn-masarx-primary {
background-color: var(--accent-orange);
border-color: var(--accent-orange);
color: white;
font-weight: 600;
border-radius: 8px;
transition: all 0.3s;
}
.btn-masarx-primary:hover {
background-color: #e66a00;
border-color: #e66a00;
color: white;
}
.text-masarx-orange {
color: var(--accent-orange);
}
.hover-orange:hover {
color: var(--accent-orange) !important;
}
</style>
{% endblock %}
{% endblock %}

View File

@ -0,0 +1,44 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans "Password Reset Complete" %} | masarX{% endblock %}
{% block content %}
<section class="py-5 bg-light" style="min-height: 80vh; display: flex; align-items: center;">
<div class="container">
<div class="row justify-content-center">
<div class="col-md-6 col-lg-5">
<div class="card shadow-sm border-0 rounded-4">
<div class="card-body p-4 p-md-5 text-center">
<div class="mb-4 text-success">
<i class="bi bi-check-circle-fill display-1"></i>
</div>
<h3 class="fw-bold mb-3">{% trans "Password Changed!" %}</h3>
<p class="text-muted mb-4">
{% trans "Your password has been set. You may go ahead and log in now." %}
</p>
<a href="{% url 'login' %}" class="btn btn-masarx-primary w-100 py-2 fw-bold">
{% trans "Log In" %}
</a>
</div>
</div>
</div>
</div>
</div>
</section>
<style>
.btn-masarx-primary {
background-color: var(--accent-orange);
border-color: var(--accent-orange);
color: white;
border-radius: 8px;
transition: all 0.3s;
}
.btn-masarx-primary:hover {
background-color: #e66a00;
border-color: #e66a00;
color: white;
}
</style>
{% endblock %}

View File

@ -0,0 +1,64 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans "New Password" %} | masarX{% endblock %}
{% block content %}
<section class="py-5 bg-light" style="min-height: 80vh; display: flex; align-items: center;">
<div class="container">
<div class="row justify-content-center">
<div class="col-md-6 col-lg-5">
<div class="card shadow-sm border-0 rounded-4">
<div class="card-body p-4 p-md-5">
<div class="text-center mb-4">
<h3 class="fw-bold">{% trans "Set New Password" %}</h3>
<p class="text-muted">{% trans "Please enter your new password twice so we can verify you typed it in correctly." %}</p>
</div>
<form method="post">
{% csrf_token %}
{% for field in form %}
<div class="mb-3">
<label class="form-label fw-medium">{{ field.label }}</label>
{{ field }}
{% if field.help_text %}
<div class="form-text small">{{ field.help_text }}</div>
{% endif %}
{% if field.errors %}
<div class="text-danger small mt-1">{{ field.errors }}</div>
{% endif %}
</div>
{% endfor %}
<button type="submit" class="btn btn-masarx-primary w-100 py-2 mt-3 fw-bold">{% trans "Change Password" %}</button>
</form>
</div>
</div>
</div>
</div>
</div>
</section>
<style>
.form-control {
border-radius: 8px;
padding: 12px 15px;
border-color: #dee2e6;
}
.form-control:focus {
border-color: var(--accent-orange);
box-shadow: 0 0 0 0.25rem rgba(255, 126, 21, 0.15);
}
.btn-masarx-primary {
background-color: var(--accent-orange);
border-color: var(--accent-orange);
color: white;
border-radius: 8px;
transition: all 0.3s;
}
.btn-masarx-primary:hover {
background-color: #e66a00;
border-color: #e66a00;
color: white;
}
</style>
{% endblock %}

View File

@ -0,0 +1,32 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans "Email Sent" %} | masarX{% endblock %}
{% block content %}
<section class="py-5 bg-light" style="min-height: 80vh; display: flex; align-items: center;">
<div class="container">
<div class="row justify-content-center">
<div class="col-md-6 col-lg-5">
<div class="card shadow-sm border-0 rounded-4">
<div class="card-body p-4 p-md-5 text-center">
<div class="mb-4 text-success">
<i class="bi bi-envelope-check-fill display-1"></i>
</div>
<h3 class="fw-bold mb-3">{% trans "Check Your Email" %}</h3>
<p class="text-muted mb-4">
{% trans "We've sent you instructions on how to reset your password. If an account exists with the email you entered, you will receive them shortly." %}
</p>
<p class="text-muted small mb-4">
{% trans "If you don't receive an email, please check your spam folder." %}
</p>
<a href="{% url 'login' %}" class="btn btn-outline-secondary w-100 py-2 rounded-3">
{% trans "Return to Login" %}
</a>
</div>
</div>
</div>
</div>
</div>
</section>
{% endblock %}

View File

@ -0,0 +1,72 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans "Reset Password" %} | masarX{% endblock %}
{% block content %}
<section class="py-5 bg-light" style="min-height: 80vh; display: flex; align-items: center;">
<div class="container">
<div class="row justify-content-center">
<div class="col-md-6 col-lg-5">
<div class="card shadow-sm border-0 rounded-4">
<div class="card-body p-4 p-md-5">
<div class="text-center mb-4">
{% if platform_profile.logo %}
<img src="{{ platform_profile.logo.url }}" alt="{{ platform_profile.name }}" height="60" class="mb-3">
{% else %}
<h2 class="fw-bold text-masarx-primary mb-3">{{ platform_profile.name|default:"masarX" }}</h2>
{% endif %}
<h4 class="fw-bold">{% trans "Reset Password" %}</h4>
<p class="text-muted mb-0">{% trans "Enter your email address and we'll send you a link to reset your password." %}</p>
</div>
<form method="post">
{% csrf_token %}
{% for field in form %}
<div class="mb-3">
<label class="form-label fw-medium">{{ field.label }}</label>
{{ field }}
{% if field.errors %}
<div class="text-danger small mt-1">{{ field.errors }}</div>
{% endif %}
</div>
{% endfor %}
<button type="submit" class="btn btn-masarx-primary w-100 py-2 fw-bold">{% trans "Send Reset Link" %}</button>
</form>
<div class="text-center mt-4">
<a href="{% url 'login' %}" class="text-decoration-none text-muted">
<i class="bi bi-arrow-left me-1"></i> {% trans "Back to Login" %}
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<style>
.form-control {
border-radius: 8px;
padding: 12px 15px;
border-color: #dee2e6;
}
.form-control:focus {
border-color: var(--accent-orange);
box-shadow: 0 0 0 0.25rem rgba(255, 126, 21, 0.15);
}
.btn-masarx-primary {
background-color: var(--accent-orange);
border-color: var(--accent-orange);
color: white;
border-radius: 8px;
transition: all 0.3s;
}
.btn-masarx-primary:hover {
background-color: #e66a00; /* Darker orange */
border-color: #e66a00;
color: white;
}
</style>
{% endblock %}

View File

@ -120,7 +120,17 @@
</div>
<div class="col-md-6">
<label class="form-label" for="{{ form.receiver_phone.id_for_label }}">{{ form.receiver_phone.label }}</label>
{{ form.receiver_phone }}
<div class="d-flex gap-2">
<div class="flex-shrink-0" style="width: 140px;">
{{ form.receiver_phone_code }}
</div>
<div class="flex-grow-1">
{{ form.receiver_phone }}
</div>
</div>
{% if form.receiver_phone_code.errors %}
<div class="text-danger small">{{ form.receiver_phone_code.errors }}</div>
{% endif %}
{% if form.receiver_phone.errors %}
<div class="text-danger small">{{ form.receiver_phone.errors }}</div>
{% endif %}

View File

@ -0,0 +1,8 @@
from django import template
from core.models import PlatformProfile
register = template.Library()
@register.simple_tag
def get_platform_profile():
return PlatformProfile.objects.first()

View File

@ -9,6 +9,27 @@ urlpatterns = [
path('register/', views.register, name='register'),
path('register/verify/', views.verify_registration, name='verify_registration'),
# Password Reset URLs
path('password-reset/', auth_views.PasswordResetView.as_view(
template_name='core/password_reset_form.html',
email_template_name='core/emails/password_reset_email.html',
subject_template_name='core/emails/password_reset_subject.txt',
success_url='/password-reset/done/'
), name='password_reset'),
path('password-reset/done/', auth_views.PasswordResetDoneView.as_view(
template_name='core/password_reset_done.html'
), name='password_reset_done'),
path('reset/<uidb64>/<token>/', auth_views.PasswordResetConfirmView.as_view(
template_name='core/password_reset_confirm.html',
success_url='/reset/done/'
), name='password_reset_confirm'),
path('reset/done/', auth_views.PasswordResetCompleteView.as_view(
template_name='core/password_reset_complete.html'
), name='password_reset_complete'),
path('dashboard/', views.dashboard, name='dashboard'),
path('shipment-request/', views.shipment_request, name='shipment_request'),
path('accept-parcel/<int:parcel_id>/', views.accept_parcel, name='accept_parcel'),
@ -27,4 +48,4 @@ urlpatterns = [
path('profile/', views.profile_view, name='profile'),
path('profile/edit/', views.edit_profile, name='edit_profile'),
path('profile/verify-otp/', views.verify_otp_view, name='verify_otp'),
]
]