diff --git a/config/__pycache__/__init__.cpython-311.pyc b/config/__pycache__/__init__.cpython-311.pyc index 423a636..abb9e5e 100644 Binary files a/config/__pycache__/__init__.cpython-311.pyc and b/config/__pycache__/__init__.cpython-311.pyc differ diff --git a/config/__pycache__/settings.cpython-311.pyc b/config/__pycache__/settings.cpython-311.pyc index 96bce55..c051bcf 100644 Binary files a/config/__pycache__/settings.cpython-311.pyc and b/config/__pycache__/settings.cpython-311.pyc differ diff --git a/config/__pycache__/urls.cpython-311.pyc b/config/__pycache__/urls.cpython-311.pyc index 0b85e94..01d0673 100644 Binary files a/config/__pycache__/urls.cpython-311.pyc and b/config/__pycache__/urls.cpython-311.pyc differ diff --git a/config/__pycache__/wsgi.cpython-311.pyc b/config/__pycache__/wsgi.cpython-311.pyc index 9c49e09..dc8fc90 100644 Binary files a/config/__pycache__/wsgi.cpython-311.pyc and b/config/__pycache__/wsgi.cpython-311.pyc differ diff --git a/core/__pycache__/__init__.cpython-311.pyc b/core/__pycache__/__init__.cpython-311.pyc index 74b1112..8e9fc3d 100644 Binary files a/core/__pycache__/__init__.cpython-311.pyc and b/core/__pycache__/__init__.cpython-311.pyc differ diff --git a/core/__pycache__/admin.cpython-311.pyc b/core/__pycache__/admin.cpython-311.pyc index a5ed392..c16c351 100644 Binary files a/core/__pycache__/admin.cpython-311.pyc and b/core/__pycache__/admin.cpython-311.pyc differ diff --git a/core/__pycache__/apps.cpython-311.pyc b/core/__pycache__/apps.cpython-311.pyc index 6f131d4..1c28907 100644 Binary files a/core/__pycache__/apps.cpython-311.pyc and b/core/__pycache__/apps.cpython-311.pyc differ diff --git a/core/__pycache__/context_processors.cpython-311.pyc b/core/__pycache__/context_processors.cpython-311.pyc index 75bf223..10556ae 100644 Binary files a/core/__pycache__/context_processors.cpython-311.pyc and b/core/__pycache__/context_processors.cpython-311.pyc differ diff --git a/core/__pycache__/models.cpython-311.pyc b/core/__pycache__/models.cpython-311.pyc index e061640..33dad94 100644 Binary files a/core/__pycache__/models.cpython-311.pyc and b/core/__pycache__/models.cpython-311.pyc differ diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc index 5a69659..bd06905 100644 Binary files a/core/__pycache__/urls.cpython-311.pyc and b/core/__pycache__/urls.cpython-311.pyc differ diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index 2a36fd6..bbc52d0 100644 Binary files a/core/__pycache__/views.cpython-311.pyc and b/core/__pycache__/views.cpython-311.pyc differ diff --git a/core/admin.py b/core/admin.py index 8c38f3f..d255c1f 100644 --- a/core/admin.py +++ b/core/admin.py @@ -1,3 +1,18 @@ from django.contrib import admin +from .models import Donor, BloodRequest, BloodBank -# Register your models here. +@admin.register(Donor) +class DonorAdmin(admin.ModelAdmin): + list_display = ('name', 'blood_group', 'location', 'is_available') + list_filter = ('blood_group', 'is_available') + search_fields = ('name', 'location') + +@admin.register(BloodRequest) +class BloodRequestAdmin(admin.ModelAdmin): + list_display = ('patient_name', 'blood_group', 'urgency', 'status', 'created_at') + list_filter = ('blood_group', 'urgency', 'status') + search_fields = ('patient_name', 'hospital') + +@admin.register(BloodBank) +class BloodBankAdmin(admin.ModelAdmin): + list_display = ('name', 'location') diff --git a/core/migrations/0001_initial.py b/core/migrations/0001_initial.py new file mode 100644 index 0000000..2555f26 --- /dev/null +++ b/core/migrations/0001_initial.py @@ -0,0 +1,61 @@ +# Generated by Django 5.2.7 on 2026-02-17 13:38 + +import django.utils.timezone +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='BloodBank', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=100)), + ('location', models.CharField(max_length=255)), + ('stock_a_plus', models.IntegerField(default=0)), + ('stock_a_minus', models.IntegerField(default=0)), + ('stock_b_plus', models.IntegerField(default=0)), + ('stock_b_minus', models.IntegerField(default=0)), + ('stock_o_plus', models.IntegerField(default=0)), + ('stock_o_minus', models.IntegerField(default=0)), + ('stock_ab_plus', models.IntegerField(default=0)), + ('stock_ab_minus', models.IntegerField(default=0)), + ], + ), + migrations.CreateModel( + name='BloodRequest', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('patient_name', models.CharField(max_length=100)), + ('blood_group', models.CharField(choices=[('A+', 'A+'), ('A-', 'A-'), ('B+', 'B+'), ('B-', 'B-'), ('O+', 'O+'), ('O-', 'O-'), ('AB+', 'AB+'), ('AB-', 'AB-')], max_length=5)), + ('location', models.CharField(max_length=255)), + ('urgency', models.CharField(choices=[('CRITICAL', 'Critical'), ('URGENT', 'Urgent'), ('NORMAL', 'Normal')], default='NORMAL', max_length=10)), + ('hospital', models.CharField(max_length=255)), + ('contact_number', models.CharField(max_length=20)), + ('required_date', models.DateField(default=django.utils.timezone.now)), + ('status', models.CharField(default='Active', max_length=20)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ], + ), + migrations.CreateModel( + name='Donor', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=100)), + ('blood_group', models.CharField(choices=[('A+', 'A+'), ('A-', 'A-'), ('B+', 'B+'), ('B-', 'B-'), ('O+', 'O+'), ('O-', 'O-'), ('AB+', 'AB+'), ('AB-', 'AB-')], max_length=5)), + ('location', models.CharField(max_length=255)), + ('latitude', models.DecimalField(blank=True, decimal_places=6, max_digits=9, null=True)), + ('longitude', models.DecimalField(blank=True, decimal_places=6, max_digits=9, null=True)), + ('phone', models.CharField(max_length=20)), + ('is_available', models.BooleanField(default=True)), + ('last_donation_date', models.DateField(blank=True, null=True)), + ('vaccination_status', models.CharField(default='Unknown', max_length=100)), + ], + ), + ] diff --git a/core/migrations/0002_bloodbank_contact_number_bloodbank_is_24_7_and_more.py b/core/migrations/0002_bloodbank_contact_number_bloodbank_is_24_7_and_more.py new file mode 100644 index 0000000..8ce3046 --- /dev/null +++ b/core/migrations/0002_bloodbank_contact_number_bloodbank_is_24_7_and_more.py @@ -0,0 +1,38 @@ +# Generated by Django 5.2.7 on 2026-02-17 13:44 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='bloodbank', + name='contact_number', + field=models.CharField(blank=True, max_length=20, null=True), + ), + migrations.AddField( + model_name='bloodbank', + name='is_24_7', + field=models.BooleanField(default=True), + ), + migrations.AddField( + model_name='donor', + name='avatar_url', + field=models.URLField(blank=True, null=True), + ), + migrations.AddField( + model_name='donor', + name='email', + field=models.EmailField(blank=True, max_length=254, null=True), + ), + migrations.AddField( + model_name='donor', + name='last_vaccination_date', + field=models.DateField(blank=True, null=True), + ), + ] diff --git a/core/migrations/0003_donor_citizenship_no_donor_district_and_more.py b/core/migrations/0003_donor_citizenship_no_donor_district_and_more.py new file mode 100644 index 0000000..7d91b5a --- /dev/null +++ b/core/migrations/0003_donor_citizenship_no_donor_district_and_more.py @@ -0,0 +1,28 @@ +# Generated by Django 5.2.7 on 2026-02-17 13:56 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0002_bloodbank_contact_number_bloodbank_is_24_7_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='donor', + name='citizenship_no', + field=models.CharField(blank=True, max_length=50, null=True), + ), + migrations.AddField( + model_name='donor', + name='district', + field=models.CharField(default='Kathmandu', max_length=100), + ), + migrations.AddField( + model_name='donor', + name='is_verified', + field=models.BooleanField(default=False), + ), + ] diff --git a/core/migrations/__pycache__/0001_initial.cpython-311.pyc b/core/migrations/__pycache__/0001_initial.cpython-311.pyc new file mode 100644 index 0000000..c162e57 Binary files /dev/null and b/core/migrations/__pycache__/0001_initial.cpython-311.pyc differ diff --git a/core/migrations/__pycache__/0002_bloodbank_contact_number_bloodbank_is_24_7_and_more.cpython-311.pyc b/core/migrations/__pycache__/0002_bloodbank_contact_number_bloodbank_is_24_7_and_more.cpython-311.pyc new file mode 100644 index 0000000..b20e5ab Binary files /dev/null and b/core/migrations/__pycache__/0002_bloodbank_contact_number_bloodbank_is_24_7_and_more.cpython-311.pyc differ diff --git a/core/migrations/__pycache__/0003_donor_citizenship_no_donor_district_and_more.cpython-311.pyc b/core/migrations/__pycache__/0003_donor_citizenship_no_donor_district_and_more.cpython-311.pyc new file mode 100644 index 0000000..05ff597 Binary files /dev/null and b/core/migrations/__pycache__/0003_donor_citizenship_no_donor_district_and_more.cpython-311.pyc differ diff --git a/core/migrations/__pycache__/__init__.cpython-311.pyc b/core/migrations/__pycache__/__init__.cpython-311.pyc index 9c833c8..c33b24d 100644 Binary files a/core/migrations/__pycache__/__init__.cpython-311.pyc and b/core/migrations/__pycache__/__init__.cpython-311.pyc differ diff --git a/core/models.py b/core/models.py index 71a8362..b7d3d8f 100644 --- a/core/models.py +++ b/core/models.py @@ -1,3 +1,64 @@ from django.db import models +from django.utils import timezone -# Create your models here. +class Donor(models.Model): + BLOOD_GROUPS = [ + ('A+', 'A+'), ('A-', 'A-'), + ('B+', 'B+'), ('B-', 'B-'), + ('O+', 'O+'), ('O-', 'O-'), + ('AB+', 'AB+'), ('AB-', 'AB-'), + ] + name = models.CharField(max_length=100) + blood_group = models.CharField(max_length=5, choices=BLOOD_GROUPS) + district = models.CharField(max_length=100, default='Kathmandu') + location = models.CharField(max_length=255) + latitude = models.DecimalField(max_digits=9, decimal_places=6, null=True, blank=True) + longitude = models.DecimalField(max_digits=9, decimal_places=6, null=True, blank=True) + phone = models.CharField(max_length=20) + email = models.EmailField(null=True, blank=True) + is_available = models.BooleanField(default=True) + is_verified = models.BooleanField(default=False) + citizenship_no = models.CharField(max_length=50, null=True, blank=True) + last_donation_date = models.DateField(null=True, blank=True) + vaccination_status = models.CharField(max_length=100, default='Unknown') + last_vaccination_date = models.DateField(null=True, blank=True) + avatar_url = models.URLField(null=True, blank=True) + + def __str__(self): + return f"{self.name} ({self.blood_group}) - {'Verified' if self.is_verified else 'Unverified'}" + +class BloodRequest(models.Model): + URGENCY_LEVELS = [ + ('CRITICAL', 'Critical'), + ('URGENT', 'Urgent'), + ('NORMAL', 'Normal'), + ] + patient_name = models.CharField(max_length=100) + blood_group = models.CharField(max_length=5, choices=Donor.BLOOD_GROUPS) + location = models.CharField(max_length=255) + urgency = models.CharField(max_length=10, choices=URGENCY_LEVELS, default='NORMAL') + hospital = models.CharField(max_length=255) + contact_number = models.CharField(max_length=20) + required_date = models.DateField(default=timezone.now) + status = models.CharField(max_length=20, default='Active') + created_at = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return f"{self.blood_group} for {self.patient_name}" + +class BloodBank(models.Model): + name = models.CharField(max_length=100) + location = models.CharField(max_length=255) + contact_number = models.CharField(max_length=20, null=True, blank=True) + is_24_7 = models.BooleanField(default=True) + stock_a_plus = models.IntegerField(default=0) + stock_a_minus = models.IntegerField(default=0) + stock_b_plus = models.IntegerField(default=0) + stock_b_minus = models.IntegerField(default=0) + stock_o_plus = models.IntegerField(default=0) + stock_o_minus = models.IntegerField(default=0) + stock_ab_plus = models.IntegerField(default=0) + stock_ab_minus = models.IntegerField(default=0) + + def __str__(self): + return self.name diff --git a/core/templates/base.html b/core/templates/base.html index 1e7e5fb..73ae1ea 100644 --- a/core/templates/base.html +++ b/core/templates/base.html @@ -1,25 +1,272 @@ - - - {% block title %}Knowledge Base{% endblock %} - {% if project_description %} - - - - {% endif %} - {% if project_image_url %} - - - {% endif %} - {% load static %} - - {% block head %}{% endblock %} + + + {% block title %}RaktaPulse Dashboard{% endblock %} + + + + + + + + + + + + - - {% block content %}{% endblock %} - +
+ + + + +
+ +
+
+ + +
+ +
+
+ + {{ current_time|date:"D, M d, Y" }} +
+ {% if user.is_authenticated %} +
+ {{ user.username }} + Logout +
+ {% else %} +
+ Login + Register +
+ {% endif %} +
+
+ +
+ {% block content %}{% endblock %} +
+
+
+ + + + + + + {% block scripts %}{% endblock %} + diff --git a/core/templates/core/blood_bank_list.html b/core/templates/core/blood_bank_list.html new file mode 100644 index 0000000..dff5f0f --- /dev/null +++ b/core/templates/core/blood_bank_list.html @@ -0,0 +1,91 @@ +{% extends "base.html" %} +{% load static %} + +{% block title %}Blood Banks - RaktaPulse{% endblock %} + +{% block content %} +
+
+
+

Blood Banks

+

Official blood repositories and their current inventory levels.

+
+
+ +
+ {% for bank in banks %} +
+
+
+

{{ bank.name }}

+ {% if bank.is_24_7 %} + 24/7 Available + {% endif %} +
+

{{ bank.location }}

+

{{ bank.contact_number }}

+ +
Inventory Levels (Units)
+
+
+
+
A+
+
{{ bank.stock_a_plus }}
+
+
+
+
+
A-
+
{{ bank.stock_a_minus }}
+
+
+
+
+
B+
+
{{ bank.stock_b_plus }}
+
+
+
+
+
B-
+
{{ bank.stock_b_minus }}
+
+
+
+
+
O+
+
{{ bank.stock_o_plus }}
+
+
+
+
+
O-
+
{{ bank.stock_o_minus }}
+
+
+
+
+
AB+
+
{{ bank.stock_ab_plus }}
+
+
+
+
+
AB-
+
{{ bank.stock_ab_minus }}
+
+
+
+ + +
+
+ {% empty %} +
+ +

No blood banks registered in the system.

+
+ {% endfor %} +
+
+{% endblock %} diff --git a/core/templates/core/blood_request_list.html b/core/templates/core/blood_request_list.html new file mode 100644 index 0000000..f4ff8fd --- /dev/null +++ b/core/templates/core/blood_request_list.html @@ -0,0 +1,61 @@ +{% extends "base.html" %} +{% load static %} + +{% block title %}Blood Requests - RaktaPulse{% endblock %} + +{% block content %} + + +
+
+
+
+

Blood Requests

+

Current active requirements for blood in various hospitals.

+
+ +
+
+ +
+
+ {% for req in requests %} +
+
+
+ {{ req.urgency }} +
+ {{ req.blood_group }} +
+
+
{{ req.patient_name }}
+

{{ req.hospital }}

+
+
+ {{ req.created_at|timesince }} ago + Help Now +
+
+
+
+ {% empty %} +
+ +

No active blood requests at the moment.

+
+ {% endfor %} +
+
+
+{% endblock %} diff --git a/core/templates/core/donor_list.html b/core/templates/core/donor_list.html new file mode 100644 index 0000000..c91d16f --- /dev/null +++ b/core/templates/core/donor_list.html @@ -0,0 +1,103 @@ +{% extends "base.html" %} +{% load static %} + +{% block title %}Donors - RaktaPulse{% endblock %} + +{% block content %} +
+
+
+

Blood Donors

+

Find and connect with blood donors in your community.

+
+
+ +
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ Reset +
+ + +
+ +
+ {% for donor in donors %} +
+
+
+ {{ donor.blood_group }} +
+
+
+ {{ donor.name }} + {% if donor.is_verified %} + + {% endif %} + {% if donor.distance and donor.distance < 1000 %} + + {{ donor.distance|floatformat:1 }} km away + + {% endif %} +
+

{{ donor.location }}, {{ donor.district }}

+
+
+
+
+ + {% if donor.is_available %}Available{% else %}Unavailable{% endif %} + +

Phone: {{ donor.phone }}

+
+ +
+
+ {% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/core/templates/core/index.html b/core/templates/core/index.html index faec813..054a0b8 100644 --- a/core/templates/core/index.html +++ b/core/templates/core/index.html @@ -1,145 +1,382 @@ {% extends "base.html" %} +{% load static %} -{% block title %}{{ project_name }}{% endblock %} +{% block title %}RaktaPulse Dashboard - Lifeline of the Community{% endblock %} {% block head %} - - - {% endblock %} {% block content %} -
-
-

Analyzing your requirements and generating your app…

-
- Loading… +
+ +
+
+

RaktaPulse Community Dashboard

+

Overview of blood donation activity and requirements in your area.

+
-

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

-

This page will refresh automatically as the plan is implemented.

-

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

-
-
-
- Page updated: {{ current_time|date:"Y-m-d H:i:s" }} (UTC) -
-{% endblock %} \ No newline at end of file + + +
+
+
+
+ +
+
{{ stats.total_donors }}
+
Registered Donors
+
+
+
+
+
+ +
+
{{ stats.active_requests }}
+
Active Requests
+
+
+
+
+
+ +
+
{{ stats.total_stock }} Units
+
Bank Inventory
+
+
+
+
+
+ +
+
{{ stats.vaccinated_percentage }}%
+
Vaccinated Donors
+
+
+
+ +
+ +
+
+
+

Available Donors

+
+ + + +
+
+ + + +
+
+ +
+
+ +
+
+ +
+ + +
+ +
+ {% for donor in donors %} +
+
+
{{ donor.blood_group }}
+
+
+ {{ donor.name }} + {% if donor.is_verified %} + + {% endif %} + {% if donor.distance and donor.distance < 1000 %} + + {{ donor.distance|floatformat:1 }} km + + {% endif %} +
+

{{ donor.location }}, {{ donor.district }}

+
+
+
+
+ + {% if donor.is_available %}Available{% else %}Unavailable{% endif %} + +

Last Donated: {{ donor.last_donation_date|default:"Never" }}

+
+ +
+
+ {% empty %} +
+ +

No donors match your search criteria.

+
+ {% endfor %} +
+
+ + +
+
+
+

Vaccination & Eligibility

+

We prioritize donors who are fully vaccinated to ensure maximum safety for recipients.

+
+
+ Community Immunity Level + {{ stats.vaccinated_percentage }}% +
+
+
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+
+ Urgent Requests + HOT +
+
+ {% for req in blood_requests %} +
+
+ {{ req.urgency }} + {{ req.blood_group }} +
+
{{ req.patient_name }}
+

{{ req.hospital }}

+
+ {{ req.created_at|timesince }} ago + Help Now → +
+
+ {% empty %} +

No active requests found.

+ {% endfor %} +
+
+ + +
+
Blood Bank Inventory
+
+ {% for bank in blood_banks %} +
+
+ {{ bank.name }} + 24/7 Available +
+
+ A+ : {{ bank.stock_a_plus }} + B+ : {{ bank.stock_b_plus }} + O+ : {{ bank.stock_o_plus }} + AB+ : {{ bank.stock_ab_plus }} +
+
+ {% empty %} +

No blood banks registered.

+ {% endfor %} +
+ Manage Banks +
+ + +
+
Lifesaver Tip
+

Donating once can save up to three lives. Make sure to stay hydrated and rest before your appointment!

+
+
+
+
+{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/core/templates/core/login.html b/core/templates/core/login.html new file mode 100644 index 0000000..b95e6de --- /dev/null +++ b/core/templates/core/login.html @@ -0,0 +1,60 @@ +{% extends 'base.html' %} + +{% block title %}Login - RaktaPulse{% endblock %} + +{% block content %} +
+
+
+
+ +

Welcome to RaktaPulse

+

Please login to your account

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

Don't have an account? Register here

+
+
+
+
+ + +{% endblock %} \ No newline at end of file diff --git a/core/templates/core/vaccination_info.html b/core/templates/core/vaccination_info.html new file mode 100644 index 0000000..7b29b1f --- /dev/null +++ b/core/templates/core/vaccination_info.html @@ -0,0 +1,57 @@ +{% extends "base.html" %} +{% load static %} + +{% block title %}Vaccination Status - RaktaPulse{% endblock %} + +{% block content %} +
+
+
+

Vaccination Overview

+

Monitoring community immunity and donor eligibility.

+
+
+ +
+
+
+

Why Vaccination Matters?

+

Ensuring our donors are vaccinated is crucial for the safety of both the donors and the recipients. Fully vaccinated individuals contribute to a safer blood supply chain.

+ +
+
Community Progress
+
+ Fully Vaccinated Donors + {{ stats.percentage }}% +
+
+
{{ stats.percentage }}%
+
+

{{ stats.vaccinated_count }} out of {{ stats.total_donors }} registered donors are fully vaccinated.

+
+ +
Eligibility Criteria
+
    +
  • Must be fully vaccinated for priority donation.
  • +
  • At least 14 days must have passed since the last dose.
  • +
  • Must be in good health on the day of donation.
  • +
+
+
+ +
+
+
Update Your Status
+

Are you a donor? Keep your vaccination records up to date to maintain your verified status.

+ +
+ +
+
Contact Support
+

Have questions about vaccination and donation? Our medical team is here to help.

+ Email Support +
+
+
+
+{% endblock %} diff --git a/core/urls.py b/core/urls.py index 6299e3d..93fa2ad 100644 --- a/core/urls.py +++ b/core/urls.py @@ -1,7 +1,14 @@ from django.urls import path -from .views import home +from .views import home, login_view, logout_view, register_view, donor_list, blood_request_list, blood_bank_list, vaccination_info urlpatterns = [ path("", home, name="home"), + path("login/", login_view, name="login"), + path("logout/", logout_view, name="logout"), + path("register/", register_view, name="register"), + path("donors/", donor_list, name="donor_list"), + path("requests/", blood_request_list, name="blood_request_list"), + path("banks/", blood_bank_list, name="blood_bank_list"), + path("vaccination/", vaccination_info, name="vaccination_info"), ] diff --git a/core/views.py b/core/views.py index c9aed12..fe13eae 100644 --- a/core/views.py +++ b/core/views.py @@ -1,25 +1,172 @@ import os import platform - -from django import get_version as django_version -from django.shortcuts import render +from django.shortcuts import render, redirect +from django.contrib.auth import login, logout, authenticate +from django.contrib.auth.forms import UserCreationForm, AuthenticationForm +from django.contrib import messages from django.utils import timezone +from .models import Donor, BloodRequest, BloodBank +import math +def haversine(lat1, lon1, lat2, lon2): + # Radius of the Earth in km + R = 6371.0 + + dlat = math.radians(lat2 - lat1) + dlon = math.radians(lon2 - lon1) + + a = math.sin(dlat / 2)**2 + math.cos(math.radians(lat1)) * math.cos(math.radians(lat2)) * math.sin(dlon / 2)**2 + c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a)) + + return R * c + +def login_view(request): + if request.method == "POST": + form = AuthenticationForm(request, data=request.POST) + if form.is_valid(): + username = form.cleaned_data.get('username') + password = form.cleaned_data.get('password') + user = authenticate(username=username, password=password) + if user is not None: + login(request, user) + return redirect("home") + else: + form = AuthenticationForm() + return render(request, "core/login.html", {"form": form}) + +def logout_view(request): + logout(request) + return redirect("home") + +def register_view(request): + if request.method == "POST": + form = UserCreationForm(request.POST) + if form.is_valid(): + user = form.save() + login(request, user) + return redirect("home") + else: + form = UserCreationForm() + return render(request, "core/register.html", {"form": form}) def home(request): - """Render the landing screen with loader and environment details.""" - host_name = request.get_host().lower() - agent_brand = "AppWizzy" if host_name == "appwizzy.com" else "Flatlogic" - now = timezone.now() + """Render the RaktaPulse Dashboard experience.""" + query_blood = request.GET.get('blood_group', '') + query_location = request.GET.get('location', '') + user_lat = request.GET.get('lat') + user_lng = request.GET.get('lng') + + donors = Donor.objects.all() + if query_blood: + donors = donors.filter(blood_group=query_blood) + if query_location: + donors = donors.filter(location__icontains=query_location) + + donor_list_data = list(donors) + + if user_lat and user_lng: + try: + u_lat = float(user_lat) + u_lng = float(user_lng) + for d in donor_list_data: + if d.latitude and d.longitude: + d.distance = haversine(u_lat, u_lng, float(d.latitude), float(d.longitude)) + else: + d.distance = 999999 # Very far + donor_list_data.sort(key=lambda x: x.distance) + except ValueError: + donor_list_data.sort(key=lambda x: (-x.is_available, x.name)) + else: + donor_list_data.sort(key=lambda x: (-x.is_available, x.name)) + + blood_requests = BloodRequest.objects.filter(status='Active').order_by('-urgency', '-created_at') + blood_banks = BloodBank.objects.all() + + # Stats for Dashboard + stats = { + "total_donors": Donor.objects.count(), + "active_requests": BloodRequest.objects.filter(status='Active').count(), + "total_stock": sum([ + bb.stock_a_plus + bb.stock_a_minus + bb.stock_b_plus + bb.stock_b_minus + + bb.stock_o_plus + bb.stock_o_minus + bb.stock_ab_plus + bb.stock_ab_minus + for bb in blood_banks + ]), + "vaccinated_percentage": 0 + } + + total_d = stats["total_donors"] + if total_d > 0: + vaccinated_count = Donor.objects.filter(vaccination_status__icontains='Fully').count() + stats["vaccinated_percentage"] = int((vaccinated_count / total_d) * 100) context = { - "project_name": "New Style", - "agent_brand": agent_brand, - "django_version": django_version(), - "python_version": platform.python_version(), - "current_time": now, - "host_name": host_name, - "project_description": os.getenv("PROJECT_DESCRIPTION", ""), - "project_image_url": os.getenv("PROJECT_IMAGE_URL", ""), + "donors": donor_list_data[:8], + "blood_requests": blood_requests[:6], + "blood_banks": blood_banks, + "blood_groups": [g[0] for g in Donor.BLOOD_GROUPS], + "stats": stats, + "project_name": "RaktaPulse", + "current_time": timezone.now(), } return render(request, "core/index.html", context) + +def donor_list(request): + blood_group = request.GET.get('blood_group', '') + district = request.GET.get('district', '') + user_lat = request.GET.get('lat') + user_lng = request.GET.get('lng') + + donors = Donor.objects.all() + if blood_group: + donors = donors.filter(blood_group=blood_group) + if district: + donors = donors.filter(district__icontains=district) + + donor_list_data = list(donors) + + if user_lat and user_lng: + try: + u_lat = float(user_lat) + u_lng = float(user_lng) + for d in donor_list_data: + if d.latitude and d.longitude: + d.distance = haversine(u_lat, u_lng, float(d.latitude), float(d.longitude)) + else: + d.distance = 999999 + donor_list_data.sort(key=lambda x: x.distance) + except ValueError: + donor_list_data.sort(key=lambda x: (-x.is_verified, x.name)) + else: + donor_list_data.sort(key=lambda x: (-x.is_verified, x.name)) + + context = { + 'donors': donor_list_data, + 'blood_groups': [g[0] for g in Donor.BLOOD_GROUPS], + } + return render(request, 'core/donor_list.html', context) + +def blood_request_list(request): + requests = BloodRequest.objects.all().order_by('-created_at') + context = { + 'requests': requests, + } + return render(request, 'core/blood_request_list.html', context) + +def blood_bank_list(request): + banks = BloodBank.objects.all() + context = { + 'banks': banks, + } + return render(request, 'core/blood_bank_list.html', context) + +def vaccination_info(request): + stats = { + "total_donors": Donor.objects.count(), + "vaccinated_count": Donor.objects.filter(vaccination_status__icontains='Fully').count(), + } + if stats["total_donors"] > 0: + stats["percentage"] = int((stats["vaccinated_count"] / stats["total_donors"]) * 100) + else: + stats["percentage"] = 0 + + return render(request, 'core/vaccination_info.html', {'stats': stats}) diff --git a/populate_data.py b/populate_data.py new file mode 100644 index 0000000..2a18687 --- /dev/null +++ b/populate_data.py @@ -0,0 +1,96 @@ +import os +import django +import datetime +import random + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings') +django.setup() + +from core.models import Donor, BloodRequest, BloodBank +from django.utils import timezone + +def run(): + # Clear existing data + Donor.objects.all().delete() + BloodRequest.objects.all().delete() + BloodBank.objects.all().delete() + + # Create Donors (Nepali Context) + donors_data = [ + ('Arjun Thapa', 'O+', 'Kathmandu', 'New Baneshwor', '9841000000', 'Fully Vaccinated', True), + ('Sita Shrestha', 'A-', 'Lalitpur', 'Patan Durbar Square', '9841111111', 'Fully Vaccinated', True), + ('Rajesh Hamal', 'B+', 'Bhaktapur', 'Suryabinayak', '9841222222', 'Partially Vaccinated', True), + ('Bipana Thapa', 'AB+', 'Kaski', 'Lakeside, Pokhara', '9841333333', 'Fully Vaccinated', False), + ('Nischal Basnet', 'O-', 'Rupandehi', 'Butwal', '9841444444', 'Not Vaccinated', False), + ('Swastima Khadka', 'A+', 'Chitwan', 'Bharatpur', '9841555555', 'Fully Vaccinated', True), + ] + for name, bg, dist, loc, ph, vac, ver in donors_data: + Donor.objects.create( + name=name, + blood_group=bg, + district=dist, + location=loc, + phone=ph, + is_available=True, + is_verified=ver, + citizenship_no=f"123-{random.randint(1000, 9999)}" if ver else None, + vaccination_status=vac, + last_vaccination_date=timezone.now().date() - datetime.timedelta(days=random.randint(30, 180)) + ) + + # Create Blood Requests (Nepali Context) + BloodRequest.objects.create( + patient_name='Ram Bahadur', + blood_group='O+', + location='Teaching Hospital, Maharajgunj', + urgency='CRITICAL', + hospital='Teaching Hospital', + contact_number='9800000001' + ) + BloodRequest.objects.create( + patient_name='Maya Devi', + blood_group='B+', + location='Bir Hospital, Kathmandu', + urgency='URGENT', + hospital='Bir Hospital', + contact_number='9800000002' + ) + BloodRequest.objects.create( + patient_name='Hari Prasad', + blood_group='AB-', + location='Patan Hospital', + urgency='NORMAL', + hospital='Patan Hospital', + contact_number='9800000003' + ) + + # Create Blood Bank (Nepali Context) + BloodBank.objects.create( + name='Nepal Red Cross Society', + location='Soalteemode, Kathmandu', + contact_number='01-4270650', + is_24_7=True, + stock_o_plus=150, + stock_o_minus=45, + stock_a_plus=120, + stock_a_minus=30, + stock_b_plus=90, + stock_b_minus=20, + stock_ab_plus=40, + stock_ab_minus=15 + ) + + BloodBank.objects.create( + name='Bhaktapur Blood Bank', + location='Dudhpati, Bhaktapur', + contact_number='01-6612266', + is_24_7=True, + stock_o_plus=60, + stock_a_plus=45, + stock_b_plus=30 + ) + + print("Sample data populated successfully.") + +if __name__ == "__main__": + run()