Skip to content

Commit 7060c0f

Browse files
author
Tyler Gonsalves
committed
Merge branch 'main' into privacy-policy-page
2 parents ee28dd0 + 64bc3a4 commit 7060c0f

File tree

9 files changed

+156
-4
lines changed

9 files changed

+156
-4
lines changed

code/mymedic/static/css/dashboard.css

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,55 @@
210210
font-weight: 500;
211211
}
212212

213+
214+
/* Appointment Card Section */
215+
.appointments-container {
216+
display: flex;
217+
flex-wrap: wrap;
218+
gap: 1.5rem;
219+
justify-content: flex-start;
220+
margin-top: 2rem;
221+
}
222+
223+
.appointments-section .card {
224+
width: 260px;
225+
height: 200px;
226+
padding: 1.2rem 1rem;
227+
margin-bottom: 3rem;
228+
border-radius: 12px;
229+
background-color: #ffffff;
230+
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
231+
text-align: center;
232+
display: flex;
233+
flex-direction: column;
234+
justify-content: space-between;
235+
}
236+
237+
238+
.appointment-date {
239+
font-size: 1.1rem;
240+
font-weight: 600;
241+
margin-bottom: 0.5rem;
242+
color: #20b2aa;
243+
}
244+
245+
.appointment-detail {
246+
font-size: 0.95rem;
247+
color: #444;
248+
margin-bottom: 1rem;
249+
}
250+
251+
.appointments-section .card form {
252+
margin-top: auto;
253+
}
254+
255+
.appointments-section .btn-danger {
256+
background-color: #dc3545;
257+
border-color: #dc3545;
258+
font-weight: 500;
259+
}
260+
261+
213262
/* Responsive */
214263
@media (max-width: 768px) {
215264
.welcome-title {
@@ -224,4 +273,4 @@
224273
.dashboard-main {
225274
padding: 1rem 0;
226275
}
227-
}
276+
}

code/mymedic/tests/users/__init__.py

Whitespace-only changes.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
from django.test import TestCase, Client
2+
from django.contrib.auth.models import User
3+
from users.models import Appointment
4+
from django.urls import reverse
5+
from datetime import date
6+
7+
class AppointmentTests(TestCase):
8+
def setUp(self):
9+
self.client = Client()
10+
self.user = User.objects.create_user(username='testuser', password='testpass')
11+
self.appointment = Appointment.objects.create(
12+
user=self.user,
13+
patient_name='testuser',
14+
doctor_name='Dr. House',
15+
date=date.today(),
16+
reason='Annual Checkup'
17+
)
18+
19+
def test_appointment_shows_on_dashboard(self):
20+
self.client.login(username='testuser', password='testpass')
21+
response = self.client.get(reverse('dashboard'))
22+
self.assertEqual(response.status_code, 200)
23+
self.assertContains(response, 'Dr. House')
24+
self.assertContains(response, 'Annual Checkup')
25+
26+
def test_cancel_appointment(self):
27+
self.client.login(username='testuser', password='testpass')
28+
response = self.client.post(reverse('cancel_appointment', args=[self.appointment.id]))
29+
self.assertRedirects(response, reverse('dashboard'))
30+
self.assertFalse(Appointment.objects.filter(id=self.appointment.id).exists())

code/mymedic/users/admin.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
"""This module registers the user models with django"""
22
from django.contrib import admin
33
from .models import Patient
4+
from .models import Appointment
45

56
# Register your models here.
6-
admin.site.register(Patient)
7+
admin.site.register(Patient)
8+
admin.site.register(Appointment)
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Generated by Django 4.2.21 on 2025-06-15 07:18
2+
3+
from django.conf import settings
4+
from django.db import migrations, models
5+
import django.db.models.deletion
6+
7+
8+
class Migration(migrations.Migration):
9+
10+
dependencies = [
11+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
12+
('users', '0001_initial'),
13+
]
14+
15+
operations = [
16+
migrations.CreateModel(
17+
name='Appointment',
18+
fields=[
19+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
20+
('patient_name', models.CharField(max_length=100)),
21+
('doctor_name', models.CharField(max_length=100)),
22+
('date', models.DateField()),
23+
('reason', models.CharField(max_length=200)),
24+
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
25+
],
26+
),
27+
]

code/mymedic/users/models.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
Verified: ✅ Unit tested, reviewed
1212
"""
1313
from django.db import models
14+
from django.contrib.auth.models import User
1415

1516
# Create your models here.
1617
class Patient(models.Model):
@@ -23,4 +24,15 @@ class Patient(models.Model):
2324
date_of_birth = models.DateField(blank=True, null=True)
2425

2526
def __str__(self):
26-
return f"{self.first_name} {self.last_name} ({self.email})"
27+
return f"{self.first_name} {self.last_name} ({self.email})"
28+
29+
30+
class Appointment(models.Model):
31+
user = models.ForeignKey(User, on_delete=models.CASCADE)
32+
patient_name = models.CharField(max_length=100)
33+
doctor_name = models.CharField(max_length=100)
34+
date = models.DateField()
35+
reason = models.CharField(max_length=200)
36+
37+
def __str__(self):
38+
return f"{self.date} - {self.patient_name} with {self.doctor_name}"

code/mymedic/users/templates/users/dashboard.html

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,25 @@ <h3 class="stat-number">1</h3>
9999
</div>
100100
</div>
101101

102+
<!-- Upcoming Appointments -->
103+
<div class="appointments-section">
104+
<h3 class="section-title">Your Upcoming Appointments</h3>
105+
<div class="appointments-container">
106+
{% for appointment in appointments %}
107+
<div class="card">
108+
<div class="appointment-date">{{ appointment.date|date:"F d, Y" }}</div>
109+
<div class="appointment-detail">Appointment with {{ appointment.doctor_name }}</div>
110+
<div class="appointment-reason">{{ appointment.reason }}</div>
111+
<form method="POST" action="{% url 'cancel_appointment' appointment.id %}" onsubmit="return confirm('Are you sure you want to cancel this appointment?');">
112+
{% csrf_token %}
113+
<button type="submit" class="btn btn-danger">Cancel</button>
114+
</form>
115+
</div>
116+
{% endfor %}
117+
</div>
118+
</div>
119+
120+
102121
<!-- Quick Actions -->
103122
<div class="actions-section">
104123
<div class="row">
@@ -134,6 +153,7 @@ <h4 class="action-title">Prescriptions</h4>
134153
</div>
135154
</div>
136155

156+
137157
<!-- Recent Activity -->
138158
<div class="activity-section">
139159
<div class="row">

code/mymedic/users/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
path('profile', views.profile, name='profile'),
99
path('mlogout', views.mlogout, name='mlogout'),
1010
path('', views.mlogin, name=''), # Default route to login
11+
path('cancel/<int:appointment_id>/', views.cancel_appointment, name='cancel_appointment'),
1112
path("privacy/", views.privacy_policy, name="privacy_policy"),
1213

1314
]

code/mymedic/users/views.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
from .models import Patient
1919
from django.contrib.auth.decorators import login_required
2020
from django.contrib import messages
21+
from users.models import Appointment
22+
from django.shortcuts import get_object_or_404
2123

2224
# Create your views here.
2325
def register(request):
@@ -77,7 +79,8 @@ def dashboard(request):
7779
"""
7880
Render the dashboard view for users.
7981
"""
80-
return render(request, 'users/dashboard.html')
82+
appointments = Appointment.objects.filter(user=request.user).order_by('date')
83+
return render(request, 'users/dashboard.html', {'appointments': appointments})
8184

8285
@login_required(login_url='mlogin')
8386
def profile(request):
@@ -114,6 +117,14 @@ def profile(request):
114117
return redirect("profile")
115118
else:
116119
return render(request, 'users/profile.html', context={"form": form})
120+
121+
@login_required(login_url='mlogin')
122+
def cancel_appointment(request, appointment_id):
123+
appointment = get_object_or_404(Appointment, id=appointment_id, user=request.user)
124+
if request.method == "POST":
125+
appointment.delete()
126+
messages.success(request, "Appointment canceled successfully.")
127+
return redirect("dashboard")
117128

118129
def privacy_policy(request):
119130
return render(request, 'users/privacy_policy.html')

0 commit comments

Comments
 (0)