Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion code/docker-compose-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ services:
- ./mymedic:/usr/src/mymedic

# Command to run the Django development server
command: python manage.py runserver 0.0.0:8000
command: sh -c "python manage.py makemigrations && python manage.py migrate && python manage.py runserver 0.0.0:8000"
50 changes: 50 additions & 0 deletions code/mymedic/data_mockup/records.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
[
{
"user_id": 1,
"doctor": "Dr. Smith",
"prescription": "Amoxicillin",
"dosage": "500mg",
"date": "2025-05-22",
"notes": "Take with food to avoid stomach upset. Prescribed for sinus infection."
},
{
"user_id": 1,
"doctor": "Dr. Adams",
"prescription": "Ibuprofen",
"dosage": "200mg",
"date": "2025-06-01",
"notes": "Take every 6 hours for pain relief. Do not exceed 1200mg per day."
},
{
"user_id": 1,
"doctor": "Dr. Smith",
"prescription": "Paracetamol",
"dosage": "650mg",
"date": "2025-06-05",
"notes": "For headaches and mild fever. Safe with other medications."
},
{
"user_id": 1,
"doctor": "Dr. Gomez",
"prescription": "Azithromycin",
"dosage": "250mg",
"date": "2025-06-03",
"notes": "5-day course for respiratory infection. Avoid antacids during treatment."
},
{
"user_id": 1,
"doctor": "Dr. Patel",
"prescription": "Lisinopril",
"dosage": "10mg",
"date": "2025-05-28",
"notes": "Monitor blood pressure. Report any dizziness or swelling."
},
{
"user_id": 1,
"doctor": "Dr. Nguyen",
"prescription": "Metformin",
"dosage": "1000mg",
"date": "2025-06-06",
"notes": "For blood sugar control. Take with meals to reduce GI upset."
}
]
66 changes: 66 additions & 0 deletions code/mymedic/static/css/dashboard.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,72 @@
padding: 2rem 0;
}

/* Search Section */
.search-section {
margin-bottom: 1rem;
}

.search-card {
background: rgba(255, 255, 255, 0.95);
border-radius: 15px;
padding: 2rem;
padding-top: 1rem;
padding-bottom: 0.25rem;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(10px);
}

.search-title {
color: #343a40;
font-size: 1.5rem;
font-weight: 700;
margin-bottom: 0.5rem;
}

.search-row {
display: flex;
align-items: center;
gap: 10px;
margin-top: 10px;
}

#search-input {
flex: 1;
padding: 10px;
font-size: 16px;
border: 1px solid #ccc;
border-radius: 5px;
box-sizing: border-box;
}

.btn {
border-radius: 5px !important;
font-weight: 600;
}

.btn-success {
background-color: #20b2aa !important;
border-color: #20b2aa !important;
}

.btn-success:hover:not(:disabled) {
background-color: #1a9999 !important;
border-color: #1a9999 !important;
box-shadow: 0 5px 15px rgba(32, 178, 170, 0.3);
}

.btn:disabled {
opacity: 0.6;
cursor: not-allowed;
}

#search-results {
margin-top: 20px;
font-size: 15px;
color: #555;
text-align: center;
}

/* Welcome Section */
.welcome-section {
margin-bottom: 2rem;
Expand Down
84 changes: 84 additions & 0 deletions code/mymedic/static/js/dashboard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
function logout() {
const logoutButton = document.querySelector('button[onclick="logout()"]');

if (logoutButton) {
logoutButton.disabled = true;
logoutButton.innerText = "Logging out...";
}

localStorage.removeItem("access");

setTimeout(() => {
window.location.href = "/login/";
}, 500);
}

document.addEventListener('DOMContentLoaded', function() {

const scheduleButtons = document.querySelectorAll('.action-card .btn');
if (scheduleButtons[0]) {
scheduleButtons[0].addEventListener('click', function() {
alert('Schedule appointment feature coming soon!');
});
}

if (scheduleButtons[1]) {
scheduleButtons[1].addEventListener('click', function() {
alert('View records feature coming soon!');
});
}

if (scheduleButtons[2]) {
scheduleButtons[2].addEventListener('click', function() {
alert('Manage prescriptions feature coming soon!');
});
}

const statCards = document.querySelectorAll('.stat-card');
statCards.forEach(card => {
card.addEventListener('click', function() {

const statLabel = this.querySelector('.stat-label').textContent;
alert(`${statLabel} details coming soon!`);
});

card.style.cursor = 'pointer';
});

const actionCards = document.querySelectorAll('.action-card');
actionCards.forEach(card => {
card.addEventListener('mouseenter', function() {
this.style.transform = 'translateY(-5px)';
});

card.addEventListener('mouseleave', function() {
this.style.transform = 'translateY(0)';
});
});
});

async function validateToken() {
const token = localStorage.getItem("access");
if (!token) return false;

try {
const res = await fetch("/api/validate-token/", {
method: "GET",
headers: {
"Authorization": `Bearer ${token}`,
"Content-Type": "application/json"
}
});

if (!res.ok) {
localStorage.removeItem("access");
window.location.href = "/login/";
return false;
}

return true;
} catch (error) {
console.log("Token validation failed:", error);
return true;
}
}
48 changes: 48 additions & 0 deletions code/mymedic/static/js/search.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
async function searchRecords() {
const input = document.getElementById("search-input").value.trim();
const resultsDiv = document.getElementById("search-results");

resultsDiv.innerHTML = "";

if (!input) {
resultsDiv.innerHTML = `<p class="text-danger">⚠️ Please enter a search term.</p>`;
return;
}

try {
const response = await fetch(`/api/search/?q=${encodeURIComponent(input)}`);
const data = await response.json();

if (data.length === 0) {
resultsDiv.innerHTML = `<p>No results found for "<strong>${input}</strong>".</p>`;
return;
}

/**
@ai-generated
Tool: ChatGPT (OpenAI)
Prompt: "Render search results as an HTML list from filtered JSON data"
Generated on: 2025-06-08
Modified by: Mengliang Tan
Modifications: Display doctor, prescription, date, dosage, and notes in formatted HTML

Verified: ✅ Tested via frontend display
*/
let html = `<ul class="list-group mt-3">`;
data.forEach(record => {
html += `<li class="list-group-item">
<strong>Doctor:</strong> ${record.doctor} <br>
<strong>Prescription:</strong> ${record.prescription} <br>
<strong>Date:</strong> ${record.date} <br>
<strong>Dosage:</strong> ${record.dosage} <br>
<strong>Notes:</strong> ${record.notes}
</li>`;
});
html += `</ul>`;
resultsDiv.innerHTML = html;

} catch (err) {
resultsDiv.innerHTML = `<p class="text-danger">❌ Error searching records. Please try again later.</p>`;
}
}

26 changes: 26 additions & 0 deletions code/mymedic/users/migrations/0003_prescription.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Generated by Django 5.2.1 on 2025-06-15 14:46

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('users', '0002_appointment'),
]

operations = [
migrations.CreateModel(
name='Prescription',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('doctor', models.CharField(max_length=100)),
('prescription', models.CharField(max_length=255)),
('date', models.DateField(blank=True, null=True)),
('dosage', models.CharField(blank=True, max_length=100, null=True)),
('notes', models.TextField(blank=True, null=True)),
('patient', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='users.patient')),
],
),
]
14 changes: 12 additions & 2 deletions code/mymedic/users/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ class Patient(models.Model):

def __str__(self):
return f"{self.first_name} {self.last_name} ({self.email})"


class Appointment(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
Expand All @@ -35,4 +34,15 @@ class Appointment(models.Model):
reason = models.CharField(max_length=200)

def __str__(self):
return f"{self.date} - {self.patient_name} with {self.doctor_name}"
return f"{self.date} - {self.patient_name} with {self.doctor_name}"

class Prescription(models.Model):
patient = models.ForeignKey(Patient, on_delete=models.CASCADE)
doctor = models.CharField(max_length=100)
prescription = models.CharField(max_length=255)
date = models.DateField(blank=True, null=True)
dosage = models.CharField(max_length=100, blank=True, null=True)
notes = models.TextField(blank=True, null=True)

def __str__(self):
return f"{self.doctor} - {self.prescription}"
17 changes: 17 additions & 0 deletions code/mymedic/users/templates/users/dashboard.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,21 @@ <h1 class="header-title">MyMedic</h1>
<!-- Main Content -->
<main class="dashboard-main">
<div class="container-fluid">
<!-- Search -->
<div class="search-section animate__animated animate__fadeIn">
<div class="row">
<div class="col-12">
<div class="search-card">
<h2 class="search-title">Search Records</h2>
<div class="search-row">
<input type="text" id="search-input" placeholder="Enter doctor or prescription" />
<button id="search-btn" class="btn btn-success" onclick="searchRecords()">Search</button>
</div>
<div id="search-results" class="mt-3"></div>
</div>
</div>
</div>
</div>

<!-- Welcome Section -->
<div class="welcome-section animate__animated animate__fadeIn">
Expand Down Expand Up @@ -195,4 +210,6 @@ <h5 class="activity-title">Prescription Refilled</h5>

</footer>
</main>
<script src="{% static 'js/dashboard.js' %}"></script>
<script src="{% static 'js/search.js' %}"></script>
</html>
2 changes: 1 addition & 1 deletion code/mymedic/users/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@
path('', views.mlogin, name=''), # Default route to login
path('cancel/<int:appointment_id>/', views.cancel_appointment, name='cancel_appointment'),
path("privacy/", views.privacy_policy, name="privacy_policy"),

path('api/search/', views.search_records, name='search'),
]
Loading