diff --git a/config/__pycache__/settings.cpython-311.pyc b/config/__pycache__/settings.cpython-311.pyc index 9aced4f..50ad71d 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 01d0673..8cde51e 100644 Binary files a/config/__pycache__/urls.cpython-311.pyc and b/config/__pycache__/urls.cpython-311.pyc differ diff --git a/config/settings.py b/config/settings.py index 0b62db9..103f1eb 100644 --- a/config/settings.py +++ b/config/settings.py @@ -61,6 +61,7 @@ INSTALLED_APPS = [ MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.locale.LocaleMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', @@ -141,6 +142,15 @@ USE_I18N = True USE_TZ = True +LANGUAGES = [ + ('en', 'English'), + ('ne', 'Nepali'), +] + +LOCALE_PATHS = [ + BASE_DIR / 'locale', +] + # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/5.2/howto/static-files/ diff --git a/config/urls.py b/config/urls.py index bcfc074..baccfac 100644 --- a/config/urls.py +++ b/config/urls.py @@ -21,6 +21,7 @@ from django.conf.urls.static import static urlpatterns = [ path("admin/", admin.site.urls), + path("i18n/", include("django.conf.urls.i18n")), path("", include("core.urls")), ] diff --git a/core/__pycache__/models.cpython-311.pyc b/core/__pycache__/models.cpython-311.pyc index 61b392a..ffaadc6 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 cc49284..77f725c 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 a39fa71..c9d8df3 100644 Binary files a/core/__pycache__/views.cpython-311.pyc and b/core/__pycache__/views.cpython-311.pyc differ diff --git a/core/migrations/0009_bloodrequest_user_donor_user_donationevent_feedback_and_more.py b/core/migrations/0009_bloodrequest_user_donor_user_donationevent_feedback_and_more.py new file mode 100644 index 0000000..f9e4101 --- /dev/null +++ b/core/migrations/0009_bloodrequest_user_donor_user_donationevent_feedback_and_more.py @@ -0,0 +1,58 @@ +# Generated by Django 5.2.7 on 2026-02-18 05:21 + +import django.db.models.deletion +import django.utils.timezone +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0008_userprofile'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.AddField( + model_name='bloodrequest', + name='user', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='blood_requests', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='donor', + name='user', + field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='donor_profile', to=settings.AUTH_USER_MODEL), + ), + migrations.CreateModel( + name='DonationEvent', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('date', models.DateTimeField(default=django.utils.timezone.now)), + ('is_completed', models.BooleanField(default=False)), + ('donor', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='donations', to='core.donor')), + ('donor_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='my_donations', to=settings.AUTH_USER_MODEL)), + ('request', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='donations', to='core.bloodrequest')), + ], + ), + migrations.CreateModel( + name='Feedback', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('content', models.TextField()), + ('rating', models.PositiveIntegerField(default=5)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='feedbacks', to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='Notification', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('message', models.TextField()), + ('is_read', models.BooleanField(default=False)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='notifications', to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/core/migrations/__pycache__/0009_bloodrequest_user_donor_user_donationevent_feedback_and_more.cpython-311.pyc b/core/migrations/__pycache__/0009_bloodrequest_user_donor_user_donationevent_feedback_and_more.cpython-311.pyc new file mode 100644 index 0000000..0431d83 Binary files /dev/null and b/core/migrations/__pycache__/0009_bloodrequest_user_donor_user_donationevent_feedback_and_more.cpython-311.pyc differ diff --git a/core/models.py b/core/models.py index 367259c..00c3cec 100644 --- a/core/models.py +++ b/core/models.py @@ -46,6 +46,7 @@ class VaccineRecord(models.Model): return f"{self.vaccine_name} - Dose {self.dose_number} for {self.user.username}" class Donor(models.Model): + user = models.OneToOneField(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='donor_profile') name = models.CharField(max_length=100) blood_group = models.CharField(max_length=5, choices=BLOOD_GROUPS) district = models.CharField(max_length=100, default='Kathmandu') @@ -71,6 +72,7 @@ class BloodRequest(models.Model): ('URGENT', 'Urgent'), ('NORMAL', 'Normal'), ] + user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='blood_requests', null=True, blank=True) patient_name = models.CharField(max_length=100) blood_group = models.CharField(max_length=5, choices=BLOOD_GROUPS) location = models.CharField(max_length=255) @@ -105,3 +107,31 @@ class BloodBank(models.Model): def __str__(self): return self.name + +class DonationEvent(models.Model): + donor = models.ForeignKey(Donor, on_delete=models.CASCADE, related_name='donations') + request = models.ForeignKey(BloodRequest, on_delete=models.CASCADE, related_name='donations') + donor_user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='my_donations') + date = models.DateTimeField(default=timezone.now) + is_completed = models.BooleanField(default=False) + + def __str__(self): + return f"Donation by {self.donor.name} for {self.request.patient_name}" + +class Notification(models.Model): + user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='notifications') + message = models.TextField() + is_read = models.BooleanField(default=False) + created_at = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return f"Notification for {self.user.username}: {self.message[:20]}..." + +class Feedback(models.Model): + user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='feedbacks') + content = models.TextField() + rating = models.PositiveIntegerField(default=5) + created_at = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return f"Feedback from {self.user.username} - {self.rating} stars" diff --git a/core/templates/base.html b/core/templates/base.html index 660a66f..6f5d13f 100644 --- a/core/templates/base.html +++ b/core/templates/base.html @@ -1,5 +1,6 @@ +{% load i18n %} - + @@ -178,6 +179,78 @@ #sidebar.active { margin-left: 0; } } + /* SOS Floating Button */ + .sos-btn { + position: fixed; + bottom: 30px; + right: 30px; + width: 65px; + height: 65px; + background-color: var(--pulse-red); + color: white; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + text-decoration: none; + box-shadow: 0 4px 15px rgba(230, 57, 70, 0.4); + z-index: 9999; + transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); + font-weight: 800; + font-size: 1.1rem; + border: 3px solid white; + } + + .sos-btn:hover { + transform: scale(1.1); + color: white; + box-shadow: 0 6px 20px rgba(230, 57, 70, 0.6); + } + + .sos-btn .pulse-ring { + position: absolute; + width: 100%; + height: 100%; + border-radius: 50%; + background-color: var(--pulse-red); + opacity: 0.6; + animation: sos-pulse 2s infinite; + z-index: -1; + } + + .sos-content { + display: flex; + flex-direction: column; + align-items: center; + line-height: 1; + } + + .sos-text { + font-size: 1.1rem; + font-weight: 800; + } + + .sos-number { + font-size: 0.7rem; + font-weight: 600; + margin-top: 2px; + } + + @keyframes sos-pulse { + 0% { transform: scale(1); opacity: 0.6; } + 100% { transform: scale(1.8); opacity: 0; } + } + + @media (max-width: 576px) { + .sos-btn { + bottom: 20px; + right: 20px; + width: 55px; + height: 55px; + font-size: 0.9rem; + } + } + {% block head %}{% endblock %} @@ -195,25 +268,19 @@ - -
-
-

Need Help?

- Emergency: 1115 -
-
@@ -231,6 +298,31 @@
+ + +
Detect Location @@ -241,6 +333,13 @@
{% if user.is_authenticated %}
+ + + + + {{ user.notifications.count }} + +
@@ -335,6 +434,39 @@ } checkLocationCookie(); + +
+
+ SOS + 1115 +
+
+ + + {% block scripts %}{% endblock %} diff --git a/core/templates/core/blood_request_list.html b/core/templates/core/blood_request_list.html index 71f97e8..1442784 100644 --- a/core/templates/core/blood_request_list.html +++ b/core/templates/core/blood_request_list.html @@ -21,8 +21,8 @@
-

Blood Requests

-

Current active requirements for blood in various hospitals.

+

{% if current_status %}{{ current_status }} {% endif %}Blood Requests

+

{% if current_status == 'Active' %}Current urgent requirements for blood.{% else %}History of blood requests in our community.{% endif %}

Post a Request
@@ -34,7 +34,14 @@
- {{ req.urgency }} +
+ {{ req.urgency }} + {% if req.status == 'Active' %} + Active + {% else %} + {{ req.status }} + {% endif %} +
{{ req.blood_group }}
@@ -44,7 +51,10 @@
{{ req.created_at|timesince }} ago - Help Now +
+ Volunteer + Call +
diff --git a/core/templates/core/donor_list.html b/core/templates/core/donor_list.html index b391186..1818a0c 100644 --- a/core/templates/core/donor_list.html +++ b/core/templates/core/donor_list.html @@ -71,8 +71,9 @@

Phone: {{ donor.phone }}

Contact Now -
- {% endfor %} +
+
+ {% endfor %}
diff --git a/core/templates/core/feedback.html b/core/templates/core/feedback.html new file mode 100644 index 0000000..6451f56 --- /dev/null +++ b/core/templates/core/feedback.html @@ -0,0 +1,34 @@ +{% extends 'core/base.html' %} +{% load i18n %} + +{% block content %} +
+
+
+
+

{% trans "Share Your Feedback" %}

+

{% trans "We value your experience. Please let us know how we can improve." %}

+ +
+ {% csrf_token %} +
+ + +
+
+ + +
+ +
+
+
+
+
+{% endblock %} diff --git a/core/templates/core/index.html b/core/templates/core/index.html index e0da796..34766e4 100644 --- a/core/templates/core/index.html +++ b/core/templates/core/index.html @@ -1,7 +1,8 @@ {% extends "base.html" %} {% load static %} +{% load i18n %} -{% block title %}RaktaPulse Dashboard - Lifeline of the Community{% endblock %} +{% block title %}{% trans "RaktaPulse Dashboard" %} - {% trans "Lifeline of the Community" %}{% endblock %} {% block head %}