Autosave: 20260217-162235
This commit is contained in:
parent
d86257fa5a
commit
0f9878cadc
BIN
core/__pycache__/forms.cpython-311.pyc
Normal file
BIN
core/__pycache__/forms.cpython-311.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
27
core/forms.py
Normal file
27
core/forms.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
from django import forms
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from .models import UserProfile, BLOOD_GROUPS
|
||||||
|
|
||||||
|
class UserUpdateForm(forms.ModelForm):
|
||||||
|
email = forms.EmailField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = User
|
||||||
|
fields = ['username', 'email', 'first_name', 'last_name']
|
||||||
|
widgets = {
|
||||||
|
'username': forms.TextInput(attrs={'class': 'form-control'}),
|
||||||
|
'email': forms.EmailInput(attrs={'class': 'form-control'}),
|
||||||
|
'first_name': forms.TextInput(attrs={'class': 'form-control'}),
|
||||||
|
'last_name': forms.TextInput(attrs={'class': 'form-control'}),
|
||||||
|
}
|
||||||
|
|
||||||
|
class ProfileUpdateForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = UserProfile
|
||||||
|
fields = ['bio', 'location', 'phone', 'blood_group']
|
||||||
|
widgets = {
|
||||||
|
'bio': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
|
||||||
|
'location': forms.TextInput(attrs={'class': 'form-control'}),
|
||||||
|
'phone': forms.TextInput(attrs={'class': 'form-control'}),
|
||||||
|
'blood_group': forms.Select(attrs={'class': 'form-control'}, choices=BLOOD_GROUPS),
|
||||||
|
}
|
||||||
18
core/migrations/0007_bloodbank_total_capacity.py
Normal file
18
core/migrations/0007_bloodbank_total_capacity.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.2.7 on 2026-02-17 16:06
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('core', '0006_bloodrequest_latitude_bloodrequest_longitude'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='bloodbank',
|
||||||
|
name='total_capacity',
|
||||||
|
field=models.IntegerField(default=1000),
|
||||||
|
),
|
||||||
|
]
|
||||||
28
core/migrations/0008_userprofile.py
Normal file
28
core/migrations/0008_userprofile.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# Generated by Django 5.2.7 on 2026-02-17 16:13
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('core', '0007_bloodbank_total_capacity'),
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='UserProfile',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('bio', models.TextField(blank=True, max_length=500)),
|
||||||
|
('location', models.CharField(blank=True, max_length=100)),
|
||||||
|
('birth_date', models.DateField(blank=True, null=True)),
|
||||||
|
('phone', models.CharField(blank=True, max_length=20)),
|
||||||
|
('blood_group', models.CharField(blank=True, choices=[('A+', 'A+'), ('A-', 'A-'), ('B+', 'B+'), ('B-', 'B-'), ('O+', 'O+'), ('O-', 'O-'), ('AB+', 'AB+'), ('AB-', 'AB-')], max_length=5)),
|
||||||
|
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='profile', to=settings.AUTH_USER_MODEL)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
Binary file not shown.
BIN
core/migrations/__pycache__/0008_userprofile.cpython-311.pyc
Normal file
BIN
core/migrations/__pycache__/0008_userprofile.cpython-311.pyc
Normal file
Binary file not shown.
@ -1,6 +1,36 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
from django.db.models.signals import post_save
|
||||||
|
from django.dispatch import receiver
|
||||||
|
|
||||||
|
BLOOD_GROUPS = [
|
||||||
|
('A+', 'A+'), ('A-', 'A-'),
|
||||||
|
('B+', 'B+'), ('B-', 'B-'),
|
||||||
|
('O+', 'O+'), ('O-', 'O-'),
|
||||||
|
('AB+', 'AB+'), ('AB-', 'AB-'),
|
||||||
|
]
|
||||||
|
|
||||||
|
class UserProfile(models.Model):
|
||||||
|
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
|
||||||
|
bio = models.TextField(max_length=500, blank=True)
|
||||||
|
location = models.CharField(max_length=100, blank=True)
|
||||||
|
birth_date = models.DateField(null=True, blank=True)
|
||||||
|
phone = models.CharField(max_length=20, blank=True)
|
||||||
|
blood_group = models.CharField(max_length=5, choices=BLOOD_GROUPS, blank=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.user.username
|
||||||
|
|
||||||
|
@receiver(post_save, sender=User)
|
||||||
|
def create_or_save_user_profile(sender, instance, created, **kwargs):
|
||||||
|
if created:
|
||||||
|
UserProfile.objects.get_or_create(user=instance)
|
||||||
|
else:
|
||||||
|
# For existing users, ensure profile exists
|
||||||
|
if not hasattr(instance, 'profile'):
|
||||||
|
UserProfile.objects.create(user=instance)
|
||||||
|
instance.profile.save()
|
||||||
|
|
||||||
class VaccineRecord(models.Model):
|
class VaccineRecord(models.Model):
|
||||||
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='vaccine_records')
|
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='vaccine_records')
|
||||||
@ -16,12 +46,6 @@ class VaccineRecord(models.Model):
|
|||||||
return f"{self.vaccine_name} - Dose {self.dose_number} for {self.user.username}"
|
return f"{self.vaccine_name} - Dose {self.dose_number} for {self.user.username}"
|
||||||
|
|
||||||
class Donor(models.Model):
|
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)
|
name = models.CharField(max_length=100)
|
||||||
blood_group = models.CharField(max_length=5, choices=BLOOD_GROUPS)
|
blood_group = models.CharField(max_length=5, choices=BLOOD_GROUPS)
|
||||||
district = models.CharField(max_length=100, default='Kathmandu')
|
district = models.CharField(max_length=100, default='Kathmandu')
|
||||||
@ -48,7 +72,7 @@ class BloodRequest(models.Model):
|
|||||||
('NORMAL', 'Normal'),
|
('NORMAL', 'Normal'),
|
||||||
]
|
]
|
||||||
patient_name = models.CharField(max_length=100)
|
patient_name = models.CharField(max_length=100)
|
||||||
blood_group = models.CharField(max_length=5, choices=Donor.BLOOD_GROUPS)
|
blood_group = models.CharField(max_length=5, choices=BLOOD_GROUPS)
|
||||||
location = models.CharField(max_length=255)
|
location = models.CharField(max_length=255)
|
||||||
urgency = models.CharField(max_length=10, choices=URGENCY_LEVELS, default='NORMAL')
|
urgency = models.CharField(max_length=10, choices=URGENCY_LEVELS, default='NORMAL')
|
||||||
hospital = models.CharField(max_length=255)
|
hospital = models.CharField(max_length=255)
|
||||||
@ -77,6 +101,7 @@ class BloodBank(models.Model):
|
|||||||
stock_o_minus = models.IntegerField(default=0)
|
stock_o_minus = models.IntegerField(default=0)
|
||||||
stock_ab_plus = models.IntegerField(default=0)
|
stock_ab_plus = models.IntegerField(default=0)
|
||||||
stock_ab_minus = models.IntegerField(default=0)
|
stock_ab_minus = models.IntegerField(default=0)
|
||||||
|
total_capacity = models.IntegerField(default=1000)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|||||||
@ -202,6 +202,7 @@
|
|||||||
<li class="{% if request.resolver_match.url_name == 'live_map' %}active{% endif %}"><a href="{% url 'live_map' %}"><i class="bi bi-map text-danger"></i> Live Alerts</a></li>
|
<li class="{% if request.resolver_match.url_name == 'live_map' %}active{% endif %}"><a href="{% url 'live_map' %}"><i class="bi bi-map text-danger"></i> Live Alerts</a></li>
|
||||||
<li class="{% if request.resolver_match.url_name == 'vaccination_info' %}active{% endif %}"><a href="{% url 'vaccination_info' %}"><i class="bi bi-shield-check"></i> Vaccination</a></li>
|
<li class="{% if request.resolver_match.url_name == 'vaccination_info' %}active{% endif %}"><a href="{% url 'vaccination_info' %}"><i class="bi bi-shield-check"></i> Vaccination</a></li>
|
||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
|
<li class="{% if request.resolver_match.url_name == 'profile' %}active{% endif %}"><a href="{% url 'profile' %}"><i class="bi bi-person-bounding-box"></i> My Profile</a></li>
|
||||||
<li class="{% if 'vaccination_dashboard' in request.resolver_match.url_name or 'add_vaccination' in request.resolver_match.url_name %}active{% endif %}"><a href="{% url 'vaccination_dashboard' %}"><i class="bi bi-journal-check"></i> My Records</a></li>
|
<li class="{% if 'vaccination_dashboard' in request.resolver_match.url_name or 'add_vaccination' in request.resolver_match.url_name %}active{% endif %}"><a href="{% url 'vaccination_dashboard' %}"><i class="bi bi-journal-check"></i> My Records</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li><a href="/admin/"><i class="bi bi-gear-fill"></i> Settings</a></li>
|
<li><a href="/admin/"><i class="bi bi-gear-fill"></i> Settings</a></li>
|
||||||
@ -218,35 +219,40 @@
|
|||||||
<!-- Page Content -->
|
<!-- Page Content -->
|
||||||
<div id="content">
|
<div id="content">
|
||||||
<!-- Top Bar -->
|
<!-- Top Bar -->
|
||||||
<div class="top-bar justify-content-between">
|
<div class="top-bar justify-content-between flex-wrap">
|
||||||
<div class="d-flex align-items-center">
|
<div class="d-flex align-items-center">
|
||||||
<button type="button" id="sidebarCollapse" class="btn btn-link text-danger me-3 p-0">
|
<button type="button" id="sidebarCollapse" class="btn btn-link text-danger me-3 p-0">
|
||||||
<i class="bi bi-list fs-3"></i>
|
<i class="bi bi-list fs-3"></i>
|
||||||
</button>
|
</button>
|
||||||
<div class="search-box d-none d-sm-flex">
|
<div class="search-box d-none d-lg-flex">
|
||||||
<i class="bi bi-search text-secondary"></i>
|
<i class="bi bi-search text-secondary"></i>
|
||||||
<input type="text" placeholder="Search anything...">
|
<input type="text" placeholder="Search anything...">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="d-flex align-items-center gap-4">
|
<div class="d-flex align-items-center gap-2 gap-md-4">
|
||||||
<div id="location-status" class="d-none d-md-flex align-items-center text-secondary small cursor-pointer" style="cursor: pointer;" onclick="detectLocation()">
|
<div id="location-status" class="d-none d-xl-flex align-items-center text-secondary small cursor-pointer" style="cursor: pointer;" onclick="detectLocation()">
|
||||||
<i class="bi bi-geo-alt me-2"></i>
|
<i class="bi bi-geo-alt me-1"></i>
|
||||||
<span id="location-text">Detect Location</span>
|
<span id="location-text">Detect Location</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-none d-md-flex align-items-center text-secondary small">
|
<div class="d-none d-md-flex align-items-center text-secondary small">
|
||||||
<i class="bi bi-calendar3 me-2"></i>
|
<i class="bi bi-calendar3 me-1"></i>
|
||||||
{{ current_time|date:"D, M d, Y" }}
|
{{ current_time|date:"M d" }}
|
||||||
</div>
|
</div>
|
||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
<div class="d-flex align-items-center gap-2">
|
<div class="d-flex align-items-center gap-2">
|
||||||
<span class="d-none d-sm-inline fw-bold text-dark">{{ user.username }}</span>
|
<a href="{% url 'profile' %}" class="text-decoration-none d-flex align-items-center gap-2">
|
||||||
<a href="/logout" class="btn btn-outline-danger btn-sm">Logout</a>
|
<div class="bg-danger bg-opacity-10 rounded-circle p-1 d-flex align-items-center justify-content-center" style="width: 32px; height: 32px;">
|
||||||
|
<i class="bi bi-person-fill text-danger"></i>
|
||||||
|
</div>
|
||||||
|
<span class="d-none d-sm-inline fw-bold text-dark">{{ user.username }}</span>
|
||||||
|
</a>
|
||||||
|
<a href="{% url 'logout' %}" class="btn btn-outline-danger btn-sm">Logout</a>
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="d-flex align-items-center gap-2">
|
<div class="d-flex align-items-center gap-2">
|
||||||
<a href="/login" class="btn btn-danger btn-sm px-3">Login</a>
|
<a href="{% url 'login' %}" class="btn btn-danger btn-sm px-2 px-sm-3">Login</a>
|
||||||
<a href="/register" class="btn btn-outline-danger btn-sm px-3">Register</a>
|
<a href="{% url 'register' %}" class="btn btn-outline-danger btn-sm px-2 px-sm-3">Register</a>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -48,54 +48,78 @@
|
|||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h6 class="fw-bold text-dark mb-3">Inventory Levels (Units)</h6>
|
<h6 class="fw-bold text-dark mb-3">Inventory Levels (Max {{ bank.total_capacity }} units/type)</h6>
|
||||||
<div class="row g-2 mb-4">
|
<div class="row g-2 mb-4">
|
||||||
<div class="col-3">
|
<div class="col-3">
|
||||||
<div class="p-2 border rounded text-center bg-light">
|
<div class="p-2 border rounded text-center bg-light">
|
||||||
<div class="extra-small text-muted">A+</div>
|
<div class="extra-small text-muted">A+</div>
|
||||||
<div class="fw-bold">{{ bank.stock_a_plus }}</div>
|
<div class="fw-bold">{{ bank.stock_a_plus }}</div>
|
||||||
|
<div class="progress mt-1" style="height: 4px;">
|
||||||
|
<div class="progress-bar bg-danger" style="width: {% widthratio bank.stock_a_plus bank.total_capacity 100 %}%"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-3">
|
<div class="col-3">
|
||||||
<div class="p-2 border rounded text-center bg-light">
|
<div class="p-2 border rounded text-center bg-light">
|
||||||
<div class="extra-small text-muted">A-</div>
|
<div class="extra-small text-muted">A-</div>
|
||||||
<div class="fw-bold">{{ bank.stock_a_minus }}</div>
|
<div class="fw-bold">{{ bank.stock_a_minus }}</div>
|
||||||
|
<div class="progress mt-1" style="height: 4px;">
|
||||||
|
<div class="progress-bar bg-danger" style="width: {% widthratio bank.stock_a_minus bank.total_capacity 100 %}%"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-3">
|
<div class="col-3">
|
||||||
<div class="p-2 border rounded text-center bg-light">
|
<div class="p-2 border rounded text-center bg-light">
|
||||||
<div class="extra-small text-muted">B+</div>
|
<div class="extra-small text-muted">B+</div>
|
||||||
<div class="fw-bold">{{ bank.stock_b_plus }}</div>
|
<div class="fw-bold">{{ bank.stock_b_plus }}</div>
|
||||||
|
<div class="progress mt-1" style="height: 4px;">
|
||||||
|
<div class="progress-bar bg-danger" style="width: {% widthratio bank.stock_b_plus bank.total_capacity 100 %}%"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-3">
|
<div class="col-3">
|
||||||
<div class="p-2 border rounded text-center bg-light">
|
<div class="p-2 border rounded text-center bg-light">
|
||||||
<div class="extra-small text-muted">B-</div>
|
<div class="extra-small text-muted">B-</div>
|
||||||
<div class="fw-bold">{{ bank.stock_b_minus }}</div>
|
<div class="fw-bold">{{ bank.stock_b_minus }}</div>
|
||||||
|
<div class="progress mt-1" style="height: 4px;">
|
||||||
|
<div class="progress-bar bg-danger" style="width: {% widthratio bank.stock_b_minus bank.total_capacity 100 %}%"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-3">
|
<div class="col-3">
|
||||||
<div class="p-2 border rounded text-center bg-light">
|
<div class="p-2 border rounded text-center bg-light">
|
||||||
<div class="extra-small text-muted">O+</div>
|
<div class="extra-small text-muted">O+</div>
|
||||||
<div class="fw-bold">{{ bank.stock_o_plus }}</div>
|
<div class="fw-bold">{{ bank.stock_o_plus }}</div>
|
||||||
|
<div class="progress mt-1" style="height: 4px;">
|
||||||
|
<div class="progress-bar bg-danger" style="width: {% widthratio bank.stock_o_plus bank.total_capacity 100 %}%"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-3">
|
<div class="col-3">
|
||||||
<div class="p-2 border rounded text-center bg-light">
|
<div class="p-2 border rounded text-center bg-light">
|
||||||
<div class="extra-small text-muted">O-</div>
|
<div class="extra-small text-muted">O-</div>
|
||||||
<div class="fw-bold">{{ bank.stock_o_minus }}</div>
|
<div class="fw-bold">{{ bank.stock_o_minus }}</div>
|
||||||
|
<div class="progress mt-1" style="height: 4px;">
|
||||||
|
<div class="progress-bar bg-danger" style="width: {% widthratio bank.stock_o_minus bank.total_capacity 100 %}%"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-3">
|
<div class="col-3">
|
||||||
<div class="p-2 border rounded text-center bg-light">
|
<div class="p-2 border rounded text-center bg-light">
|
||||||
<div class="extra-small text-muted">AB+</div>
|
<div class="extra-small text-muted">AB+</div>
|
||||||
<div class="fw-bold">{{ bank.stock_ab_plus }}</div>
|
<div class="fw-bold">{{ bank.stock_ab_plus }}</div>
|
||||||
|
<div class="progress mt-1" style="height: 4px;">
|
||||||
|
<div class="progress-bar bg-danger" style="width: {% widthratio bank.stock_ab_plus bank.total_capacity 100 %}%"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-3">
|
<div class="col-3">
|
||||||
<div class="p-2 border rounded text-center bg-light">
|
<div class="p-2 border rounded text-center bg-light">
|
||||||
<div class="extra-small text-muted">AB-</div>
|
<div class="extra-small text-muted">AB-</div>
|
||||||
<div class="fw-bold">{{ bank.stock_ab_minus }}</div>
|
<div class="fw-bold">{{ bank.stock_ab_minus }}</div>
|
||||||
|
<div class="progress mt-1" style="height: 4px;">
|
||||||
|
<div class="progress-bar bg-danger" style="width: {% widthratio bank.stock_ab_minus bank.total_capacity 100 %}%"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -133,8 +133,8 @@
|
|||||||
<div class="icon-box bg-primary bg-opacity-10 text-primary">
|
<div class="icon-box bg-primary bg-opacity-10 text-primary">
|
||||||
<i class="bi bi-droplet"></i>
|
<i class="bi bi-droplet"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-value">{{ stats.total_stock }} <small class="fs-6 fw-normal">Units</small></div>
|
<div class="stat-value">{{ stats.total_stock }} <small class="fs-6 fw-normal">/ {{ stats.total_capacity }}</small></div>
|
||||||
<div class="stat-label">Bank Inventory</div>
|
<div class="stat-label">Inventory vs Capacity</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xl-3 col-md-6">
|
<div class="col-xl-3 col-md-6">
|
||||||
|
|||||||
74
core/templates/core/profile.html
Normal file
74
core/templates/core/profile.html
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
{% block title %}User Profile - RaktaPulse{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container py-4">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<div class="glass-card">
|
||||||
|
<div class="d-flex align-items-center mb-4">
|
||||||
|
<div class="bg-danger rounded-circle d-flex align-items-center justify-content-center me-3" style="width: 60px; height: 60px;">
|
||||||
|
<i class="bi bi-person-fill text-white fs-2"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h2 class="mb-0 fw-bold">{{ user.username }}</h2>
|
||||||
|
<p class="text-secondary mb-0">Member since {{ user.date_joined|date:"M d, Y" }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form method="POST">
|
||||||
|
{% csrf_token %}
|
||||||
|
<h5 class="fw-bold mb-3 border-bottom pb-2">Account Information</h5>
|
||||||
|
<div class="row g-3 mb-4">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label class="form-label small fw-bold">Username</label>
|
||||||
|
{{ u_form.username }}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label class="form-label small fw-bold">Email Address</label>
|
||||||
|
{{ u_form.email }}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label class="form-label small fw-bold">First Name</label>
|
||||||
|
{{ u_form.first_name }}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label class="form-label small fw-bold">Last Name</label>
|
||||||
|
{{ u_form.last_name }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h5 class="fw-bold mb-3 border-bottom pb-2">Profile Details</h5>
|
||||||
|
<div class="row g-3 mb-4">
|
||||||
|
<div class="col-12">
|
||||||
|
<label class="form-label small fw-bold">Bio</label>
|
||||||
|
{{ p_form.bio }}
|
||||||
|
<div class="form-text">Write a short bio about yourself.</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label small fw-bold">Blood Group</label>
|
||||||
|
{{ p_form.blood_group }}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label small fw-bold">Phone</label>
|
||||||
|
{{ p_form.phone }}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label small fw-bold">Location</label>
|
||||||
|
{{ p_form.location }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-grid">
|
||||||
|
<button type="submit" class="btn btn-danger py-2 fw-bold">
|
||||||
|
<i class="bi bi-check-circle me-2"></i>Update Profile
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@ -1,12 +1,13 @@
|
|||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
from .views import home, login_view, logout_view, register_view, donor_list, blood_request_list, blood_bank_list, vaccination_info, vaccination_dashboard, add_vaccination, live_map
|
from .views import home, login_view, logout_view, register_view, donor_list, blood_request_list, blood_bank_list, vaccination_info, vaccination_dashboard, add_vaccination, live_map, request_blood, profile
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("", home, name="home"),
|
path("", home, name="home"),
|
||||||
path("login/", login_view, name="login"),
|
path("login/", login_view, name="login"),
|
||||||
path("logout/", logout_view, name="logout"),
|
path("logout/", logout_view, name="logout"),
|
||||||
path("register/", register_view, name="register"),
|
path("register/", register_view, name="register"),
|
||||||
|
path("profile/", profile, name="profile"),
|
||||||
path("donors/", donor_list, name="donor_list"),
|
path("donors/", donor_list, name="donor_list"),
|
||||||
path("requests/", blood_request_list, name="blood_request_list"),
|
path("requests/", blood_request_list, name="blood_request_list"),
|
||||||
path("banks/", blood_bank_list, name="blood_bank_list"),
|
path("banks/", blood_bank_list, name="blood_bank_list"),
|
||||||
|
|||||||
@ -6,9 +6,34 @@ from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
|
|||||||
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 django.utils import timezone
|
from django.utils import timezone
|
||||||
from .models import Donor, BloodRequest, BloodBank, VaccineRecord
|
from .models import Donor, BloodRequest, BloodBank, VaccineRecord, UserProfile, BLOOD_GROUPS
|
||||||
|
from .forms import UserUpdateForm, ProfileUpdateForm
|
||||||
import math
|
import math
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def profile(request):
|
||||||
|
# Ensure user has a profile
|
||||||
|
profile, created = UserProfile.objects.get_or_create(user=request.user)
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
u_form = UserUpdateForm(request.POST, instance=request.user)
|
||||||
|
p_form = ProfileUpdateForm(request.POST, instance=profile)
|
||||||
|
if u_form.is_valid() and p_form.is_valid():
|
||||||
|
u_form.save()
|
||||||
|
p_form.save()
|
||||||
|
messages.success(request, f'Your account has been updated!')
|
||||||
|
return redirect('profile')
|
||||||
|
else:
|
||||||
|
u_form = UserUpdateForm(instance=request.user)
|
||||||
|
p_form = ProfileUpdateForm(instance=profile)
|
||||||
|
|
||||||
|
context = {
|
||||||
|
'u_form': u_form,
|
||||||
|
'p_form': p_form
|
||||||
|
}
|
||||||
|
|
||||||
|
return render(request, 'core/profile.html', context)
|
||||||
|
|
||||||
def haversine(lat1, lon1, lat2, lon2):
|
def haversine(lat1, lon1, lat2, lon2):
|
||||||
# Radius of the Earth in km
|
# Radius of the Earth in km
|
||||||
R = 6371.0
|
R = 6371.0
|
||||||
@ -92,6 +117,7 @@ def home(request):
|
|||||||
bb.stock_o_plus + bb.stock_o_minus + bb.stock_ab_plus + bb.stock_ab_minus
|
bb.stock_o_plus + bb.stock_o_minus + bb.stock_ab_plus + bb.stock_ab_minus
|
||||||
for bb in blood_banks
|
for bb in blood_banks
|
||||||
]),
|
]),
|
||||||
|
"total_capacity": sum([bb.total_capacity * 8 for bb in blood_banks]), # 8 blood types
|
||||||
"vaccinated_percentage": 0
|
"vaccinated_percentage": 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,7 +130,7 @@ def home(request):
|
|||||||
"donors": donor_list_data[:8],
|
"donors": donor_list_data[:8],
|
||||||
"blood_requests": blood_requests[:6],
|
"blood_requests": blood_requests[:6],
|
||||||
"blood_banks": blood_banks,
|
"blood_banks": blood_banks,
|
||||||
"blood_groups": [g[0] for g in Donor.BLOOD_GROUPS],
|
"blood_groups": [g[0] for g in BLOOD_GROUPS],
|
||||||
"stats": stats,
|
"stats": stats,
|
||||||
"project_name": "RaktaPulse",
|
"project_name": "RaktaPulse",
|
||||||
"current_time": timezone.now(),
|
"current_time": timezone.now(),
|
||||||
@ -142,7 +168,7 @@ def donor_list(request):
|
|||||||
|
|
||||||
context = {
|
context = {
|
||||||
'donors': donor_list_data,
|
'donors': donor_list_data,
|
||||||
'blood_groups': [g[0] for g in Donor.BLOOD_GROUPS],
|
'blood_groups': [g[0] for g in BLOOD_GROUPS],
|
||||||
}
|
}
|
||||||
return render(request, 'core/donor_list.html', context)
|
return render(request, 'core/donor_list.html', context)
|
||||||
|
|
||||||
@ -231,7 +257,7 @@ def request_blood(request):
|
|||||||
messages.error(request, "Please fill in all required fields.")
|
messages.error(request, "Please fill in all required fields.")
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'blood_groups': [g[0] for g in Donor.BLOOD_GROUPS],
|
'blood_groups': [g[0] for g in BLOOD_GROUPS],
|
||||||
'urgency_levels': BloodRequest.URGENCY_LEVELS,
|
'urgency_levels': BloodRequest.URGENCY_LEVELS,
|
||||||
}
|
}
|
||||||
return render(request, 'core/request_blood.html', context)
|
return render(request, 'core/request_blood.html', context)
|
||||||
|
|||||||
17
reduce_capacity.py
Normal file
17
reduce_capacity.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import os
|
||||||
|
import django
|
||||||
|
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
|
||||||
|
django.setup()
|
||||||
|
|
||||||
|
from core.models import BloodBank
|
||||||
|
|
||||||
|
def run():
|
||||||
|
banks = BloodBank.objects.all()
|
||||||
|
for bank in banks:
|
||||||
|
bank.total_capacity = 200 # Reduced from 1000
|
||||||
|
bank.save()
|
||||||
|
print("Capacity reduced for all blood banks.")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
run()
|
||||||
Loading…
x
Reference in New Issue
Block a user