added hire and another features

main
Babit Shrestha 6 months ago
parent 6b9504eedb
commit 3ae01ed458
  1. BIN
      sahara/db.sqlite3
  2. BIN
      sahara/main/__pycache__/models.cpython-312.pyc
  3. BIN
      sahara/main/__pycache__/urls.cpython-312.pyc
  4. BIN
      sahara/main/__pycache__/views.cpython-312.pyc
  5. 18
      sahara/main/migrations/0006_servicerequest_phone_number.py
  6. 22
      sahara/main/migrations/0007_remove_servicerequest_phone_number_user_phone_number.py
  7. 18
      sahara/main/migrations/0008_alter_servicerequest_is_approved.py
  8. 18
      sahara/main/migrations/0009_alter_servicerequest_is_approved.py
  9. BIN
      sahara/main/migrations/__pycache__/0006_servicerequest_phone_number.cpython-312.pyc
  10. BIN
      sahara/main/migrations/__pycache__/0007_remove_servicerequest_phone_number_user_phone_number.cpython-312.pyc
  11. BIN
      sahara/main/migrations/__pycache__/0008_alter_servicerequest_is_approved.cpython-312.pyc
  12. BIN
      sahara/main/migrations/__pycache__/0009_alter_servicerequest_is_approved.cpython-312.pyc
  13. 10
      sahara/main/models.py
  14. 114
      sahara/main/templates/main/home.html
  15. 126
      sahara/main/templates/main/profile.html
  16. 164
      sahara/main/templates/main/services1.html
  17. 4
      sahara/main/urls.py
  18. 112
      sahara/main/views.py
  19. 56
      sahara/static/css/styles.css
  20. 144
      sahara/static/css/styles.css_1
  21. BIN
      sahara/static/img/background.jpg
  22. BIN
      sahara/static/img/dummy pic.png
  23. BIN
      sahara/static/img/grandmother.png
  24. BIN
      sahara/static/profile-images/pic1.jpg
  25. 26
      sahara/templates/base.html

Binary file not shown.

@ -0,0 +1,18 @@
# Generated by Django 5.1.4 on 2025-01-12 03:35
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('main', '0005_user_login_profile_alter_servicerequest_service_and_more'),
]
operations = [
migrations.AddField(
model_name='servicerequest',
name='phone_number',
field=models.CharField(blank=True, max_length=15, null=True),
),
]

@ -0,0 +1,22 @@
# Generated by Django 5.1.4 on 2025-01-12 03:41
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('main', '0006_servicerequest_phone_number'),
]
operations = [
migrations.RemoveField(
model_name='servicerequest',
name='phone_number',
),
migrations.AddField(
model_name='user',
name='phone_number',
field=models.CharField(blank=True, max_length=15, null=True),
),
]

@ -0,0 +1,18 @@
# Generated by Django 5.1.4 on 2025-01-12 10:38
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('main', '0007_remove_servicerequest_phone_number_user_phone_number'),
]
operations = [
migrations.AlterField(
model_name='servicerequest',
name='is_approved',
field=models.BooleanField(blank=True, null=True),
),
]

@ -0,0 +1,18 @@
# Generated by Django 5.1.4 on 2025-01-12 10:38
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('main', '0008_alter_servicerequest_is_approved'),
]
operations = [
migrations.AlterField(
model_name='servicerequest',
name='is_approved',
field=models.BooleanField(blank=True, default=False, null=True),
),
]

@ -55,7 +55,6 @@ class UserManager(BaseUserManager):
return self.create_user(first_name, last_name, email, password, **extra_fields) return self.create_user(first_name, last_name, email, password, **extra_fields)
def send_verification_email(self, user): def send_verification_email(self, user):
# Generate the token and the uid for the verification URL
token = default_token_generator.make_token(user) token = default_token_generator.make_token(user)
uid = urlsafe_base64_encode(force_bytes(user.pk)) uid = urlsafe_base64_encode(force_bytes(user.pk))
verification_url = f"{settings.FRONTEND_URL}/verify-email/{uid}/{token}/" verification_url = f"{settings.FRONTEND_URL}/verify-email/{uid}/{token}/"
@ -93,6 +92,7 @@ class User(AbstractBaseUser, PermissionsMixin):
bio = models.CharField(max_length=200, blank=True, null=True) bio = models.CharField(max_length=200, blank=True, null=True)
member_since = models.DateTimeField(auto_now_add=True) member_since = models.DateTimeField(auto_now_add=True)
updated_on = models.DateField(auto_now=True) updated_on = models.DateField(auto_now=True)
phone_number = models.CharField(max_length=15, blank=True, null=True)
service_offered = models.ForeignKey(Service, on_delete=models.CASCADE,blank=True,null=True) service_offered = models.ForeignKey(Service, on_delete=models.CASCADE,blank=True,null=True)
login_profile = models.CharField( login_profile = models.CharField(
max_length=15, max_length=15,
@ -112,6 +112,11 @@ class User(AbstractBaseUser, PermissionsMixin):
def get_short_name(self): def get_short_name(self):
return self.first_name return self.first_name
@property
def url(self):
if self.profile_picture:
return self.profile_picture.url
return None
class ServiceRequest(models.Model): class ServiceRequest(models.Model):
client = models.ForeignKey(User,on_delete=models.CASCADE,related_name="client") client = models.ForeignKey(User,on_delete=models.CASCADE,related_name="client")
@ -119,12 +124,13 @@ class ServiceRequest(models.Model):
agreed_price = models.DecimalField(max_digits=999,decimal_places=2 , default=0) agreed_price = models.DecimalField(max_digits=999,decimal_places=2 , default=0)
service_hour = models.PositiveIntegerField(default=1) service_hour = models.PositiveIntegerField(default=1)
agreed_on = models.DateField(auto_now_add=True) agreed_on = models.DateField(auto_now_add=True)
is_approved = models.DateTimeField(blank=True, null=True) is_approved = models.BooleanField(blank=True, null=True,default=False)
remarks = models.TextField(blank=True, null=True) remarks = models.TextField(blank=True, null=True)
is_completed = models.BooleanField(default=False) is_completed = models.BooleanField(default=False)
completed_date = models.DateTimeField(null=True,blank=True) completed_date = models.DateTimeField(null=True,blank=True)
service = models.ForeignKey(Service, on_delete=models.CASCADE, related_name="service_offered") service = models.ForeignKey(Service, on_delete=models.CASCADE, related_name="service_offered")
def __str__(self): def __str__(self):
return self.service.name return self.service.name

@ -5,7 +5,7 @@
<header class="bg-primary text-white text-center py-5"> <header class="bg-primary text-white text-center py-5">
<div class="container"> <div class="container">
<h1>Welcome to Sahara</h1> <h1>Welcome to Sahara</h1>
<p>Your one-stop platform for elder care services.</p> <p>Your one-stop platform for elder cure serviecs.</p>
</div> </div>
</header> </header>
@ -24,26 +24,6 @@
<li><a href="{% url 'home' %}?category={{ service.id }}" class="category-link">{{ service.name }}</a></li> <li><a href="{% url 'home' %}?category={{ service.id }}" class="category-link">{{ service.name }}</a></li>
{% endfor %} {% endfor %}
</ul> </ul>
<h4>Price</h4>
<input
type="number"
class="form-control"
id="basePriceInput"
value="100"
min="1"
step="0.01">
<input
type="range"
class="form-range"
min="0.5"
max="2"
step="0.01"
value="1"
id="ratioSlider">
<p class="fs-5">
<strong>Price:</strong> Rs.<span id="price">100.00</span>
(<span id="ratio">1.00</span>x)
</p>
</div> </div>
</div> </div>
@ -67,7 +47,7 @@
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<p class="price mb-0">Rs. {{ user.price|floatformat:2 }}</p> <p class="price mb-0">Rs. {{ user.price|floatformat:2 }}</p>
<!-- Hire button --> <!-- Hire button -->
<button class="btn btn-primary btn-sm ms-auto" data-bs-toggle="modal" data-bs-target="#hireModal" data-name="{{ user.first_name }} {{ user.last_name }}" data-bio="{{ user.bio }}" data-price="{{ user.price|floatformat:2 }}" data-id="{{ user.id }}">Hire</button> <button class="btn btn-primary btn-sm ms-auto" data-bs-toggle="modal" data-bs-target="#hireModal" data-id="{{user.id}}" data-name="{{ user.first_name }} {{ user.last_name }}" data-email="{{ user.email }}" data-contact = "{{ user.phone_number }}" data-bio="{{ user.bio }}" data-price="{{ user.price|floatformat:2 }}" data-id="{{ user.id }}">Hire</button>
</div> </div>
</div> </div>
</div> </div>
@ -90,24 +70,44 @@
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<form id="hireForm"> <form id="hireForm" method="POST">
{% csrf_token %}
<div class="mb-3"> <div class="mb-3">
<label for="caretakerName" class="form-label">Caretaker Name</label> <label for="caretakerName" class="form-label">Caretaker Name</label>
<input type="text" class="form-control" id="caretakerName" disabled> <input type="text" class="form-control" name="caretakerName" id="caretakerName" disabled>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="caretakerBio" class="form-label">Bio</label> <label for="caretakerBio" class="form-label">Bio</label>
<textarea class="form-control" id="caretakerBio" rows="3" disabled></textarea> <textarea class="form-control" id="caretakerBio" name="caretakerBio" rows="3" disabled></textarea>
</div>
<div class="mb-3">
<label for="caretakeremail" class="form-label">Email Address</label>
<textarea class="form-control" id="caretakeremail" name = "caretakeremail" rows="3" disabled></textarea>
</div>
<div class="mb-3">
<label for="caretakercontact" class="form-label">Contact no</label>
<textarea class="form-control" id="caretakercontact" name="caretakercontact" rows="3" disabled></textarea>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="caretakerPrice" class="form-label">Price</label> <label for="caretakerPrice" class="form-label">Price</label>
<input type="text" class="form-control" id="caretakerPrice" disabled> <input type="text" class="form-control" id="caretakerPrice" name="caretakercontact" price="caretakercontact">
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="caretakerService" class="form-label">Service</label> <label for="serviceHour" class="form-label">Hours to Hire</label>
<input type="text" class="form-control" id="caretakerService" disabled> <input type="number" class="form-control" id="serviceHour" name="serviceHour">
</div> </div>
<button type="submit" class="btn btn-primary">Confirm Hire</button> <div class="mb-3">
<label for="service" class="form-label">Service </label>
<select class="form-control" id="caretakerservice" name="caretakerservice">
{% for service in services %}
<option value={{service.id}}>{{service.name}}</option>
{% endfor %}
</select>
</div>
<div class="mb-3">
<input type="hidden" class="form-control" id="caretakerid" name="caretakerid" disabled>
</div>
<a "btn btn-primary" href="javascript:sendRequest()" >Send Request</a>
</form> </form>
</div> </div>
</div> </div>
@ -127,26 +127,68 @@
const bio = button.getAttribute('data-bio'); const bio = button.getAttribute('data-bio');
const price = button.getAttribute('data-price'); const price = button.getAttribute('data-price');
const serviceId = button.getAttribute('data-id'); const serviceId = button.getAttribute('data-id');
const contact = button.getAttribute('data-contact');
const email = button.getAttribute('data-email');
const id = button.getAttribute('data-id');
// Populate the modal fields
document.getElementById('caretakerName').value = name; document.getElementById('caretakerName').value = name;
document.getElementById('caretakerBio').value = bio; document.getElementById('caretakerBio').value = bio;
document.getElementById('caretakerPrice').value = price; document.getElementById('caretakerPrice').value = price;
// Fetch service name based on service ID (optional, if needed) document.getElementById('caretakeremail').value = email;
fetch(`/get-service-name/${serviceId}/`) document.getElementById('caretakercontact').value = contact;
.then(response => response.json()) document.getElementById('caretakerid').value = id;
.then(data => {
document.getElementById('caretakerService').value = data.service_name;
}); });
const sendRequest = async () => {
try {
const price = document.getElementById('caretakerPrice').value;
const serviceHour = document.getElementById('serviceHour').value;
const serviceProviderId = document.getElementById('caretakerid').value;
const caretakerservice = document.getElementById('caretakerservice').value;
const csrfToken = document.querySelector('[name=csrfmiddlewaretoken]').value;
const hireUrl = "{% url 'hire' %}";
const initiatorId = "{{ request.user.id }}";
const response = await fetch(hireUrl, {
method: "POST",
headers: {
"Content-Type": "application/json; charset=UTF-8",
"X-CSRFToken": csrfToken,
},
body: JSON.stringify({
price: price,
initiator: initiatorId,
serviceProvider: serviceProviderId,
serviceHour: serviceHour,
caretakerservice: caretakerservice,
})
}); });
if (!response.ok) {
const errorText = await response.text();
throw new Error(errorText);
}
const data = await response.json();
console.log('Request was successful:', data);
window.location.href = window.location.href;
} catch (error) {
console.error('There was an error with the request:', error.message);
alert('There was an error with your request: ' + error.message);
}
};
const sendSearch = () => { const sendSearch = () => {
let url = window.location.href; let url = window.location.href;
const searchTerm = document.getElementById("search").value; const searchTerm = document.getElementById("search").value;
url = url.split('?')[0] + "?search=" + encodeURIComponent(searchTerm); url = url.split('?')[0] + "?search=" + encodeURIComponent(searchTerm);
window.location.href = url; window.location.href = url;
} }
</script> </script>
{% endblock %} {% endblock %}

@ -0,0 +1,126 @@
{% extends 'base.html' %}
{% load static %}
{% block content %}
<style>
body {
background-color: #f8f9fa;
}
.profile-header {
background-color: #007bff;
color: white;
padding: 20px;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20px;
}
.profile-header .left {
display: flex;
align-items: center;
}
.profile-header img {
border-radius: 50%;
width: 100px;
height: 100px;
margin-right: 20px;
}
.profile-details {
margin-bottom: 20px;
}
.card {
border: none;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.status-badge {
padding: 5px 10px;
border-radius: 5px;
color: white;
}
.status-active {
background-color: #28a745;
}
.status-complete {
background-color: #17a2b8;
}
</style>
<div class="container mt-4">
<!-- Profile Header -->
<div class="profile-header">
<div class="left">
{% if user.profile and user.profile.url %}
<img src="{{ user.profile.url }}" alt="Profile Picture">
{% else %}
<img src="{% static 'img/dummypic.png' %}" alt="Profile Picture">
{% endif %}
<div>
<h2>{{ user.first_name|capfirst }} {{ user.last_name|capfirst }}</h2>
<p>Customer ID: {{ user.id }}</p>
</div>
</div>
<div>
<p>Member Since: {{ user.member_since|date:"b - Y" }}</p>
<p>Status: Active</p>
</div>
</div>
<!-- Profile Details -->
<div class="profile-details">
<div class="row">
<div class="col-md-12">
<div class="card p-6">
<h5>Contact Information</h5>
<p>Email: {{ user.email }}</p>
<p>Phone: (+977) {{ user.phone_number }}</p>
<p>Address: {{ user.address }}</p>
</div>
</div>
</div>
</div>
{% if request.user == user %}
<!-- Pending/Active Requests -->
<div class="recent-activities">
<h4 class="mb-3">Pending/Active Requests</h4>
<div class="card p-3">
<ul class="list-group list-group-flush">
{% for req in pending_requests %}
<li class="list-group-item d-flex justify-content-between align-items-center">
{{ req.service_offered }} request from {{ req.client.first_name|capfirst }} {{ req.client.last_name|capfirst }}
<a class="status-badge status-active">Accept</a>
</li>
{% empty %}
<li class="list-group-item d-flex justify-content-between align-items-center">
Hurray! There are no Pending Requests till now.
</li>
{% endfor %}
</ul>
</div>
</div>
<!-- Completed Services -->
<div class="recent-activities mt-4">
<h4 class="my-3">Completed/Active Requests</h4>
<div class="card p-3">
<ul class="list-group list-group-flush">
{% for service in current %}
<li class="list-group-item d-flex justify-content-between align-items-center">
{{ service.service_offered }} request from {{ service.client.first_name|capfirst }} {{ service.client.last_name|capfirst }}
<a class="status-badge status-complete">Complete</a>
</li>
{% empty %}
<li class="list-group-item d-flex justify-content-between align-items-center">
There are no active tasks right now.
</li>
{% endfor %}
</ul>
</div>
</div>
{% endif %}
</div>
{% endblock %}

@ -0,0 +1,164 @@
{% extends 'base.html' %}
{% block content %}
<style>
/* General Styles */
body {
margin: 0;
font-family: Arial, sans-serif;
}
h1, h2 {
text-align: center;
color: #333;
}
.section {
padding: 50px 20px;
background-color: #fdf6e3; /* Beige background */
margin: 20px auto;
width: 80%;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
opacity: 0;
transform: translateX(-100px);
transition: all 0.8s ease-in-out;
}
.section.visible {
opacity: 1;
transform: translateX(0);
}
.service {
display: flex;
align-items: center;
margin-top: 20px;
}
.service img {
width: 100px;
height: 100px;
border-radius: 8px;
margin-right: 20px;
}
.service p {
font-size: 16px;
line-height: 1.6;
}
.services-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
margin-top: 40px;
}
.grid-item {
background-color: #ffffff;
padding: 20px;
border-radius: 8px;
text-align: center;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
opacity: 0;
transform: translateY(100px);
transition: all 0.8s ease-in-out;
}
.grid-item.visible {
opacity: 1;
transform: translateY(0);
}
.grid-item img {
width: 80px;
height: 80px;
margin-bottom: 10px;
}
.grid-item h3 {
margin: 10px 0;
font-size: 18px;
}
.grid-item p {
font-size: 14px;
color: #555;
}
</style>
</head>
<body>
<h1>Services</h1>
<section class="section" id="service-1">
<h2>Our Services</h2>
<div class="service">
<img src="https://via.placeholder.com/100" alt="Service Image">
<p>I am a tech-savvy individual with a Bachelor's degree in Software Development, seeking employment as a mobile game developer. I am passionate about consistently advancing my knowledge and skills. I have attended multiple seminars and boot camps on coding and game development.</p>
</div>
</section>
<section class="section" id="service-2">
<h2>What We Offer</h2>
<div class="service">
<img src="https://via.placeholder.com/100" alt="Service Image">
<p>I am a tech-savvy individual with a Bachelor's degree in Software Development, seeking employment as a mobile game developer. I am passionate about consistently advancing my knowledge and skills. I have attended multiple seminars and boot camps on coding and game development.</p>
</div>
</section>
<section class="section" id="services-grid">
<h2>Our Web App Provides</h2>
<div class="services-grid">
<div class="grid-item">
<img src="https://via.placeholder.com/80" alt="Feature 1">
<h3>Feature 1</h3>
<p>Detail about the first feature of the web app.</p>
</div>
<div class="grid-item">
<img src="https://via.placeholder.com/80" alt="Feature 2">
<h3>Feature 2</h3>
<p>Detail about the second feature of the web app.</p>
</div>
<div class="grid-item">
<img src="https://via.placeholder.com/80" alt="Feature 3">
<h3>Feature 3</h3>
<p>Detail about the third feature of the web app.</p>
</div>
<div class="grid-item">
<img src="https://via.placeholder.com/80" alt="Feature 4">
<h3>Feature 4</h3>
<p>Detail about the fourth feature of the web app.</p>
</div>
</div>
</section>
<script>
// Function to check if element is in viewport
function isInViewport(element) {
const rect = element.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}
// Function to add "visible" class to sections
function handleScroll() {
const sections = document.querySelectorAll('.section, .grid-item');
sections.forEach(section => {
if (isInViewport(section)) {
section.classList.add('visible');
}
});
}
// Listen for scroll event
window.addEventListener('scroll', handleScroll);
// Trigger scroll event on load to show elements already in view
window.addEventListener('load', handleScroll);
</script>
{% endblock %}

@ -5,7 +5,9 @@ urlpatterns = [
path('', views.home, name="home"), path('', views.home, name="home"),
path('register/', views.register, name='register'), path('register/', views.register, name='register'),
path('activate/<str:uidb64>/<str:token>/', views.activate_account, name='activate_account'), path('activate/<str:uidb64>/<str:token>/', views.activate_account, name='activate_account'),
# path('verify-email/<str:uidb64>/<str:token>/', views.verify_email, name='verify_email'),
path('login/', views.user_login, name='login'), path('login/', views.user_login, name='login'),
path('logout/', views.user_logout, name='logout'), path('logout/', views.user_logout, name='logout'),
path('hire/', views.hire_view, name='hire'),
path('services/',views.services,name='services'),
path('profiles/<pk>',views.profie_View, name="profiles")
] ]

@ -1,17 +1,22 @@
from django.shortcuts import render, redirect,HttpResponse,get_list_or_404 from django.shortcuts import render, redirect,HttpResponse,get_object_or_404
from django.contrib.auth import login, logout, authenticate from django.contrib.auth import login, logout, authenticate
from django.contrib.auth.tokens import default_token_generator from django.contrib.auth.tokens import default_token_generator
from django.utils.http import urlsafe_base64_decode from django.utils.http import urlsafe_base64_decode
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.contrib import messages from django.contrib import messages
from .models import User,Service from .models import User,Service,ServiceRequest
from .forms import UserRegistrationForm from .forms import UserRegistrationForm
import logging import logging
import json
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_protect
logger = logging.getLogger('main') logger = logging.getLogger('main')
def home(request): def home(request):
if(request.method == "GET"):
category = request.GET.get('category') category = request.GET.get('category')
search = request.GET.get('search')
services = Service.objects.all() services = Service.objects.all()
if category: if category:
try: try:
@ -19,17 +24,26 @@ def home(request):
service_providers = User.objects.filter(service_offered=service) service_providers = User.objects.filter(service_offered=service)
except Service.DoesNotExist: except Service.DoesNotExist:
service_providers = [] service_providers = []
elif search:
try:
service_providers = User.objects.filter(first_name__startswith=search)
except Service.DoesNotExist:
service_providers = []
else: else:
service_providers = User.objects.filter(service_offered__isnull=False) service_providers = User.objects.filter(service_offered__isnull=False)
context = { context = {
'service_providers': service_providers, 'service_providers': service_providers,
'services': services 'services': services
} }
return render(request, "main/home.html", context) return render(request, "main/home.html", context)
print(request.POST)
return HttpResponse("<h1>tjisfjsa<h1>")
def register(request): def register(request):
if request.user.is_authenticated:
messages.warning(request,"You are already logged in. Please Logout first to register ")
return redirect('home')
if request.method == 'POST' and request.FILES: if request.method == 'POST' and request.FILES:
form = UserRegistrationForm(request.POST,request.FILES, instance=request.user) form = UserRegistrationForm(request.POST,request.FILES, instance=request.user)
if form.is_valid(): if form.is_valid():
@ -38,7 +52,7 @@ def register(request):
user.save() user.save()
try: try:
user.send_verification_email() user.send_verification_email(user)
messages.success(request, 'Registration successful! Please check your email to activate your account.') messages.success(request, 'Registration successful! Please check your email to activate your account.')
except Exception as e: except Exception as e:
logger.error(f"Error sending verification email: {e}") logger.error(f"Error sending verification email: {e}")
@ -67,24 +81,29 @@ def activate_account(request, uidb64, token):
return redirect('register') return redirect('register')
def user_login(request): def user_login(request):
print(request.user.is_authenticated)
if request.user.is_authenticated: if request.user.is_authenticated:
messages.info(request, f'You are already logged in as {request.user}')
return redirect('home') return redirect('home')
else: else:
if request.method == 'POST': if request.method == 'POST':
email = request.POST['email'] email = request.POST['email']
password = request.POST['password'] password = request.POST['password']
# Authenticate the user using the email and password
user = authenticate(request, email=email, password=password) user = authenticate(request, email=email, password=password)
if user is not None: if user is not None:
form = login(request, user) # Log the user in
messages.success(request, f' welcome {user} !!') login(request, user)
messages.success(request, f'Welcome {user}!')
return redirect('home') return redirect('home')
else: else:
messages.info(request, f'Something went wrong') # If authentication fails
messages.error(request, 'Invalid email or password. Please try again.')
messages.info(request, f'You are Already Logged in as {request.user}')
return render(request, 'main/login.html', {'title':'log in'})
# Handle GET request by initializing a blank form
form = None # Optionally, you can replace this with your login form
return render(request, 'main/login.html', {'form': form})
@login_required @login_required
def user_logout(request): def user_logout(request):
@ -92,7 +111,70 @@ def user_logout(request):
messages.success(request, 'You have been logged out.') messages.success(request, 'You have been logged out.')
return redirect('login') return redirect('login')
# def verify_email(request, uidb64, token): def services(request):
# # This view is redundant if it does the same as activate_account return render(request,'main/services1.html')
# # Consider removing or assigning a different purpose
# pass @login_required
@csrf_protect
def hire_view(request):
if request.method == 'POST':
try:
data = json.loads(request.body)
price = data.get('price')
initiator_id = data.get('initiator')
service_provider_id = data.get('serviceProvider')
service_hour = data.get('serviceHour')
caretakerservice_id = data.get('caretakerservice')
# Validate required fields
if not price or not initiator_id or not service_provider_id or not service_hour or not caretakerservice_id:
return JsonResponse({'error': 'Missing required fields'}, status=400)
# Validate initiator
if str(request.user.id) != str(initiator_id):
return JsonResponse({'error': 'Unauthorized initiator'}, status=401)
# Retrieve service provider and service
service_provider = get_object_or_404(User, id=service_provider_id)
service = get_object_or_404(Service, id=caretakerservice_id)
# Create and save the service request
service_request = ServiceRequest(
agreed_price=price,
service_provider=service_provider,
client=request.user,
service_hour=service_hour,
service=service
)
service_request.save()
messages.success(request, 'Request submitted successfully!')
return JsonResponse({'success': 'Request submitted successfully!'}, status=201)
except json.JSONDecodeError:
messages.error(request, 'Invalid JSON format')
return JsonResponse({'error': 'Invalid JSON format'}, status=400)
except User.DoesNotExist:
messages.error(request, 'Service provider does not exist')
return JsonResponse({'error': 'Service provider does not exist'}, status=404)
except Service.DoesNotExist:
messages.error(request, 'Service does not exist')
return JsonResponse({'error': 'Service does not exist'}, status=404)
except Exception as e:
messages.error(request, f'An error occurred: {str(e)}')
return JsonResponse({'error': 'An error occurred'}, status=500)
else:
messages.error(request, 'Invalid request method')
return JsonResponse({'error': 'Invalid request method'}, status=405)
def profie_View(request,pk):
if request.method == "GET":
user = get_object_or_404(User,id=pk)
pending_requests = ServiceRequest.objects.filter(service_provider=user, is_approved=False)
current = ServiceRequest.objects.filter(service_provider=user, is_approved=True)
completed = ServiceRequest.objects.filter(service_provider=user, is_completed=True)
context = {'user':user,
'pending_requests':pending_requests,
'completed_orders' : completed
}
return render(request,'main/profile.html', context)

@ -142,3 +142,59 @@ body {
min-height: 100vh; min-height: 100vh;
background: url('img/backgroung-form.jpg') no-repeat center center/cover; background: url('img/backgroung-form.jpg') no-repeat center center/cover;
} }
/* status for history */
.status-badge {
font-size: 0.9em;
padding: 0.25em 0.6em;
border-radius: 10px;
margin-left: 10px;
}
.status-active {
background-color: #28a745;
color: white;
}
.status-inactive {
background-color: #dc3545;
color: white;
}
footer {
margin-top: 50px;
}
/* darken */
header {
position: relative;
background: url('../img/background.jpg') no-repeat center center/cover;
height: 300px;
width: 100%;
}
header::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5); /* Dark overlay */
z-index: 1; /* Make sure the overlay is above the image but below the text */
}
header .container {
position: relative;
z-index: 2; /* Ensure the text appears above the overlay */
}
header h1 {
font-size: 2.5rem; /* Larger text for better visibility */
font-weight: bold;
color: #fff; /* White text for contrast */
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.7); /* Adding shadow to make text pop */
}
header p {
font-size: 1.2rem;
color: #fff; /* White text for contrast */
text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.7); /* Subtle shadow for better legibility */
}

@ -0,0 +1,144 @@
body {
background-color:#ffffff;
}
.navbar .navbar-brand {
margin-right: auto;
}
.navbar .nav {
margin: 0 auto;
text-align: center;
}
.navbar .login {
margin-left: auto;
}
.search-bar {
margin-top: 20px;
display: flex;
justify-content: center;
align-items: center;
}
.search-bar input {
width: 50%;
border-radius: 50px;
}
.profile-card {
border: 1px solid #ddd;
border-radius: 10px;
overflow: hidden;
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.profile-card:hover {
transform: translateY(-10px);
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
}
.profile-card img {
width: 100%;
height: 200px;
object-fit: cover;
object-position: 10%;
}
.profile-card .card-body {
padding: 15px;
}
.profile-card .card-title {
font-size: 1.25rem;
font-weight: bold;
margin-bottom: 10px;
}
.profile-card .card-text {
font-size: 0.9rem;
color: #555;
}
.profile-card .price {
font-size: 1.1rem;
font-weight: bold;
color: #007bff;
}
.profile-card .availability {
font-size: 0.9rem;
color: #28a745;
}
.category-bar {
background-color: #f8f9fa; /* Light background */
padding: 20px;
border-radius: 10px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); /* Subtle shadow */
}
.category-bar h4 {
font-size: 1.25rem;
font-weight: bold;
margin-bottom: 15px;
color: #333;
}
.category-bar ul {
padding-left: 0;
}
.category-bar .category-link {
display: block;
padding: 10px 15px;
margin: 5px 0;
color: #555;
text-decoration: none;
border-radius: 5px;
transition: background-color 0.3s ease, color 0.3s ease;
}
.category-bar .category-link:hover {
background-color: #007bff; /* Highlight on hover */
color: #fff;
}
/* odd */
.form-container {
font-family: Arial, sans-serif;
margin: auto;
padding: 30px;
background: rgba(255, 255, 255, 0.9);
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
width: 600px;
}
.form-container h2 {
margin-bottom: 20px;
}
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 5px;
}
.form-group input,
.form-group textarea,
.form-group select {
width: 100%;
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
}
.form-group input[type="file"] {
padding: 5px;
}
.form-group button {
width: 100%;
padding: 10px;
background-color: #007BFF;
color: #fff;
border: none;
border-radius: 5px;
cursor: pointer;
}
.form-group button:hover {
background-color: #0056b3;
}
.form-wrapper {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: url('img/backgroung-form.jpg') no-repeat center center/cover;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 492 KiB

@ -10,30 +10,42 @@
<link rel="stylesheet" href="{% static 'css/styles.css' %}"> <link rel="stylesheet" href="{% static 'css/styles.css' %}">
</head> </head>
<body> <body>
<nav class="navbar navbar-expand-lg bg-body-tertiary"> <div class="bg-body-tertiary">
<nav class="navbar container navbar-expand-lg">
<div class="container-fluid"> <div class="container-fluid">
<a class="navbar-brand" href="#"><img src="{% static 'img/logofinal.png' %}" height="50px" width="75px" alt="Logo"></a> <a class="navbar-brand" href="{% url 'home' %}"><img src="{% static 'img/logofinal.png' %}" height="50px" width="75px" alt="Logo"></a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation"> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span> <span class="navbar-toggler-icon"></span>
</button> </button>
<ul class="nav justify-content-center"> <ul class="nav justify-content-center">
<li class="nav-item"> <li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">Home</a> <a class="nav-link active" aria-current="page" href="{% url 'home' %}">Home</a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="#">About us</a> <a class="nav-link" href="#">About us</a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="#">Services</a> <a class="nav-link" href="{% url 'services' %}">Services</a>
</li> </li>
{% if request.user.is_authenticated %}
<li class="nav-item">
<a class="nav-link" href="{% url 'profiles' request.user.id %}">Profile</a>
</li>
{% endif %}
</ul> </ul>
<div class="login"> <div class="login">
<a href="#" class="btn btn-outline-primary">Login</a> {% if request.user.is_authenticated %}
<a href="{% url 'logout' %}" class="btn btn-outline-primary">Log Out</a>
{% else %}
<a href="{% url 'register' %}" class="btn btn-outline-success">SignUp</a>
<a href="{% url 'login' %}" class="btn btn-outline-primary">Log In</a>
{% endif %}
</div> </div>
</div> </div>
</div> </div>
</nav> </nav>
</div>
<div class="container mt-3"> <div class="container mt-3">
{% for message in messages %} {% for message in messages %}
<div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert"> <div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert">
@ -47,3 +59,7 @@
{% block content %} {% block content %}
{% endblock %} {% endblock %}
<footer class="bg-dark text-white text-center py-3">
<p>&copy; 2025 Sahara. All Rights Reserved. | <a href="#" class="text-white">Privacy Policy</a> | <a href="#" class="text-white">Terms of Service</a></p>
</footer>
Loading…
Cancel
Save