<|start_filename|>Web/BeautyBooking.Web.ViewModels/BlogPosts/BlogPostsPaginatedListViewModel.cs<|end_filename|>
﻿namespace BeautyBooking.Web.ViewModels.BlogPosts
{
    using BeautyBooking.Web.ViewModels.Common.Pagination;

    public class BlogPostsPaginatedListViewModel
    {
        public PaginatedList<BlogPostViewModel> BlogPosts { get; set; }
    }
}


<|start_filename|>Web/BeautyBooking.Web/Views/Appointments/Index.cshtml<|end_filename|>
﻿@model BeautyBooking.Web.ViewModels.Appointments.AppointmentsListViewModel
@{
    this.ViewData["Title"] = "Your Appointments";
}

@if (@Model.Appointments.Count() == 0)
{
    <div class="row">
        <div class="col-lg-4 ml-lg-5">
            <div class="about_text_2">
                <p>
                    Oh, no! Nothing booked yet...
                </p>
            </div>
            <div class="about_text_highlight">
                Book an appointment in 3 easy steps:
            </div>
            <div class="about_text_highlight">
                <ol>
                    <li>Find a salon.</li>
                    <li>Choose a beauty service.</li>
                    <li>Pick date and time.</li>
                </ol>
            </div>
            <div class="about_text_2">
                <p>
                    Waiting you back here. :)
                </p>
            </div>
        </div>
    </div>
    <div class="row">
        <div class="col-lg-4 ml-lg-5">
            <div class="button button-large button_1 elements_button mt-4">
                <a asp-area="" asp-controller="Salons" asp-action="Index">
                    <span>Find Salons</span>
                    <span>Find Salons</span>
                </a>
            </div>
        </div>
    </div>
}

@if (@Model.Appointments.Count() > 0)
{
    <h2>Upcoming (@Model.Appointments.Count())</h2>

    <table class="table table-bordered table-striped">
        <thead class="thead-light">
            <tr>
                <th scope="col">Date and Time</th>
                <th scope="col">Status <span class="text-info">*</span></th>
                <th scope="col">Salon</th>
                <th scope="col">Address</th>
                <th scope="col">Service</th>
                <th scope="col">Cancelation</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var appointment in this.Model.Appointments)
            {
                <tr>
                    <th scope="row">@appointment.DateTime.ToString("f")</th>
                    <td>
                        @if (appointment.Confirmed == true)
                        {
                            <span class="badge badge-success">Confirmed</span>
                        }
                        else if (appointment.Confirmed == false)
                        {
                            <span class="badge badge-danger">Declined</span>
                        }
                        else
                        {
                            <span class="badge badge-secondary">Pending</span>
                        }
                    </td>
                    <td>@appointment.SalonName</td>
                    <td>@appointment.SalonCityName, @appointment.SalonAddress</td>
                    <td>@appointment.ServiceName</td>
                    <td>
                        <a class="btn btn-outline-danger btn-sm"
                           asp-area="" asp-controller="Appointments" asp-action="CancelAppointment" asp-route-id="@appointment.Id">
                            Cancel
                        </a>
                    </td>
                </tr>
            }
        </tbody>
    </table>

    <div class="row">
        <div class="col-lg-10 ml-lg-5">
            <div class="about_text_highlight">
                <span class="text-info">*</span> Status
            </div>
            <div class="about_text_2">
                <ol>
                    <li>
                        <span class="badge badge-secondary">Pending</span>
                        - Waiting for the Salon's reply.
                    </li>
                    <li>
                        <span class="badge badge-success">Confirmed</span>
                        - Good! Your appointment is confirmed.
                        They are expecting you on the set date and time.
                    </li>
                    <li>
                        <span class="badge badge-danger">Declined</span>
                        - Sorry, the appointment can't happen on the set date and time.
                        Check your email for rescheduling options from the Salon.
                    </li>
                </ol>
                <ul>
                    <li>Or you can just <strong>book again.</strong> Remember the steps, right?</li>
                    <li>Go find a salon, choose a service and pick date and time.</li>
                    <li>
                        <div class="button button-large button_1 elements_button mt-4">
                            <a asp-area="" asp-controller="Salons" asp-action="Index">
                                <span>Find Salons</span>
                                <span>Find Salons</span>
                            </a>
                        </div>
                    </li>
                </ul>
            </div>
        </div>
    </div>
}

<hr class="bg-dark m-4" style="height: 6px;" />

<div>
    @await Component.InvokeAsync("PastAppointments")
</div>


<|start_filename|>Web/BeautyBooking.Web/Areas/Administration/Views/Dashboard/Index.cshtml<|end_filename|>
﻿@using BeautyBooking.Common
@{
    this.ViewData["Title"] = "Admin Dashboard";
}

<h3>Welcome to Admin Dashboard!</h3>
<p>Here is a quick navigation:</p>
<div>
    <a asp-area="Administration" asp-controller="BlogPosts" asp-action="Index"
       class="list-group-item list-group-item-action bg-light">Blog Posts</a>

    <div class="ml-5 my-2">
        <a class="btn btn-outline-info btn-sm" asp-area="Administration" asp-controller="BlogPosts" asp-action="AddBlogPost">Add New Blog Post</a>
    </div>

    <a asp-area="Administration" asp-controller="Categories" asp-action="Index"
       class="list-group-item list-group-item-action bg-light">Categories</a>

    <dvi class="ml-5 my-2">
        <a class="btn btn-outline-info btn-sm" asp-area="Administration" asp-controller="Categories" asp-action="AddCategory">Add New Category</a>
    </dvi>

    <a asp-area="Administration" asp-controller="Services" asp-action="Index"
       class="list-group-item list-group-item-action bg-light">Services</a>

    <div class="ml-5 my-2">
        <a class="btn btn-outline-info btn-sm" asp-area="Administration" asp-controller="Services" asp-action="AddService">Add New Service</a>
    </div>

    <a asp-area="Administration" asp-controller="Cities" asp-action="Index"
       class="list-group-item list-group-item-action bg-light">Cities</a>

    <div class="ml-5 my-2">
        <a class="btn btn-outline-info btn-sm" asp-area="Administration" asp-controller="Cities" asp-action="AddCity">Add New City</a>
    </div>

    <a asp-area="Administration" asp-controller="Salons" asp-action="Index"
       class="list-group-item list-group-item-action bg-light">Salons</a>

    <div class="ml-5 my-2">
        <a class="btn btn-outline-info btn-sm" asp-area="Administration" asp-controller="Salons" asp-action="AddSalon">Add New Salon</a>
    </div>

    <a asp-area="Administration" asp-controller="Appointments" asp-action="Index"
       class="list-group-item list-group-item-action bg-light">Appointments</a>
</div>

<|start_filename|>Web/BeautyBooking.Web/Views/Shared/_FooterPartial.cshtml<|end_filename|>
﻿@using BeautyBooking.Common

<footer class="footer">
    <div class="background_image" style="background-image:url(@GlobalConstants.Images.Footer)"></div>
    <div class="footer_content">
        <div class="container">
            <div class="row">

                <!-- Footer About -->
                <div class="col-lg-12 footer_col">
                    <div class="footer_about">
                        <div class="logo">
                            <a asp-area="" asp-controller="Home" asp-action="Index">Beauty<span>Booking</span></a>
                        </div>
                        <div class="footer_about_text">The only right way to find and book your beauty services!</div>

                        <div class="copyright">
                            Copyright &copy;
                            <script>document.write(new Date().getFullYear());</script> BeautyBooking
                        </div>
                    </div>
                </div>

            </div>
        </div>
    </div>

    <div class="footer_bar">
        <div class="container">
            <div class="row">
                <div class="col">
                    <div class="footer_bar_content d-flex flex-sm-row flex-column align-items-lg-center align-items-start justify-content-start">
                        <nav class="footer_nav">
                            <ul class="d-flex flex-lg-row flex-column align-items-lg-center align-items-start justify-content-start">
                                <partial name="_MenuItemsPartial" />
                            </ul>
                        </nav>
                        <div class="footer_links">
                            <ul class="d-flex flex-lg-row flex-column align-items-lg-center align-items-start justify-content-start">
                                <li><a class="text-secondary" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy Policy</a></li>
                            </ul>
                        </div>
                        <div class="footer_phone ml-lg-auto">
                            <a href="https://github.com/marinakolova/BeautyBooking" target="_blank">
                                <i class="fa fa-github" aria-hidden="true"></i>
                                <span> Open Source System</span>
                            </a>
                        </div>
                    </div>
                </div>
            </div>            
        </div>
    </div>
</footer>


<|start_filename|>Web/BeautyBooking.Web/Views/Appointments/CancelAppointment.cshtml<|end_filename|>
﻿@model BeautyBooking.Web.ViewModels.Appointments.AppointmentViewModel
@{
    this.ViewData["Title"] = "Cancel Appointment";
}

<h3><strong>Are you sure you want to cancel this appointment?</strong></h3>
<form class="col-6 mt-5">
    <div class="form-group row">
        <label class="col-sm-3 col-form-label">Date and Time</label>
        <div class="col-sm-7">
            <div class="form-control">@Model.DateTime</div>
        </div>
    </div>
    <div class="form-group row">
        <label class="col-sm-3 col-form-label">Salon</label>
        <div class="col-sm-7">
            <div class="form-control">@Model.SalonName</div>
        </div>
    </div>
    <div class="form-group row">
        <label class="col-sm-3 col-form-label">Address</label>
        <div class="col-sm-7">
            <div class="form-control">@Model.SalonCityName, @Model.SalonAddress</div>
        </div>
    </div>
    <div class="form-group row">
        <label class="col-sm-3 col-form-label">Service</label>
        <div class="col-sm-7">
            <div class="form-control">@Model.ServiceName</div>
        </div>
    </div>
</form>

<div class="col-6 mt-5 ml-5">
    <div class="row ml-5">
        <form method="post">
            <button type="submit" class="btn btn-outline-success"
                    asp-area="" asp-controller="Appointments" asp-action="DeleteAppointment" asp-route-id="@Model.Id">
                Yes, Cancel it!
            </button>
        </form>
        <div class="ml-5">
            <a class="btn btn-danger" asp-area="" asp-controller="Appointments" asp-action="Index">No! Go Back</a>
        </div>
    </div>
</div>


<|start_filename|>Web/BeautyBooking.Web.ViewModels/BlogPosts/BlogPostViewModel.cs<|end_filename|>
﻿namespace BeautyBooking.Web.ViewModels.BlogPosts
{
    using System;

    using BeautyBooking.Data.Models;
    using BeautyBooking.Services.Mapping;

    public class BlogPostViewModel : IMapFrom<BlogPost>
    {
        public int Id { get; set; }

        public string Title { get; set; }

        public string Author { get; set; }

        public string Content { get; set; }

        public string ImageUrl { get; set; }

        public DateTime CreatedOn { get; set; }
    }
}


<|start_filename|>Web/BeautyBooking.Web.ViewModels/BlogPosts/BlogPostInputModel.cs<|end_filename|>
﻿namespace BeautyBooking.Web.ViewModels.BlogPosts
{
    using System.ComponentModel.DataAnnotations;

    using BeautyBooking.Common;
    using BeautyBooking.Web.ViewModels.Common.CustomValidationAttributes;
    using Microsoft.AspNetCore.Http;

    public class BlogPostInputModel
    {
        [Required]
        [StringLength(
            GlobalConstants.DataValidations.TitleMaxLength,
            ErrorMessage = GlobalConstants.ErrorMessages.Title,
            MinimumLength = GlobalConstants.DataValidations.TitleMinLength)]
        public string Title { get; set; }

        [Required]
        [StringLength(
            GlobalConstants.DataValidations.ContentMaxLength,
            ErrorMessage = GlobalConstants.ErrorMessages.Content,
            MinimumLength = GlobalConstants.DataValidations.ContentMinLength)]
        public string Content { get; set; }

        [Required]
        [StringLength(
            GlobalConstants.DataValidations.NameMaxLength,
            ErrorMessage = GlobalConstants.ErrorMessages.Author,
            MinimumLength = GlobalConstants.DataValidations.NameMinLength)]
        public string Author { get; set; }

        [Required]
        [DataType(DataType.Upload)]
        [ValidateImageFile(ErrorMessage = GlobalConstants.ErrorMessages.Image)]
        public IFormFile Image { get; set; }
    }
}


<|start_filename|>Tests/BeautyBooking.Services.Data.Tests/UseInMemoryDatabase/AppointmentsServiceTests.cs<|end_filename|>
﻿namespace BeautyBooking.Services.Data.Tests.UseInMemoryDatabase
{
    using System;
    using System.Linq;
    using System.Threading.Tasks;

    using BeautyBooking.Data.Models;
    using BeautyBooking.Services.Data.Appointments;
    using Microsoft.EntityFrameworkCore;
    using Microsoft.Extensions.DependencyInjection;
    using Xunit;

    public class AppointmentsServiceTests : BaseServiceTests
    {
        private IAppointmentsService Service => this.ServiceProvider.GetRequiredService<IAppointmentsService>();

        /*
        TODO: Task<T> GetByIdAsync<T>(string id);

        TODO: Task<IEnumerable<T>> GetAllAsync<T>();

        TODO: Task<IEnumerable<T>> GetAllBySalonAsync<T>(string salonId);

        TODO: Task<IEnumerable<T>> GetUpcomingByUserAsync<T>(string userId);

        TODO: Task<IEnumerable<T>> GetPastByUserAsync<T>(string userId);
         */

        [Fact]
        public async Task AddAsyncShouldAddCorrectly()
        {
            var newGuidId = Guid.NewGuid().ToString();
            await this.CreateAppointmentAsync(newGuidId);

            var dateTime = DateTime.UtcNow.AddDays(5);
            var userId = Guid.NewGuid().ToString();
            var salonId = Guid.NewGuid().ToString();
            var serviceId = 1;

            await this.Service.AddAsync(userId, salonId, serviceId, dateTime);

            var appointmentsCount = await this.DbContext.Appointments.CountAsync();
            Assert.Equal(2, appointmentsCount);
        }

        [Fact]
        public async Task DeleteAsyncShouldDeleteCorrectly()
        {
            var newGuidId = Guid.NewGuid().ToString();

            var appointment = await this.CreateAppointmentAsync(newGuidId);

            await this.Service.DeleteAsync(appointment.Id);

            var appointmentsCount = this.DbContext.Appointments.Where(x => !x.IsDeleted).ToArray().Count();
            var deletedAppointment = await this.DbContext.Appointments.FirstOrDefaultAsync(x => x.Id == appointment.Id);
            Assert.Equal(0, appointmentsCount);
            Assert.Null(deletedAppointment);
        }

        [Fact]
        public async Task ConfirmAsyncShouldWorkCorrectly()
        {
            var newGuidId = Guid.NewGuid().ToString();
            var appointment = await this.CreateAppointmentAsync(newGuidId);

            await this.Service.ConfirmAsync(newGuidId);
            var result = await this.DbContext.Appointments.Where(x => x.Id == newGuidId).Select(x => x.Confirmed).FirstOrDefaultAsync();

            var appointmentsCount = await this.DbContext.Appointments.CountAsync();
            Assert.True(result);
        }

        [Fact]
        public async Task DeclineAsyncShouldWorkCorrectly()
        {
            var newGuidId = Guid.NewGuid().ToString();
            var appointment = await this.CreateAppointmentAsync(newGuidId);

            await this.Service.DeclineAsync(newGuidId);
            var result = await this.DbContext.Appointments.Where(x => x.Id == newGuidId).Select(x => x.Confirmed).FirstOrDefaultAsync();

            var appointmentsCount = await this.DbContext.Appointments.CountAsync();
            Assert.True(!result);
        }

        [Fact]
        public async Task RateAppointmentShouldWorkCorrectly()
        {
            var newGuidId = Guid.NewGuid().ToString();
            var appointment = await this.CreateAppointmentAsync(newGuidId);

            await this.Service.RateAppointmentAsync(newGuidId);
            var result = await this.DbContext.Appointments.Where(x => x.Id == newGuidId).Select(x => x.IsSalonRatedByTheUser).FirstOrDefaultAsync();

            var appointmentsCount = await this.DbContext.Appointments.CountAsync();
            Assert.True(result);
        }

        private async Task<Appointment> CreateAppointmentAsync(string newGuidId)
        {
            var appointment = new Appointment
            {
                Id = newGuidId,
                DateTime = DateTime.UtcNow.AddDays(5),
                UserId = Guid.NewGuid().ToString(),
                SalonId = Guid.NewGuid().ToString(),
                ServiceId = 1,
            };

            await this.DbContext.Appointments.AddAsync(appointment);
            await this.DbContext.SaveChangesAsync();
            this.DbContext.Entry<Appointment>(appointment).State = EntityState.Detached;
            return appointment;
        }
    }
}


<|start_filename|>Services/BeautyBooking.Services.Data/BlogPosts/BlogPostsService.cs<|end_filename|>
﻿namespace BeautyBooking.Services.Data.BlogPosts
{
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;

    using BeautyBooking.Data.Common.Repositories;
    using BeautyBooking.Data.Models;
    using BeautyBooking.Services.Mapping;
    using BeautyBooking.Web.ViewModels.BlogPosts;
    using Microsoft.EntityFrameworkCore;

    public class BlogPostsService : IBlogPostsService
    {
        private readonly IDeletableEntityRepository<BlogPost> blogPostsRepository;

        public BlogPostsService(IDeletableEntityRepository<BlogPost> blogPostsRepository)
        {
            this.blogPostsRepository = blogPostsRepository;
        }

        public async Task<IEnumerable<T>> GetAllAsync<T>(int? count = null)
        {
            IQueryable<BlogPost> query =
                this.blogPostsRepository
                .All()
                .OrderByDescending(x => x.CreatedOn);
            if (count.HasValue)
            {
                query = query.Take(count.Value);
            }

            return await query.To<T>().ToListAsync();
        }

        public async Task<IEnumerable<T>> GetAllWithPagingAsync<T>(
            int? sortId,
            int pageSize,
            int pageIndex)
        {
            IQueryable<BlogPost> query =
                this.blogPostsRepository
                .AllAsNoTracking()
                .OrderByDescending(x => x.CreatedOn);

            if (sortId != null)
            {
                query = query
                    .Where(x => x.Id == sortId);
            }

            return await query
                .Skip((pageIndex - 1) * pageSize)
                .Take(pageSize).To<T>().ToListAsync();
        }

        public async Task<int> GetCountForPaginationAsync()
        {
            return await this.blogPostsRepository
                .AllAsNoTracking()
                .CountAsync();

            // return await query.CountAsync();
        }

        public async Task<T> GetByIdAsync<T>(int id)
        {
            var blogPost =
                await this.blogPostsRepository
                .All()
                .Where(x => x.Id == id)
                .To<T>().FirstOrDefaultAsync();
            return blogPost;
        }

        public async Task AddAsync(string title, string content, string author, string imageUrl)
        {
            await this.blogPostsRepository.AddAsync(new BlogPost
            {
                Title = title,
                Content = content,
                Author = author,
                ImageUrl = imageUrl,
            });
            await this.blogPostsRepository.SaveChangesAsync();
        }

        public async Task DeleteAsync(int id)
        {
            var blogPost =
                await this.blogPostsRepository
                .AllAsNoTracking()
                .Where(x => x.Id == id)
                .FirstOrDefaultAsync();
            this.blogPostsRepository.Delete(blogPost);
            await this.blogPostsRepository.SaveChangesAsync();
        }
    }
}


<|start_filename|>Tests/BeautyBooking.Services.Data.Tests/UseInMemoryDatabase/SalonsServiceTests.cs<|end_filename|>
﻿namespace BeautyBooking.Services.Data.Tests.UseInMemoryDatabase
{
    using System;
    using System.Linq;
    using System.Threading.Tasks;

    using BeautyBooking.Data.Models;
    using BeautyBooking.Services.Data.Salons;
    using Microsoft.EntityFrameworkCore;
    using Microsoft.Extensions.DependencyInjection;
    using Xunit;

    public class SalonsServiceTests : BaseServiceTests
    {
        private ISalonsService Service => this.ServiceProvider.GetRequiredService<ISalonsService>();

        /*
        TODO: Task<IEnumerable<T>> GetAllAsync<T>();

        TODO: Task<IEnumerable<T>> GetAllWithSortingFilteringAndPagingAsync<T>(
            string searchString,
            int? sortId,
            int pageSize,
            int pageIndex);

        TODO: Task<T> GetByIdAsync<T>(string id);
         */

        [Fact]
        public async Task GetCountForPaginationAsyncShouldReturnCorrectCount()
        {
            await this.CreateSalonAsync(Guid.NewGuid().ToString());
            await this.CreateSalonAsync(Guid.NewGuid().ToString());
            await this.CreateSalonAsync(Guid.NewGuid().ToString());

            var actual = await this.Service.GetCountForPaginationAsync(" ", 0);
            Assert.Equal(0, actual);
        }

        [Fact]
        public async Task GetAllIdsByCategoryAsyncShouldReturnCorrectCount()
        {
            var salon1 = new Salon
            {
                Id = Guid.NewGuid().ToString(),
                Name = new NLipsum.Core.Sentence().ToString(),
                CategoryId = 5,
                CityId = 1,
                Address = new NLipsum.Core.Sentence().ToString(),
                ImageUrl = new NLipsum.Core.Word().ToString(),
                Rating = 4,
                RatersCount = 1,
            };
            var salon2 = new Salon
            {
                Id = Guid.NewGuid().ToString(),
                Name = new NLipsum.Core.Sentence().ToString(),
                CategoryId = 5,
                CityId = 1,
                Address = new NLipsum.Core.Sentence().ToString(),
                ImageUrl = new NLipsum.Core.Word().ToString(),
                Rating = 4,
                RatersCount = 1,
            };
            var salon3 = new Salon
            {
                Id = Guid.NewGuid().ToString(),
                Name = new NLipsum.Core.Sentence().ToString(),
                CategoryId = 5,
                CityId = 1,
                Address = new NLipsum.Core.Sentence().ToString(),
                ImageUrl = new NLipsum.Core.Word().ToString(),
                Rating = 4,
                RatersCount = 1,
            };

            await this.DbContext.Salons.AddRangeAsync(salon1, salon2, salon3);
            await this.DbContext.SaveChangesAsync();

            var expected = this.DbContext.Salons.Where(x => x.CategoryId == 5).Count();
            var actual = await this.Service.GetAllIdsByCategoryAsync(5);
            var actualCount = 0;
            foreach (var result in actual)
            {
                actualCount++;
            }

            Assert.Equal(expected, actualCount);
        }

        [Fact]
        public async Task AddAsyncShouldAddCorrectly()
        {
            var newGuidId = Guid.NewGuid().ToString();
            await this.CreateSalonAsync(newGuidId);

            var name = new NLipsum.Core.Sentence().ToString();
            var categoryId = 1;
            var cityId = 1;
            var address = new NLipsum.Core.Sentence().ToString();
            var imageUrl = new NLipsum.Core.Word().ToString();

            await this.Service.AddAsync(name, categoryId, cityId, address, imageUrl);

            var salonsCount = await this.DbContext.Salons.CountAsync();
            Assert.Equal(2, salonsCount);
        }

        [Fact]
        public async Task DeleteAsyncShouldDeleteCorrectly()
        {
            var newGuidId = Guid.NewGuid().ToString();

            var salon = await this.CreateSalonAsync(newGuidId);

            await this.Service.DeleteAsync(salon.Id);

            var salonsCount = this.DbContext.Salons.Where(x => !x.IsDeleted).ToArray().Count();
            var deletedSalon = await this.DbContext.Salons.FirstOrDefaultAsync(x => x.Id == salon.Id);
            Assert.Equal(0, salonsCount);
            Assert.Null(deletedSalon);
        }

        [Fact]
        public async Task RateSalonAsyncShouldGiveCorrectRating()
        {
            var newGuidId = Guid.NewGuid().ToString();
            var salon = await this.CreateSalonAsync(newGuidId);

            var rateValue = 4;
            await this.Service.RateSalonAsync(newGuidId, rateValue);

            var expected = rateValue;
            var actual = salon.Rating;

            Assert.Equal(expected, actual);
        }

        private async Task<Salon> CreateSalonAsync(string newGuidId)
        {
            var salon = new Salon
            {
                Id = newGuidId,
                Name = new NLipsum.Core.Sentence().ToString(),
                CategoryId = 1,
                CityId = 1,
                Address = new NLipsum.Core.Sentence().ToString(),
                ImageUrl = new NLipsum.Core.Word().ToString(),
                Rating = 4,
                RatersCount = 1,
            };

            await this.DbContext.Salons.AddAsync(salon);
            await this.DbContext.SaveChangesAsync();
            this.DbContext.Entry<Salon>(salon).State = EntityState.Detached;
            return salon;
        }
    }
}


<|start_filename|>Web/BeautyBooking.Web/Views/Home/Index.cshtml<|end_filename|>
﻿@model BeautyBooking.Web.ViewModels.Home.IndexViewModel
@{
    this.ViewData["Title"] = "Home Page";
}

<hr class="bg-dark mx-4" style="height: 6px;" />

<div class="departments">
    <div class="container">
        <div class="row">
            <div class="col text-center">
                <div class="section_title">Beauty Services</div>
                <div class="section_subtitle">to choose from</div>
            </div>
        </div>
        <div class="row dept_row">
            <div class="col">
                <div class="dept_slider_container_outer">
                    <div class="dept_slider_container">

                        <!-- Slider -->
                        <div class="owl-carousel owl-theme dept_slider">

                            @foreach (var category in Model.Categories)
                            {
                                <!-- Slide -->
                                <div class="owl-item dept_item">
                                    <div class="dept_image"><img src="@category.ImageUrl" alt=""></div>
                                    <div class="dept_content">
                                        <div class="dept_title">@category.Name</div>
                                        <div class="dept_link"><a>@category.Description</a></div>
                                    </div>
                                </div>
                            }

                        </div>
                    </div>
                    <!-- Dept Slider Nav -->
                    <div class="dept_slider_nav"><i class="fa fa-chevron-right" aria-hidden="true"></i></div>
                </div>
            </div>
        </div>
        <div class="row">
            <div class="col">
                <div class="button services_button ml-auto mr-auto">
                    <a asp-area="" asp-controller="Categories" asp-action="Index"><span>see all</span><span>see all</span></a>
                </div>
            </div>
        </div>
    </div>
</div>

<hr class="bg-dark mx-4" style="height: 6px;" />

<!-- FAQ & News -->

<div class="stuff">
    <div class="container">
        <div class="row">

            <!-- FAQ -->
            <div class="col-lg-7">
                <div class="faq">
                    <div class="faq_title">Faq & Stuff</div>
                    <div class="elements_accordions">
                        <div class="accordions">

                            <div class="accordion_container">
                                <div class="accordion d-flex flex-row align-items-center active"><div>What is BeautyBooking?</div></div>
                                <div class="accordion_panel">
                                    <div>
                                        <p>
                                            BeautyBooking is an online bookings platform for beauty services.
                                            Haircut, wax, manicure - or whichever treatment you're after -
                                            here you can book your appointment.

                                            Our mission is to create the perfect hair and beauty experience.
                                            We want to make booking beauty, styling and wellness appointments
                                            simple, effortless and fast.
                                        </p>
                                    </div>
                                </div>
                            </div>

                            <div class="accordion_container">
                                <div class="accordion d-flex flex-row align-items-center"><div>How to use the booking system?</div></div>
                                <div class="accordion_panel">
                                    <div>
                                        <p>
                                            You just need to Register and Login into your account.
                                            Then you can book your appointments in 3 easy steps:
                                            find a salon, choose a beauty service, pick date and time.
                                        </p>
                                    </div>
                                </div>
                            </div>

                            <div class="accordion_container">
                                <div class="accordion d-flex flex-row align-items-center"><div>How to register a salon?</div></div>
                                <div class="accordion_panel">
                                    <div>
                                        <p>
                                            Interested in listing your salon in BeautyBooking? Good call. Stay Tuned!
                                            <br>COMING SOON: "Register a Salon" option for all users.
                                            <br>With BeautyBooking managing your schedule would be easy as never before.
                                        </p>
                                    </div>
                                </div>
                            </div>

                        </div>
                    </div>
                </div>
            </div>

            <!-- Latest News -->
            <div class="col-lg-5">
                <div class="news-grey">
                    <div class="news_title">Latest Blog Posts</div>
                    <div class="news_container">
                        <div>
                            @await Component.InvokeAsync("LatestBlogPosts", 4)
                        </div>
                    </div>
                </div>
            </div>

        </div>
    </div>
</div>

<hr class="bg-dark mx-4" style="height: 6px;" />


<|start_filename|>Web/BeautyBooking.Web/Views/Shared/_HeaderPartial.cshtml<|end_filename|>
﻿<header class="header" id="header">
    <div>
        <div class="header_top">
            <div class="container">
                <div class="row">
                    <div class="col">
                        <div class="header_top_content d-flex flex-row align-items-center justify-content-start">
                            <div class="logo">
                                <a asp-area="" asp-controller="Home" asp-action="Index"><span>Beauty</span>Booking</a>
                            </div>
                            <div class="header_top_extra d-flex flex-row align-items-center justify-content-start ml-auto">
                                <div class="header_top_nav">
                                    <ul class="d-flex flex-row align-items-center justify-content-start">
                                        <partial name="_LoginPartial" />
                                    </ul>
                                </div>
                            </div>
                            <div class="hamburger ml-auto"><i class="fa fa-bars" aria-hidden="true"></i></div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <div class="header_nav" id="header_nav_pin">
            <div class="header_nav_inner">
                <div class="header_nav_container">
                    <div class="container">
                        <div class="row">
                            <div class="col">
                                <div class="header_nav_content d-flex flex-row align-items-center justify-content-start">
                                    <nav class="main_nav">
                                        <ul class="d-flex flex-row align-items-center justify-content-start">
                                            <partial name="_MenuItemsPartial" />
                                        </ul>
                                    </nav>
                                    @if (this.ViewData["Title"].ToString() == "Beauty Salons")
                                    {
                                        <partial name="_SearchBarPartial" />
                                    }
                                    <!--
                                    <div class="search_content d-flex flex-row align-items-center justify-content-end ml-auto">
                                        <form action="#" id="search_container_form" class="search_container_form">
                                            <input type="text" class="search_container_input" placeholder="Search" required="required">
                                            <button class="search_container_button"><i class="fa fa-search" aria-hidden="true"></i></button>
                                        </form>
                                    </div>
                                    -->
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</header>


<|start_filename|>Web/BeautyBooking.Web/Views/Shared/_MenuItemsPartial.cshtml<|end_filename|>
﻿@using BeautyBooking.Common
@using BeautyBooking.Data.Models
@using Microsoft.AspNetCore.Identity
@inject SignInManager<ApplicationUser> SignInManager
@inject UserManager<ApplicationUser> UserManager

<li class="menu_item"><a asp-area="" asp-controller="Home" asp-action="Index">Home</a></li>
<li class="menu_item"><a asp-area="" asp-controller="Categories" asp-action="Index">Categories</a></li>
<li class="menu_item"><a asp-area="" asp-controller="Salons" asp-action="Index">Salons</a></li>
<li class="menu_item"><a asp-area="" asp-controller="BlogPosts" asp-action="Index">Blog</a></li>
<li class="menu_item">
    <a asp-area="" asp-controller="Appointments" asp-action="Index"><i class="fa fa-calendar" aria-hidden="true"></i> Appointments</a>
</li>

@if (this.SignInManager.IsSignedIn(this.User) && this.User.IsInRole(GlobalConstants.SalonManagerRoleName))
{
    <li class="menu_item">
        <a asp-area="Manager" asp-controller="Dashboard" asp-action="Index"><i class="fa fa-tasks" aria-hidden="true"></i> Salon Manager</a>
    </li>
}


<|start_filename|>Tests/BeautyBooking.Services.Data.Tests/UseInMemoryDatabase/ServicesServiceTests.cs<|end_filename|>
﻿namespace BeautyBooking.Services.Data.Tests.UseInMemoryDatabase
{
    using System.Linq;
    using System.Threading.Tasks;

    using BeautyBooking.Data.Models;
    using BeautyBooking.Services.Data.Services;
    using Microsoft.EntityFrameworkCore;
    using Microsoft.Extensions.DependencyInjection;
    using Xunit;

    public class ServicesServiceTests : BaseServiceTests
    {
        private IServicesService Service => this.ServiceProvider.GetRequiredService<IServicesService>();

        [Fact]
        public async Task GetAllIdsByCategoryAsyncShouldReturnCorrectCount()
        {
            var service1 = new Service
            {
                Name = new NLipsum.Core.Sentence().ToString(),
                Description = new NLipsum.Core.Paragraph().ToString(),
                CategoryId = 10,
            };
            var service2 = new Service
            {
                Name = new NLipsum.Core.Sentence().ToString(),
                Description = new NLipsum.Core.Paragraph().ToString(),
                CategoryId = 10,
            };
            var service3 = new Service
            {
                Name = new NLipsum.Core.Sentence().ToString(),
                Description = new NLipsum.Core.Paragraph().ToString(),
                CategoryId = 10,
            };

            await this.DbContext.Services.AddRangeAsync(service1, service2, service3);
            await this.DbContext.SaveChangesAsync();

            var expected = this.DbContext.Services.Where(x => x.CategoryId == 10).Count();
            var actual = await this.Service.GetAllIdsByCategoryAsync(10);
            var actualCount = 0;
            foreach (var result in actual)
            {
                actualCount++;
            }

            Assert.Equal(expected, actualCount);
        }

        [Fact]
        public async Task AddAsyncShouldAddCorrectly()
        {
            await this.CreateServiceAsync();

            var name = new NLipsum.Core.Sentence().ToString();
            var categoryId = 1;
            var description = new NLipsum.Core.Paragraph().ToString();

            await this.Service.AddAsync(name, categoryId, description);

            var servicesCount = await this.DbContext.Services.CountAsync();
            Assert.Equal(2, servicesCount);
        }

        [Fact]
        public async Task DeleteAsyncShouldDeleteCorrectly()
        {
            var service = await this.CreateServiceAsync();

            await this.Service.DeleteAsync(service.Id);

            var servicesCount = this.DbContext.Services.Where(x => !x.IsDeleted).ToArray().Count();
            var deletedService = await this.DbContext.Services.FirstOrDefaultAsync(x => x.Id == service.Id);
            Assert.Equal(0, servicesCount);
            Assert.Null(deletedService);
        }

        private async Task<Service> CreateServiceAsync()
        {
            var service = new Service
            {
                Name = new NLipsum.Core.Sentence().ToString(),
                Description = new NLipsum.Core.Paragraph().ToString(),
                CategoryId = 1,
            };

            await this.DbContext.Services.AddAsync(service);
            await this.DbContext.SaveChangesAsync();
            this.DbContext.Entry<Service>(service).State = EntityState.Detached;
            return service;
        }
    }
}


<|start_filename|>Tests/BeautyBooking.Services.Data.Tests/UseInMemoryDatabase/BlogPostsServiceTests.cs<|end_filename|>
﻿namespace BeautyBooking.Services.Data.Tests.UseInMemoryDatabase
{
    using System.Linq;
    using System.Threading.Tasks;

    using BeautyBooking.Data.Models;
    using BeautyBooking.Services.Data.BlogPosts;
    using Microsoft.EntityFrameworkCore;
    using Microsoft.Extensions.DependencyInjection;
    using Xunit;

    public class BlogPostsServiceTests : BaseServiceTests
    {
        private IBlogPostsService Service => this.ServiceProvider.GetRequiredService<IBlogPostsService>();

        /*
        TODO: Task<IEnumerable<T>> GetAllAsync<T>(int? count = null);

        TODO: Task<IEnumerable<T>> GetAllWithPagingAsync<T>(
            int? sortId,
            int pageSize,
            int pageIndex);

        TODO: Task<T> GetByIdAsync<T>(int id);
         */

        [Fact]
        public async Task GetCountForPaginationAsyncShouldReturnCorrectCount()
        {
            await this.CreateBlogPostAsync();
            await this.CreateBlogPostAsync();
            await this.CreateBlogPostAsync();

            var expected = this.DbContext.BlogPosts.Where(x => !x.IsDeleted).ToArray().Count();
            var actual = await this.Service.GetCountForPaginationAsync();
            Assert.Equal(expected, actual);
        }

        [Fact]
        public async Task AddAsyncShouldAddCorrectly()
        {
            await this.CreateBlogPostAsync();

            var title = new NLipsum.Core.Sentence().ToString();
            var content = new NLipsum.Core.Paragraph().ToString();
            var author = new NLipsum.Core.Word().ToString();
            var imageUrl = new NLipsum.Core.Word().ToString();

            await this.Service.AddAsync(title, content, author, imageUrl);

            var blogPostsCount = await this.DbContext.BlogPosts.CountAsync();
            Assert.Equal(2, blogPostsCount);
        }

        [Fact]
        public async Task DeleteAsyncShouldDeleteCorrectly()
        {
            var blogPost = await this.CreateBlogPostAsync();

            await this.Service.DeleteAsync(blogPost.Id);

            var blogPostsCount = this.DbContext.BlogPosts.Where(x => !x.IsDeleted).ToArray().Count();
            var deletedBlogPost = await this.DbContext.BlogPosts.FirstOrDefaultAsync(x => x.Id == blogPost.Id);
            Assert.Equal(0, blogPostsCount);
            Assert.Null(deletedBlogPost);
        }

        private async Task<BlogPost> CreateBlogPostAsync()
        {
            var blogPost = new BlogPost
            {
                Title = "Test Title",
                Content = new NLipsum.Core.Paragraph().ToString(),
                Author = new NLipsum.Core.Word().ToString(),
                ImageUrl = new NLipsum.Core.Word().ToString(),
            };

            await this.DbContext.BlogPosts.AddAsync(blogPost);
            await this.DbContext.SaveChangesAsync();
            this.DbContext.Entry<BlogPost>(blogPost).State = EntityState.Detached;
            return blogPost;
        }
    }
}


<|start_filename|>Web/BeautyBooking.Web/Areas/Administration/Views/Shared/_AdminMenuPartial.cshtml<|end_filename|>
﻿<div class="menu trans_500">
    <div class="menu_content d-flex flex-column align-items-center justify-content-center text-center">
        <div class="menu_close_container"><div class="menu_close"></div></div>
        <ul>
            <li class="menu_item"><a asp-area="Administration" asp-controller="Dashboard" asp-action="Index">Admin Dashboard</a></li>
            <li class="menu_item"><a asp-area="Administration" asp-controller="BlogPosts" asp-action="Index">Blog Posts</a></li>
            <li class="menu_item"><a asp-area="Administration" asp-controller="Categories" asp-action="Index">Categories</a></li>
            <li class="menu_item"><a asp-area="Administration" asp-controller="Services" asp-action="Index">Services</a></li>
            <li class="menu_item"><a asp-area="Administration" asp-controller="Cities" asp-action="Index">Cities</a></li>
            <li class="menu_item"><a asp-area="Administration" asp-controller="Salons" asp-action="Index">Salons</a></li>
            <li class="menu_item"><a asp-area="" asp-controller="Home" asp-action="Index">BACK TO HOME PAGE</a></li>
        </ul>
    </div>
</div>


<|start_filename|>Web/BeautyBooking.Web/Controllers/HomeController.cs<|end_filename|>
﻿namespace BeautyBooking.Web.Controllers
{
    using System.Diagnostics;
    using System.Threading.Tasks;

    using BeautyBooking.Common;
    using BeautyBooking.Services.Data.BlogPosts;
    using BeautyBooking.Services.Data.Categories;
    using BeautyBooking.Web.ViewModels;
    using BeautyBooking.Web.ViewModels.Home;
    using Microsoft.AspNetCore.Mvc;

    public class HomeController : BaseController
    {
        private readonly ICategoriesService categoriesService;
        private readonly IBlogPostsService blogPostsService;

        public HomeController(
            ICategoriesService categoriesService,
            IBlogPostsService blogPostsService)
        {
            this.categoriesService = categoriesService;
            this.blogPostsService = blogPostsService;
        }

        public async Task<IActionResult> Index()
        {
            var viewModel = new IndexViewModel
            {
                Categories =
                    await this.categoriesService.GetAllAsync<IndexCategoryViewModel>(
                        GlobalConstants.SeededDataCounts.Categories),
            };
            return this.View(viewModel);
        }

        public IActionResult Privacy()
        {
            return this.View();
        }

        [Route("/Home/Error/404")]
        public IActionResult Error404()
        {
            return this.View();
        }

        [Route("/Home/Error/{code:int}")]
        public IActionResult Error(int code)
        {
            // Could handle different codes here
            // or just return the default error view
            return this.View();
        }

        [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
        public IActionResult Error()
        {
            return this.View(
                new ErrorViewModel { RequestId = Activity.Current?.Id ?? this.HttpContext.TraceIdentifier });
        }
    }
}


<|start_filename|>Web/BeautyBooking.Web/Controllers/BlogPostsController.cs<|end_filename|>
﻿namespace BeautyBooking.Web.Controllers
{
    using System.Linq;
    using System.Threading.Tasks;

    using BeautyBooking.Services.Data.BlogPosts;
    using BeautyBooking.Web.ViewModels.BlogPosts;
    using BeautyBooking.Web.ViewModels.Common.Pagination;
    using Microsoft.AspNetCore.Mvc;

    public class BlogPostsController : BaseController
    {
        private readonly IBlogPostsService blogPostsService;

        public BlogPostsController(IBlogPostsService blogPostsService)
        {
            this.blogPostsService = blogPostsService;
        }

        public async Task<IActionResult> Index(
            int? sortId,
            int? pageNumber) // blogPostId
        {
            if (sortId != null)
            {
                var blogPost = await this.blogPostsService
                    .GetByIdAsync<BlogPostViewModel>(sortId.Value);
                if (blogPost == null)
                {
                    return new StatusCodeResult(404);
                }
            }

            this.ViewData["CurrentSort"] = sortId;

            int pageSize = PageSizesConstants.BlogPosts;
            var pageIndex = pageNumber ?? 1;

            var blogPosts = await this.blogPostsService
                .GetAllWithPagingAsync<BlogPostViewModel>(sortId, pageSize, pageIndex);
            var blogPostsList = blogPosts.ToList();

            var count = await this.blogPostsService.GetCountForPaginationAsync();

            var viewModel = new BlogPostsPaginatedListViewModel
            {
                BlogPosts = new PaginatedList<BlogPostViewModel>(blogPostsList, count, pageIndex, pageSize),
            };

            return this.View(viewModel);
        }
    }
}


<|start_filename|>Tests/BeautyBooking.Services.Data.Tests/UseMocking/ServicesServiceTests.cs<|end_filename|>
﻿namespace BeautyBooking.Services.Data.Tests.UseMocking
{
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;

    using BeautyBooking.Data.Common.Repositories;
    using BeautyBooking.Data.Models;
    using BeautyBooking.Services.Data.Services;
    using Moq;
    using Xunit;

    public class ServicesServiceTests
    {
        /*
        TODO: Task<IEnumerable<T>> GetAllAsync<T>();
         */

        /*
       [Fact]
       public async Task GetAllAsyncShouldReturnCorrectNumber()
       {
           var repository = new Mock<IDeletableEntityRepository<Service>>();
           repository.Setup(r => r.All()).Returns(new List<Service>
                                                       {
                                                           new Service(),
                                                           new Service(),
                                                           new Service(),
                                                       }.AsQueryable());
           var service = new ServicesService(repository.Object);

           var result = await service.GetAllAsync<Service>();
           var resultCount = 0;
           foreach (var item in result)
           {
               resultCount++;
           }

           Assert.Equal(3, resultCount);
           repository.Verify(x => x.All(), Times.Once);
        }

            * Message:
   System.NullReferenceException : Object reference not set to an instance of an object.
 Stack Trace:
   QueryableMappingExtensions.To[TDestination](IQueryable source, Expression`1[] membersToExpand) line 20
   ServicesService.GetAllAsync[T]() line 23
   ServicesServiceTests.GetAllAsyncShouldReturnCorrectNumber() line 37
   --- End of stack trace from previous location where exception was thrown ---
*/
    }
}


<|start_filename|>Web/BeautyBooking.Web/Controllers/AppointmentsController.cs<|end_filename|>
﻿namespace BeautyBooking.Web.Controllers
{
    using System;
    using System.Threading.Tasks;

    using BeautyBooking.Data.Models;
    using BeautyBooking.Services.Data.Appointments;
    using BeautyBooking.Services.Data.Salons;
    using BeautyBooking.Services.Data.SalonServicesServices;
    using BeautyBooking.Services.DateTimeParser;
    using BeautyBooking.Web.ViewModels.Appointments;
    using BeautyBooking.Web.ViewModels.SalonServices;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Identity;
    using Microsoft.AspNetCore.Mvc;

    [Authorize]
    public class AppointmentsController : BaseController
    {
        private readonly UserManager<ApplicationUser> userManager;
        private readonly IDateTimeParserService dateTimeParserService;
        private readonly ISalonsService salonsService;
        private readonly IAppointmentsService appointmentsService;
        private readonly ISalonServicesService salonServicesService;

        public AppointmentsController(
            UserManager<ApplicationUser> userManager,
            IAppointmentsService appointmentsService,
            ISalonServicesService salonServicesService,
            IDateTimeParserService dateTimeParserService,
            ISalonsService salonsService)
        {
            this.userManager = userManager;
            this.appointmentsService = appointmentsService;
            this.salonServicesService = salonServicesService;
            this.dateTimeParserService = dateTimeParserService;
            this.salonsService = salonsService;
        }

        public async Task<IActionResult> Index()
        {
            var user = await this.userManager.GetUserAsync(this.HttpContext.User);
            var userId = await this.userManager.GetUserIdAsync(user);

            var viewModel = new AppointmentsListViewModel
            {
                Appointments =
                    await this.appointmentsService.GetUpcomingByUserAsync<AppointmentViewModel>(userId),
            };
            return this.View(viewModel);
        }

        public async Task<IActionResult> MakeAnAppointment(string salonId, int serviceId)
        {
            var salonService = await this.salonServicesService.GetByIdAsync<SalonServiceSimpleViewModel>(salonId, serviceId);
            if (salonService == null || !salonService.Available)
            {
                return this.View("UnavailableService");
            }

            var viewModel = new AppointmentInputModel
            {
                SalonId = salonId,
                ServiceId = serviceId,
            };
            return this.View(viewModel);
        }

        [HttpPost]
        public async Task<IActionResult> MakeAnAppointment(AppointmentInputModel input)
        {
            if (!this.ModelState.IsValid)
            {
                return this.RedirectToAction("MakeAnAppointment", new { input.SalonId, input.ServiceId });
            }

            DateTime dateTime;
            try
            {
                dateTime = this.dateTimeParserService.ConvertStrings(input.Date, input.Time);
            }
            catch (System.Exception)
            {
                return this.RedirectToAction("MakeAnAppointment", new { input.SalonId, input.ServiceId });
            }

            var user = await this.userManager.GetUserAsync(this.HttpContext.User);
            var userId = await this.userManager.GetUserIdAsync(user);

            await this.appointmentsService.AddAsync(userId, input.SalonId, input.ServiceId, dateTime);

            return this.RedirectToAction("Index");
        }

        [HttpGet]
        public async Task<IActionResult> CancelAppointment(string id)
        {
            var viewModel = await this.appointmentsService.GetByIdAsync<AppointmentViewModel>(id);

            if (viewModel == null)
            {
                return new StatusCodeResult(404);
            }

            return this.View(viewModel);
        }

        [HttpPost]
        public async Task<IActionResult> DeleteAppointment(string id)
        {
            await this.appointmentsService.DeleteAsync(id);

            return this.RedirectToAction("Index");
        }

        public async Task<IActionResult> RatePastAppointment(string id)
        {
            var viewModel = await this.appointmentsService.GetByIdAsync<AppointmentRatingViewModel>(id);

            return this.View(viewModel);
        }

        [HttpPost]
        public async Task<IActionResult> RateSalon(AppointmentRatingViewModel rating)
        {
            if (!this.ModelState.IsValid)
            {
                return this.RedirectToAction("RatePastAppointment", new { id = rating.Id });
            }

            if (rating.IsSalonRatedByTheUser == true)
            {
                return this.RedirectToAction("RatePastAppointment", new { id = rating.Id });
            }

            await this.appointmentsService.RateAppointmentAsync(rating.Id);
            await this.salonsService.RateSalonAsync(rating.SalonId, rating.RateValue);

            return this.RedirectToAction("Details", "Salons", new { id = rating.SalonId });
        }
    }
}


<|start_filename|>Web/BeautyBooking.Web/Views/Shared/Components/SalonServiceDetails/Default.cshtml<|end_filename|>
﻿@model BeautyBooking.Web.ViewModels.SalonServices.SalonServiceDetailsViewModel
@{
    ViewData["Title"] = "Default";
}

<div class="form-group row">
    <label class="col-sm-2 col-form-label">Salon</label>
    <div class="col-sm-10">
        <div class="form-control">@Model.SalonName</div>
    </div>
</div>
<div class="form-group row">
    <label class="col-sm-2 col-form-label">Address</label>
    <div class="col-sm-10">
        <div class="form-control">@Model.SalonCityName, @Model.SalonAddress</div>
    </div>
</div>
<div class="form-group row">
    <label class="col-sm-2 col-form-label">Service</label>
    <div class="col-sm-10">
        <div class="form-control">@Model.ServiceName</div>
    </div>
</div>


<|start_filename|>Web/BeautyBooking.Web.Infrastructure/ViewComponents/LatestBlogPostsViewComponent.cs<|end_filename|>
﻿namespace BeautyBooking.Web.Infrastructure.ViewComponents
{
    using System.Threading.Tasks;

    using BeautyBooking.Services.Data.BlogPosts;
    using BeautyBooking.Web.ViewModels.BlogPosts;
    using Microsoft.AspNetCore.Mvc;

    public class LatestBlogPostsViewComponent : ViewComponent
    {
        private readonly IBlogPostsService blogPostsService;

        public LatestBlogPostsViewComponent(IBlogPostsService blogPostsService)
        {
            this.blogPostsService = blogPostsService;
        }

        public async Task<IViewComponentResult> InvokeAsync(int? count)
        {
            var viewModel = new BlogPostsListViewModel
            {
                BlogPosts = await this.blogPostsService.GetAllAsync<BlogPostViewModel>(count),
            };

            return this.View(viewModel);
        }
    }
}


<|start_filename|>Tests/BeautyBooking.Services.Data.Tests/UseInMemoryDatabase/BaseServiceTests.cs<|end_filename|>
﻿namespace BeautyBooking.Services.Data.Tests.UseInMemoryDatabase
{
    using System;

    using BeautyBooking.Data;
    using BeautyBooking.Data.Common.Repositories;
    using BeautyBooking.Data.Repositories;
    using BeautyBooking.Services.Data.Appointments;
    using BeautyBooking.Services.Data.BlogPosts;
    using BeautyBooking.Services.Data.Categories;
    using BeautyBooking.Services.Data.Cities;
    using BeautyBooking.Services.Data.Salons;
    using BeautyBooking.Services.Data.SalonServicesServices;
    using BeautyBooking.Services.Data.Services;
    using Microsoft.EntityFrameworkCore;
    using Microsoft.Extensions.DependencyInjection;

    public abstract class BaseServiceTests : IDisposable
    {
        protected BaseServiceTests()
        {
            var services = this.SetServices();

            this.ServiceProvider = services.BuildServiceProvider();
            this.DbContext = this.ServiceProvider.GetRequiredService<ApplicationDbContext>();
        }

        protected IServiceProvider ServiceProvider { get; set; }

        protected ApplicationDbContext DbContext { get; set; }

        public void Dispose()
        {
            this.DbContext.Database.EnsureDeleted();
            this.SetServices();
        }

        private ServiceCollection SetServices()
        {
            var services = new ServiceCollection();

            services.AddDbContext<ApplicationDbContext>(
                options => options.UseInMemoryDatabase(Guid.NewGuid().ToString()));

            // Data repositories
            services.AddScoped(typeof(IDeletableEntityRepository<>), typeof(EfDeletableEntityRepository<>));
            services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>));

            // Application services
            services.AddTransient<IBlogPostsService, BlogPostsService>();
            services.AddTransient<ICategoriesService, CategoriesService>();
            services.AddTransient<IServicesService, ServicesService>();
            services.AddTransient<ICitiesService, CitiesService>();
            services.AddTransient<ISalonsService, SalonsService>();
            services.AddTransient<ISalonServicesService, SalonServicesService>();
            services.AddTransient<IAppointmentsService, AppointmentsService>();

            return services;
        }
    }
}


<|start_filename|>Web/BeautyBooking.Web/Views/Salons/Index.cshtml<|end_filename|>
﻿@model BeautyBooking.Web.ViewModels.Salons.SalonsPaginatedListViewModel
@{
    this.ViewData["Title"] = "Beauty Salons";
}

<div>
    @await Component.InvokeAsync("CategoriesSimpleList")
</div>
<div class="text-center text-dark pb-5">
    <h2><strong>@this.ViewData["CategoryName"]?.ToString()</strong></h2>
</div>

@if (!Model.Salons.Any())
{
    <h2 class="ml-5">No results!</h2>
}

<div class="row row-eq-height">
    @foreach (var salon in Model.Salons)
    {
        <div class="col-xl-3 col-md-6">
            <div class="doctor">
                <div class="doctor_image"><img src="@salon.ImageUrl" alt=""></div>
                <div class="doctor_content">
                    <div class="doctor_name">
                        <a asp-area="" asp-controller="Salons" asp-action="Details" asp-route-id="@salon.Id">@salon.Name</a>
                    </div>
                    <div class="doctor_title"><strong>@salon.CategoryName</strong></div>
                    <div class="doctor_title">@salon.CityName, @salon.Address</div>
                    <div class="doctor_title ml-2">
                        <div class="button button_1 elements_button mt-2">
                            <a asp-area="" asp-controller="Salons" asp-action="Details" asp-route-id="@salon.Id">
                                <span>See Services</span>
                                <span>See Services</span>
                            </a>
                        </div>
                    </div>
                    <div class="doctor_link">
                        <a asp-area="" asp-controller="Salons" asp-action="Details" asp-route-id="@salon.Id">+</a>
                    </div>
                </div>
            </div>
        </div>
    }
</div>

@{
    var prevDisabled = !Model.Salons.HasPreviousPage ? "disabled" : "";
    var nextDisabled = !Model.Salons.HasNextPage ? "disabled" : "";
}

<div class="row ml-5">
    <div class="m-5">
        <a asp-action="Index"
           asp-route-sortId="@ViewData["CurrentSort"]"
           asp-route-pageNumber="@(Model.Salons.PageIndex - 1)"
           asp-route-currentFilter="@ViewData["CurrentFilter"]"
           style="color: #BA55D3" class="btn btn-outline-secondary btn-lg @prevDisabled">
            &#x2190; Previous Page
        </a>
    </div>
    <div class="m-5">
        <a asp-action="Index"
           asp-route-sortId="@ViewData["CurrentSort"]"
           asp-route-pageNumber="@(Model.Salons.PageIndex + 1)"
           asp-route-currentFilter="@ViewData["CurrentFilter"]"
           style="color: #BA55D3" class="btn btn-outline-secondary btn-lg @nextDisabled">
            Next Page &#x2192;
        </a>
    </div>
</div>


<|start_filename|>Web/BeautyBooking.Web/Areas/Administration/Views/Shared/_AdminSidebarPartial.cshtml<|end_filename|>
﻿<!-- Sidebar -->
<div class="bg-light border border-secondary" id="sidebar-wrapper">
    <div class="sidebar-heading"><strong><u>Admin</u></strong></div>
    <div class="list-group list-group-flush">

        <a asp-area="Administration" asp-controller="Dashboard" asp-action="Index"
           class="list-group-item list-group-item-action bg-light">Dashboard</a>

        <a asp-area="Administration" asp-controller="BlogPosts" asp-action="Index"
           class="list-group-item list-group-item-action bg-light">Blog Posts</a>

        <a asp-area="Administration" asp-controller="Categories" asp-action="Index"
           class="list-group-item list-group-item-action bg-light">Categories</a>

        <a asp-area="Administration" asp-controller="Services" asp-action="Index"
           class="list-group-item list-group-item-action bg-light">Services</a>

        <a asp-area="Administration" asp-controller="Cities" asp-action="Index"
           class="list-group-item list-group-item-action bg-light">Cities</a>

        <a asp-area="Administration" asp-controller="Salons" asp-action="Index"
           class="list-group-item list-group-item-action bg-light">Salons</a>

        <a asp-area="Administration" asp-controller="Appointments" asp-action="Index"
           class="list-group-item list-group-item-action bg-light">Appointments</a>

    </div>
</div>
<!-- /#sidebar-wrapper -->


<|start_filename|>Web/BeautyBooking.Web/Areas/Manager/Views/Dashboard/Index.cshtml<|end_filename|>
﻿@model BeautyBooking.Web.ViewModels.Salons.SalonsListViewModel
@{
    this.ViewData["Title"] = "Salon Manager Dashboard";
}

<h3>Welcome to Salon Manager Dashboard!</h3>
<p>Here are the salons you manage:</p>

<div>
    @await Component.InvokeAsync("SalonsSimpleList")
</div>
