stylist / backend / Stylist.Domain / Repositories / Implementations / ScheduleRepository.cs
ScheduleRepository.cs
Raw
using Microsoft.EntityFrameworkCore;
using Stylist.Data.Dtos.Salon;
using Stylist.Data.Models;
using Stylist.Data.Models.Dtos.Schedule;
using Stylist.Domain.Repositories.Interfaces;

namespace Stylist.Domain.Repositories.Implementations
{
    public class ScheduleRepository : IScheduleRepository
    {
        public ScheduleRepository(StylistContext context)
        {
            _context = context;
        }

        private readonly StylistContext _context;

        public async Task<IEnumerable<ScheduleAvailableSlotDto>> GetAllHairdresserAvailableSlotsByDate(int hairdresserId, DateTime date, int duration)
        {
            var schedule = await _context
                .Schedules
                .Include(s => s.Reservations)
                .Where(s => s.HairdresserId == hairdresserId)
                .Where(s => s.Starts.Date == date.Date && s.Ends.Date == date.Date)
                .FirstOrDefaultAsync();

            if (schedule == null)
            {
                return [];
            }

            var availableSlots = new List<ScheduleAvailableSlotDto>();

            var scheduleStart = TimeOnly.FromDateTime(schedule.Starts);
            var scheduleEnd = TimeOnly.FromDateTime(schedule.Ends);
            var freeSlotStart = scheduleStart;
            var freeSlotEnd = freeSlotStart.AddMinutes(duration);

            while (freeSlotEnd <= scheduleEnd)
            {
                var isAnyReservrationDuringSlot = schedule.Reservations.Any(r => isSlotReserved(r.Starts, r.Ends, freeSlotStart, freeSlotEnd));

                if (!isAnyReservrationDuringSlot)
                    availableSlots.Add(new ScheduleAvailableSlotDto
                    {
                        Starts = freeSlotStart,
                        Ends = freeSlotEnd,
                    });

                freeSlotStart = freeSlotStart.AddMinutes(15);
                freeSlotEnd = freeSlotEnd.AddMinutes(15);
            }

            return availableSlots;
        }

        private static bool isSlotReserved(TimeOnly reservationStart, TimeOnly reservationEnd, TimeOnly startFreeSlot, TimeOnly endFreeSlot)
        {
            return reservationStart.IsBetween(startFreeSlot, endFreeSlot)
                || reservationEnd.IsBetween(startFreeSlot, endFreeSlot)
                && startFreeSlot != reservationEnd
                && endFreeSlot != reservationStart
                || (startFreeSlot.IsBetween(reservationStart, reservationEnd) || endFreeSlot.IsBetween(reservationStart, reservationEnd));
        }
    }
}