diff --git a/sahara/db.sqlite3 b/sahara/db.sqlite3 index 33e0fb4..3638b51 100644 Binary files a/sahara/db.sqlite3 and b/sahara/db.sqlite3 differ diff --git a/sahara/main/__pycache__/models.cpython-312.pyc b/sahara/main/__pycache__/models.cpython-312.pyc index eb99c66..6bcbb4c 100644 Binary files a/sahara/main/__pycache__/models.cpython-312.pyc and b/sahara/main/__pycache__/models.cpython-312.pyc differ diff --git a/sahara/main/__pycache__/urls.cpython-312.pyc b/sahara/main/__pycache__/urls.cpython-312.pyc index 2496d92..92ca9d0 100644 Binary files a/sahara/main/__pycache__/urls.cpython-312.pyc and b/sahara/main/__pycache__/urls.cpython-312.pyc differ diff --git a/sahara/main/__pycache__/views.cpython-312.pyc b/sahara/main/__pycache__/views.cpython-312.pyc index a00c760..75dc713 100644 Binary files a/sahara/main/__pycache__/views.cpython-312.pyc and b/sahara/main/__pycache__/views.cpython-312.pyc differ diff --git a/sahara/main/migrations/0006_servicerequest_phone_number.py b/sahara/main/migrations/0006_servicerequest_phone_number.py new file mode 100644 index 0000000..8a38a9c --- /dev/null +++ b/sahara/main/migrations/0006_servicerequest_phone_number.py @@ -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), + ), + ] diff --git a/sahara/main/migrations/0007_remove_servicerequest_phone_number_user_phone_number.py b/sahara/main/migrations/0007_remove_servicerequest_phone_number_user_phone_number.py new file mode 100644 index 0000000..5636c37 --- /dev/null +++ b/sahara/main/migrations/0007_remove_servicerequest_phone_number_user_phone_number.py @@ -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), + ), + ] diff --git a/sahara/main/migrations/0008_alter_servicerequest_is_approved.py b/sahara/main/migrations/0008_alter_servicerequest_is_approved.py new file mode 100644 index 0000000..131dc80 --- /dev/null +++ b/sahara/main/migrations/0008_alter_servicerequest_is_approved.py @@ -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), + ), + ] diff --git a/sahara/main/migrations/0009_alter_servicerequest_is_approved.py b/sahara/main/migrations/0009_alter_servicerequest_is_approved.py new file mode 100644 index 0000000..87d76a0 --- /dev/null +++ b/sahara/main/migrations/0009_alter_servicerequest_is_approved.py @@ -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), + ), + ] diff --git a/sahara/main/migrations/__pycache__/0006_servicerequest_phone_number.cpython-312.pyc b/sahara/main/migrations/__pycache__/0006_servicerequest_phone_number.cpython-312.pyc new file mode 100644 index 0000000..eccbadf Binary files /dev/null and b/sahara/main/migrations/__pycache__/0006_servicerequest_phone_number.cpython-312.pyc differ diff --git a/sahara/main/migrations/__pycache__/0007_remove_servicerequest_phone_number_user_phone_number.cpython-312.pyc b/sahara/main/migrations/__pycache__/0007_remove_servicerequest_phone_number_user_phone_number.cpython-312.pyc new file mode 100644 index 0000000..68786f7 Binary files /dev/null and b/sahara/main/migrations/__pycache__/0007_remove_servicerequest_phone_number_user_phone_number.cpython-312.pyc differ diff --git a/sahara/main/migrations/__pycache__/0008_alter_servicerequest_is_approved.cpython-312.pyc b/sahara/main/migrations/__pycache__/0008_alter_servicerequest_is_approved.cpython-312.pyc new file mode 100644 index 0000000..e0a972c Binary files /dev/null and b/sahara/main/migrations/__pycache__/0008_alter_servicerequest_is_approved.cpython-312.pyc differ diff --git a/sahara/main/migrations/__pycache__/0009_alter_servicerequest_is_approved.cpython-312.pyc b/sahara/main/migrations/__pycache__/0009_alter_servicerequest_is_approved.cpython-312.pyc new file mode 100644 index 0000000..8a8f8c2 Binary files /dev/null and b/sahara/main/migrations/__pycache__/0009_alter_servicerequest_is_approved.cpython-312.pyc differ diff --git a/sahara/main/models.py b/sahara/main/models.py index 257ba59..1eeaf3e 100644 --- a/sahara/main/models.py +++ b/sahara/main/models.py @@ -55,7 +55,6 @@ class UserManager(BaseUserManager): return self.create_user(first_name, last_name, email, password, **extra_fields) def send_verification_email(self, user): - # Generate the token and the uid for the verification URL token = default_token_generator.make_token(user) uid = urlsafe_base64_encode(force_bytes(user.pk)) 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) member_since = models.DateTimeField(auto_now_add=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) login_profile = models.CharField( max_length=15, @@ -112,6 +112,11 @@ class User(AbstractBaseUser, PermissionsMixin): def get_short_name(self): return self.first_name + @property + def url(self): + if self.profile_picture: + return self.profile_picture.url + return None class ServiceRequest(models.Model): client = models.ForeignKey(User,on_delete=models.CASCADE,related_name="client") @@ -119,11 +124,12 @@ class ServiceRequest(models.Model): agreed_price = models.DecimalField(max_digits=999,decimal_places=2 , default=0) service_hour = models.PositiveIntegerField(default=1) 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) is_completed = models.BooleanField(default=False) completed_date = models.DateTimeField(null=True,blank=True) service = models.ForeignKey(Service, on_delete=models.CASCADE, related_name="service_offered") + def __str__(self): return self.service.name diff --git a/sahara/main/templates/main/home.html b/sahara/main/templates/main/home.html index 0a76e01..d6e46da 100644 --- a/sahara/main/templates/main/home.html +++ b/sahara/main/templates/main/home.html @@ -5,7 +5,7 @@

Welcome to Sahara

-

Your one-stop platform for elder care services.

+

Your one-stop platform for elder cure serviecs.

@@ -24,26 +24,6 @@
  • {{ service.name }}
  • {% endfor %} -

    Price

    - - -

    - Price: Rs.100.00 - (1.00x) -

    @@ -67,7 +47,7 @@

    Rs. {{ user.price|floatformat:2 }}

    - +
    @@ -90,24 +70,44 @@ @@ -127,26 +127,68 @@ const bio = button.getAttribute('data-bio'); const price = button.getAttribute('data-price'); 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('caretakerBio').value = bio; document.getElementById('caretakerPrice').value = price; - // Fetch service name based on service ID (optional, if needed) - fetch(`/get-service-name/${serviceId}/`) - .then(response => response.json()) - .then(data => { - document.getElementById('caretakerService').value = data.service_name; - }); + document.getElementById('caretakeremail').value = email; + document.getElementById('caretakercontact').value = contact; + document.getElementById('caretakerid').value = id; }); + + +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 = () => { let url = window.location.href; const searchTerm = document.getElementById("search").value; url = url.split('?')[0] + "?search=" + encodeURIComponent(searchTerm); window.location.href = url; } - {% endblock %} diff --git a/sahara/main/templates/main/profile.html b/sahara/main/templates/main/profile.html new file mode 100644 index 0000000..d078f42 --- /dev/null +++ b/sahara/main/templates/main/profile.html @@ -0,0 +1,126 @@ +{% extends 'base.html' %} +{% load static %} + +{% block content %} + + +
    + +
    +
    + {% if user.profile and user.profile.url %} + Profile Picture + {% else %} + Profile Picture + {% endif %} + +
    +

    {{ user.first_name|capfirst }} {{ user.last_name|capfirst }}

    +

    Customer ID: {{ user.id }}

    +
    +
    +
    +

    Member Since: {{ user.member_since|date:"b - Y" }}

    +

    Status: Active

    +
    +
    + + +
    +
    +
    +
    +
    Contact Information
    +

    Email: {{ user.email }}

    +

    Phone: (+977) {{ user.phone_number }}

    +

    Address: {{ user.address }}

    +
    +
    +
    +
    + + {% if request.user == user %} + +
    +

    Pending/Active Requests

    +
    +
      + {% for req in pending_requests %} +
    • + {{ req.service_offered }} request from {{ req.client.first_name|capfirst }} {{ req.client.last_name|capfirst }} + Accept +
    • + {% empty %} +
    • + Hurray! There are no Pending Requests till now. +
    • + {% endfor %} +
    +
    +
    + + +
    +

    Completed/Active Requests

    +
    +
      + {% for service in current %} +
    • + {{ service.service_offered }} request from {{ service.client.first_name|capfirst }} {{ service.client.last_name|capfirst }} + Complete +
    • + {% empty %} +
    • + There are no active tasks right now. +
    • + {% endfor %} +
    +
    +
    + {% endif %} +
    +{% endblock %} + diff --git a/sahara/main/templates/main/services1.html b/sahara/main/templates/main/services1.html new file mode 100644 index 0000000..66c7f1b --- /dev/null +++ b/sahara/main/templates/main/services1.html @@ -0,0 +1,164 @@ +{% extends 'base.html' %} + +{% block content %} + + + +

    Services

    + +
    +

    Our Services

    +
    + Service Image +

    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.

    +
    +
    + +
    +

    What We Offer

    +
    + Service Image +

    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.

    +
    +
    + +
    +

    Our Web App Provides

    +
    +
    + Feature 1 +

    Feature 1

    +

    Detail about the first feature of the web app.

    +
    +
    + Feature 2 +

    Feature 2

    +

    Detail about the second feature of the web app.

    +
    +
    + Feature 3 +

    Feature 3

    +

    Detail about the third feature of the web app.

    +
    +
    + Feature 4 +

    Feature 4

    +

    Detail about the fourth feature of the web app.

    +
    +
    +
    + + +{% endblock %} \ No newline at end of file diff --git a/sahara/main/urls.py b/sahara/main/urls.py index 82d2a3a..c6bf744 100644 --- a/sahara/main/urls.py +++ b/sahara/main/urls.py @@ -5,7 +5,9 @@ urlpatterns = [ path('', views.home, name="home"), path('register/', views.register, name='register'), path('activate///', views.activate_account, name='activate_account'), - # path('verify-email///', views.verify_email, name='verify_email'), path('login/', views.user_login, name='login'), path('logout/', views.user_logout, name='logout'), + path('hire/', views.hire_view, name='hire'), + path('services/',views.services,name='services'), + path('profiles/',views.profie_View, name="profiles") ] \ No newline at end of file diff --git a/sahara/main/views.py b/sahara/main/views.py index 67d52db..be646c3 100644 --- a/sahara/main/views.py +++ b/sahara/main/views.py @@ -1,35 +1,49 @@ -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.tokens import default_token_generator from django.utils.http import urlsafe_base64_decode from django.contrib.auth.decorators import login_required from django.contrib import messages -from .models import User,Service +from .models import User,Service,ServiceRequest from .forms import UserRegistrationForm import logging +import json +from django.http import JsonResponse +from django.views.decorators.csrf import csrf_protect logger = logging.getLogger('main') def home(request): - category = request.GET.get('category') - services = Service.objects.all() - if category: - try: - service = Service.objects.get(id=category) - service_providers = User.objects.filter(service_offered=service) - except Service.DoesNotExist: - service_providers = [] - else: - service_providers = User.objects.filter(service_offered__isnull=False) - - context = { - 'service_providers': service_providers, - 'services': services - } + if(request.method == "GET"): + category = request.GET.get('category') + search = request.GET.get('search') + services = Service.objects.all() + if category: + try: + service = Service.objects.get(id=category) + service_providers = User.objects.filter(service_offered=service) + except Service.DoesNotExist: + service_providers = [] + elif search: + try: + service_providers = User.objects.filter(first_name__startswith=search) + except Service.DoesNotExist: + service_providers = [] + else: + service_providers = User.objects.filter(service_offered__isnull=False) + context = { + 'service_providers': service_providers, + 'services': services + } - return render(request, "main/home.html", context) + return render(request, "main/home.html", context) + print(request.POST) + return HttpResponse("

    tjisfjsa

    ") 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: form = UserRegistrationForm(request.POST,request.FILES, instance=request.user) if form.is_valid(): @@ -38,7 +52,7 @@ def register(request): user.save() try: - user.send_verification_email() + user.send_verification_email(user) messages.success(request, 'Registration successful! Please check your email to activate your account.') except Exception as e: logger.error(f"Error sending verification email: {e}") @@ -67,24 +81,29 @@ def activate_account(request, uidb64, token): return redirect('register') def user_login(request): - print(request.user.is_authenticated) if request.user.is_authenticated: + messages.info(request, f'You are already logged in as {request.user}') return redirect('home') else: if request.method == 'POST': email = request.POST['email'] password = request.POST['password'] - user = authenticate(request, email = email, password = password) + + # Authenticate the user using the email and password + user = authenticate(request, email=email, password=password) + if user is not None: - form = login(request, user) - messages.success(request, f' welcome {user} !!') + # Log the user in + login(request, user) + messages.success(request, f'Welcome {user}!') return redirect('home') - else: - messages.info(request, f'Something went wrong') + else: + # 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 def user_logout(request): @@ -92,7 +111,70 @@ def user_logout(request): messages.success(request, 'You have been logged out.') return redirect('login') -# def verify_email(request, uidb64, token): -# # This view is redundant if it does the same as activate_account -# # Consider removing or assigning a different purpose -# pass \ No newline at end of file +def services(request): + return render(request,'main/services1.html') + +@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) \ No newline at end of file diff --git a/sahara/static/css/styles.css b/sahara/static/css/styles.css index db25951..abc2fab 100644 --- a/sahara/static/css/styles.css +++ b/sahara/static/css/styles.css @@ -141,4 +141,60 @@ body { align-items: center; min-height: 100vh; 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 */ } \ No newline at end of file diff --git a/sahara/static/css/styles.css_1 b/sahara/static/css/styles.css_1 new file mode 100644 index 0000000..db25951 --- /dev/null +++ b/sahara/static/css/styles.css_1 @@ -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; +} \ No newline at end of file diff --git a/sahara/static/img/background.jpg b/sahara/static/img/background.jpg new file mode 100644 index 0000000..8c8422c Binary files /dev/null and b/sahara/static/img/background.jpg differ diff --git a/sahara/static/img/dummy pic.png b/sahara/static/img/dummy pic.png new file mode 100644 index 0000000..fd85231 Binary files /dev/null and b/sahara/static/img/dummy pic.png differ diff --git a/sahara/static/img/grandmother.png b/sahara/static/img/grandmother.png new file mode 100644 index 0000000..d557b39 Binary files /dev/null and b/sahara/static/img/grandmother.png differ diff --git a/sahara/static/profile-images/pic1.jpg b/sahara/static/profile-images/pic1.jpg new file mode 100644 index 0000000..bfbb2b8 Binary files /dev/null and b/sahara/static/profile-images/pic1.jpg differ diff --git a/sahara/templates/base.html b/sahara/templates/base.html index 4df818a..d4d4829 100644 --- a/sahara/templates/base.html +++ b/sahara/templates/base.html @@ -10,30 +10,42 @@ - +
    {% for message in messages %}