Skip to content

Commit e0bedb3

Browse files
Merge pull request #76 from AlbinHall/30-create-user-dashboard
Create user dashboard logic (and background service cleanup fix)
2 parents d8d822f + 41558fd commit e0bedb3

12 files changed

Lines changed: 247 additions & 131 deletions

File tree

HealthCareABApi/BackgroundJobs/CleanupSlotsService.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,31 @@ public class CleanupSlotsService(IServiceProvider services) : BackgroundService
1212

1313
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
1414
{
15+
// Clean on startup
16+
using (var initialScope = _services.CreateScope())
17+
{
18+
try
19+
{
20+
// Kör rensning direkt vid uppstart
21+
var initialDbContext = initialScope.ServiceProvider.GetRequiredService<HealthCareDbContext>();
22+
var currentTime = DateTime.Now;
23+
24+
var expiredSlots = initialDbContext.Availability.Where(a => a.EndTime < currentTime).ToList();
25+
26+
if (expiredSlots.Any())
27+
{
28+
initialDbContext.RemoveRange(expiredSlots);
29+
await initialDbContext.SaveChangesAsync(stoppingToken);
30+
31+
Console.WriteLine($"Deleted {expiredSlots.Count} expired slots on startup - {DateTime.Now:yyyy-MM-dd}");
32+
}
33+
}
34+
catch (Exception ex)
35+
{
36+
Console.WriteLine($"Error during initial cleanup: {ex.Message}");
37+
}
38+
}
39+
1540
while (!stoppingToken.IsCancellationRequested)
1641
{
1742
var currentTime = DateTime.Now;

HealthCareABApi/Controllers/AppointmentController.cs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,12 +115,12 @@ public async Task<IActionResult> UpdateAppointment([FromBody] UpdateAppointmentD
115115
}
116116
}
117117

118-
[HttpGet("getappointmentsbypatientid/{patientId}")]
119-
public async Task<IActionResult> GetByUserId(int patientId)
118+
[HttpGet("getcompletedappointmentsbyuserid/{userId}")]
119+
public async Task<IActionResult> GetByUserId(int userId)
120120
{
121121
try
122122
{
123-
var appointments = await _appointmentService.GetByUserIdAsync(patientId);
123+
var appointments = await _appointmentService.GetCompletedByUserIdAsync(userId);
124124
return Ok(appointments);
125125
}
126126
catch (KeyNotFoundException)
@@ -133,5 +133,23 @@ public async Task<IActionResult> GetByUserId(int patientId)
133133
}
134134
}
135135

136+
[Authorize(Roles = Roles.User)]
137+
[HttpGet("getscheduledappointments/{userId}")]
138+
public async Task<IActionResult> GetScheduledAppointments(int userId)
139+
{
140+
try
141+
{
142+
var scheduledAppointments = await _appointmentService.GetScheduledAppointmentsAsync(userId);
143+
return Ok(scheduledAppointments);
144+
}
145+
catch (KeyNotFoundException)
146+
{
147+
return BadRequest();
148+
}
149+
catch (Exception)
150+
{
151+
return StatusCode(500, "Error processing GET method at api/getscheduledappointments");
152+
}
153+
}
136154
}
137155
}

HealthCareABApi/Controllers/HistoryController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public async Task<IActionResult> GetAppointmentsForHistory()
4141
return BadRequest("User Id is not valid");
4242
}
4343

44-
var appointments = await _AppointmentRepository.GetByUserIdAsync(userId);
44+
var appointments = await _AppointmentRepository.GetCompletedByUserIdAsync(userId);
4545

4646
if (appointments == null)
4747
{
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace HealthCareABApi.DTO
2+
{
3+
public class ScheduledAppointmentsDTO
4+
{
5+
public int Id { get; set; }
6+
public DateTime AppointmentTime { get; set; }
7+
public string CaregiverName { get; set; }
8+
public string PatientName { get; set; }
9+
}
10+
}

HealthCareABApi/DTO/UniqueSlotsDTO.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
{
33
public class UniqueSlotsDTO
44
{
5+
public int Id { get; set; }
56
public DateTime StartTime { get; set; }
67
public DateTime EndTime { get; set; }
78
public List<CaregiverDTO> Caregivers { get; set; }
Lines changed: 144 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
1-
using System;
2-
using HealthCareABApi.Models;
3-
using HealthCareABApi.Repositories.Data;
4-
using Microsoft.EntityFrameworkCore;
5-
6-
namespace HealthCareABApi.Repositories.Implementations
7-
{
8-
public class AppointmentRepository : IAppointmentRepository
9-
{
10-
private readonly HealthCareDbContext _Dbcontext;
11-
12-
public AppointmentRepository(HealthCareDbContext context)
13-
{
14-
_Dbcontext = context;
15-
}
16-
17-
public async Task<IEnumerable<Appointment>> GetAllAsync()
18-
{
19-
return await _Dbcontext.Appointment
20-
.Include(a => a.Patient)
21-
.Include(a => a.Caregiver)
22-
.ToListAsync();
1+
using System;
2+
using HealthCareABApi.Models;
3+
using HealthCareABApi.Repositories.Data;
4+
using Microsoft.EntityFrameworkCore;
5+
6+
namespace HealthCareABApi.Repositories.Implementations
7+
{
8+
public class AppointmentRepository : IAppointmentRepository
9+
{
10+
private readonly HealthCareDbContext _Dbcontext;
11+
12+
public AppointmentRepository(HealthCareDbContext context)
13+
{
14+
_Dbcontext = context;
15+
}
16+
17+
public async Task<IEnumerable<Appointment>> GetAllAsync()
18+
{
19+
return await _Dbcontext.Appointment
20+
.Include(a => a.Patient)
21+
.Include(a => a.Caregiver)
22+
.ToListAsync();
2323
}
2424

2525
public async Task<Appointment> GetByIdAsync(int id)
@@ -39,87 +39,126 @@ public async Task<Appointment> GetByPatientAndTimeAsync(int patientId, DateTime
3939
a.PatientId == patientId &&
4040
EF.Functions.DateDiffSecond(a.DateTime, localTime) == 0 && // Ignorerar millisekunder i databasen och kollar tiden på sekundnivå
4141
a.Status == AppointmentStatus.Scheduled);
42-
}
43-
44-
public async Task<IEnumerable<Appointment>> GetByUserIdAsync(int patientId)
45-
{
46-
return await _Dbcontext.Appointment
47-
.Include(x => x.Caregiver)
48-
.Include(x => x.Patient)
49-
.Where(x => x.PatientId == patientId && x.Status == AppointmentStatus.Completed)
50-
.ToListAsync();
51-
}
52-
53-
public async Task CreateAsync(Appointment appointment)
54-
{
55-
if (appointment == null)
56-
{
57-
throw new ArgumentNullException(nameof(appointment), "Appointment is null and will blow up the system in 3........2........1.........");
58-
}
59-
60-
try
61-
{
62-
var availability = await _Dbcontext.Availability
63-
.FirstOrDefaultAsync(a =>
64-
a.Caregiver.Id == appointment.CaregiverId &&
65-
a.StartTime <= appointment.DateTime &&
66-
a.EndTime > appointment.DateTime &&
67-
!a.IsBooked);
68-
69-
if (availability == null)
70-
{
71-
throw new InvalidOperationException("No available slot for this time.");
72-
}
73-
74-
availability.IsBooked = true;
75-
availability.Appointment = appointment;
76-
77-
await _Dbcontext.Appointment.AddAsync(appointment);
78-
79-
await _Dbcontext.SaveChangesAsync();
80-
//await _Dbcontext.Appointment.AddAsync(appointment);
81-
//await _Dbcontext.SaveChangesAsync();
82-
}
83-
catch (DbUpdateException ex)
84-
{
85-
throw new InvalidOperationException("Database error while creating appointment", ex);
86-
}
87-
catch (Exception ex)
88-
{
89-
throw new InvalidOperationException("Error creating new appointment", ex);
90-
}
91-
}
92-
93-
public async Task<bool> UpdateAsync(int id, Appointment appointment)
94-
{
95-
var exist = await _Dbcontext.Appointment.Where(a => a.Id == id).FirstOrDefaultAsync();
96-
97-
if (exist == null)
98-
{
99-
return false;
100-
}
101-
102-
_Dbcontext.Appointment.Entry(exist).CurrentValues.SetValues(appointment);
103-
await _Dbcontext.SaveChangesAsync();
104-
return true;
105-
}
106-
107-
public async Task DeleteAsync(int id)
108-
{
109-
try
110-
{
111-
await _Dbcontext.Appointment.Where(a => a.Id == id).ExecuteDeleteAsync();
112-
await _Dbcontext.SaveChangesAsync();
113-
}
114-
catch (DbUpdateException ex)
115-
{
116-
throw new InvalidOperationException("Database error while deleting appointment", ex);
117-
}
118-
catch (Exception ex)
119-
{
120-
throw new InvalidOperationException("Error deleting appointment", ex);
121-
}
12242
}
123-
}
124-
}
125-
43+
44+
public async Task<IEnumerable<Appointment>> GetCompletedByUserIdAsync(int userId)
45+
{
46+
return await _Dbcontext.Appointment
47+
.Include(x => x.Caregiver)
48+
.Include(x => x.Patient)
49+
.Where(x => x.PatientId == userId && x.Status == AppointmentStatus.Completed)
50+
.ToListAsync();
51+
}
52+
53+
public async Task CreateAsync(Appointment appointment)
54+
{
55+
if (appointment == null)
56+
{
57+
throw new ArgumentNullException(nameof(appointment), "Appointment is null and will blow up the system in 3........2........1.........");
58+
}
59+
60+
try
61+
{
62+
var availability = await _Dbcontext.Availability
63+
.FirstOrDefaultAsync(a =>
64+
a.Caregiver.Id == appointment.CaregiverId &&
65+
a.StartTime <= appointment.DateTime &&
66+
a.EndTime > appointment.DateTime &&
67+
!a.IsBooked);
68+
69+
if (availability == null)
70+
{
71+
throw new InvalidOperationException("No available slot for this time.");
72+
}
73+
74+
availability.IsBooked = true;
75+
availability.Appointment = appointment;
76+
77+
await _Dbcontext.Appointment.AddAsync(appointment);
78+
79+
await _Dbcontext.SaveChangesAsync();
80+
}
81+
catch (DbUpdateException ex)
82+
{
83+
throw new InvalidOperationException("Database error while creating appointment", ex);
84+
}
85+
catch (Exception ex)
86+
{
87+
throw new InvalidOperationException("Error creating new appointment", ex);
88+
}
89+
}
90+
91+
public async Task<bool> UpdateAsync(int id, Appointment appointment)
92+
{
93+
var exist = await _Dbcontext.Appointment.Where(a => a.Id == id).FirstOrDefaultAsync();
94+
95+
if (exist == null)
96+
{
97+
return false;
98+
}
99+
100+
_Dbcontext.Appointment.Entry(exist).CurrentValues.SetValues(appointment);
101+
await _Dbcontext.SaveChangesAsync();
102+
return true;
103+
}
104+
105+
public async Task DeleteAsync(int id)
106+
{
107+
using (var transaction = await _Dbcontext.Database.BeginTransactionAsync())
108+
{
109+
110+
try
111+
{
112+
var relatedAvailability = await _Dbcontext.Availability
113+
.Where(a => a.AppointmentId == id)
114+
.FirstOrDefaultAsync();
115+
116+
if (relatedAvailability == null)
117+
{
118+
throw new ArgumentNullException("No availability is related to this appointment.");
119+
}
120+
121+
relatedAvailability.AppointmentId = null;
122+
relatedAvailability.IsBooked = false;
123+
await _Dbcontext.SaveChangesAsync(); // Need to update and save appointmentId in selected slot before deleting the appointment cuz of FK constraint
124+
125+
await _Dbcontext.Appointment.Where(a => a.Id == id).ExecuteDeleteAsync();
126+
await _Dbcontext.SaveChangesAsync();
127+
128+
await transaction.CommitAsync();
129+
}
130+
catch (DbUpdateException ex)
131+
{
132+
await transaction.RollbackAsync();
133+
throw new InvalidOperationException("Database error while deleting appointment", ex);
134+
}
135+
catch (Exception ex)
136+
{
137+
await transaction.RollbackAsync();
138+
throw new InvalidOperationException("Error deleting appointment", ex);
139+
}
140+
}
141+
}
142+
143+
public async Task<IEnumerable<Appointment>> GetScheduledAppointmentsAsync(int userId)
144+
{
145+
try
146+
{
147+
return await _Dbcontext.Appointment
148+
.Include(a => a.Caregiver)
149+
.Include(a => a.Patient)
150+
.Where(a => a.PatientId == userId && a.Status == AppointmentStatus.Scheduled && a.DateTime > DateTime.Now)
151+
.ToListAsync();
152+
}
153+
catch (DbUpdateException ex)
154+
{
155+
throw new InvalidOperationException("Database error while fetching scheduled appointments");
156+
}
157+
catch (Exception ex)
158+
{
159+
throw new InvalidOperationException("Error fetching scheduled appointments.", ex);
160+
}
161+
}
162+
}
163+
}
164+

HealthCareABApi/Repositories/Interfaces/IAppointmentRepository.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using HealthCareABApi.DTO;
23
using HealthCareABApi.Models;
34

45
namespace HealthCareABApi.Repositories
@@ -10,8 +11,9 @@ public interface IAppointmentRepository
1011
Task CreateAsync(Appointment appointment);
1112
Task<bool> UpdateAsync(int id, Appointment appointment);
1213
Task DeleteAsync(int id);
13-
Task<IEnumerable<Appointment>> GetByUserIdAsync(int patientId);
14+
Task<IEnumerable<Appointment>> GetCompletedByUserIdAsync(int userId);
1415
Task<Appointment> GetByPatientAndTimeAsync(int patientId, DateTime appointmentTime);
16+
Task<IEnumerable<Appointment>> GetScheduledAppointmentsAsync(int userId);
1517
}
1618
}
1719

HealthCareABApi/Repositories/Interfaces/IAppointmentService.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ public interface IAppointmentService
99
Task<Appointment> GetByIdAsync(int id);
1010
Task UpdateAsync(UpdateAppointmentDTO dto);
1111
Task DeleteAsync(int id);
12-
Task<IEnumerable<DetailedResponseDTO>> GetByUserIdAsync(int patientId);
12+
Task<IEnumerable<DetailedResponseDTO>> GetCompletedByUserIdAsync(int userId);
1313
Task<IEnumerable<GetAllAppointmentsDTO>> GetAllAsync();
14+
Task<IEnumerable<ScheduledAppointmentsDTO>> GetScheduledAppointmentsAsync(int userId);
1415
}
1516
}

0 commit comments

Comments
 (0)