repository migration

This commit is contained in:
2025-05-20 11:46:50 -04:00
commit bf536b8774
213 changed files with 117679 additions and 0 deletions
@@ -0,0 +1,165 @@
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using WhiteLagoon.Application.Common.Interfaces;
using WhiteLagoon.Application.Common.Utility;
using WhiteLagoon.Domain.Entities;
using WhiteLagoon.Web.ViewModels;
namespace WhiteLagoon.Web.Controllers
{
public class AccountController : Controller
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly RoleManager<IdentityRole> _roleManager;
public AccountController(
UserManager<ApplicationUser> userManager,
RoleManager<IdentityRole> roleManager,
SignInManager<ApplicationUser> signInManager)
{
_roleManager = roleManager;
_userManager = userManager;
_signInManager = signInManager;
}
public IActionResult Login(string returnUrl=null)
{
returnUrl??= Url.Content("~/");
LoginVM loginVM = new ()
{
RedirectUrl = returnUrl
};
return View(loginVM);
}
public async Task<IActionResult> Logout()
{
await _signInManager.SignOutAsync();
return RedirectToAction("Index", "Home");
}
public IActionResult AccessDenied()
{
return View();
}
public IActionResult Register(string returnUrl = null)
{
returnUrl ??= Url.Content("~/");
if (!_roleManager.RoleExistsAsync(SD.Role_Admin).GetAwaiter().GetResult())
{
_roleManager.CreateAsync(new IdentityRole(SD.Role_Admin)).Wait();
_roleManager.CreateAsync(new IdentityRole(SD.Role_Customer)).Wait();
}
RegisterVM registerVM = new ()
{
RoleList = _roleManager.Roles.Select(x => new SelectListItem
{
Text = x.Name,
Value = x.Name
}),
RedirectUrl = returnUrl
};
return View(registerVM);
}
[HttpPost]
public async Task<IActionResult> Register(RegisterVM registerVM)
{
if (ModelState.IsValid)
{
ApplicationUser user = new()
{
Name = registerVM.Name,
Email = registerVM.Email,
PhoneNumber = registerVM.PhoneNumber,
NormalizedEmail = registerVM.Email.ToUpper(),
EmailConfirmed = true,
UserName = registerVM.Email,
CreatedAt = DateTime.Now
};
var result = await _userManager.CreateAsync(user, registerVM.Password);
if (result.Succeeded)
{
if (!string.IsNullOrEmpty(registerVM.Role))
{
await _userManager.AddToRoleAsync(user, registerVM.Role);
}
else
{
await _userManager.AddToRoleAsync(user, SD.Role_Customer);
}
await _signInManager.SignInAsync(user, isPersistent: false);
if (string.IsNullOrEmpty(registerVM.RedirectUrl))
{
return RedirectToAction("Index", "Home");
}
else
{
return LocalRedirect(registerVM.RedirectUrl);
}
}
foreach (var error in result.Errors)
{
ModelState.AddModelError("", error.Description);
}
}
registerVM.RoleList = _roleManager.Roles.Select(x => new SelectListItem
{
Text = x.Name,
Value = x.Name
});
return View(registerVM);
}
[HttpPost]
public async Task<IActionResult> Login(LoginVM loginVM)
{
if (ModelState.IsValid)
{
var result = await _signInManager
.PasswordSignInAsync(loginVM.Email, loginVM.Password, loginVM.RememberMe, lockoutOnFailure:false);
if (result.Succeeded)
{
var user = await _userManager.FindByEmailAsync(loginVM.Email);
if (await _userManager.IsInRoleAsync(user, SD.Role_Admin))
{
return RedirectToAction("Index", "Dashboard");
}
else
{
if (string.IsNullOrEmpty(loginVM.RedirectUrl))
{
return RedirectToAction("Index", "Home");
}
else
{
return LocalRedirect(loginVM.RedirectUrl);
}
}
}
else
{
ModelState.AddModelError("", "Invalid login attempt.");
}
}
return View(loginVM);
}
}
}
@@ -0,0 +1,138 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using WhiteLagoon.Application.Common.Interfaces;
using WhiteLagoon.Application.Common.Utility;
using WhiteLagoon.Application.Services.Interface;
using WhiteLagoon.Domain.Entities;
using WhiteLagoon.Infrastructure.Data;
using WhiteLagoon.Web.ViewModels;
namespace WhiteLagoon.Web.Controllers
{
[Authorize(Roles = SD.Role_Admin)]
public class AmenityController : Controller
{
private readonly IAmenityService _amenityService;
private readonly IVillaService _villaService;
public AmenityController(IAmenityService amenityService, IVillaService villaService)
{
_amenityService = amenityService;
_villaService = villaService;
}
public IActionResult Index()
{
var amenities = _amenityService.GetAllAmenities();
return View(amenities);
}
public IActionResult Create()
{
AmenityVM amenityVM = new()
{
VillaList = _villaService.GetAllVillas().Select(u => new SelectListItem
{
Text = u.Name,
Value = u.Id.ToString()
})
};
return View(amenityVM);
}
[HttpPost]
public IActionResult Create(AmenityVM obj)
{
if (ModelState.IsValid)
{
_amenityService.CreateAmenity(obj.Amenity);
TempData["success"] = "The amenity has been created successfully.";
return RedirectToAction(nameof(Index));
}
obj.VillaList = _villaService.GetAllVillas().Select(u => new SelectListItem
{
Text = u.Name,
Value = u.Id.ToString()
});
return View(obj);
}
public IActionResult Update(int amenityId)
{
AmenityVM amenityVM = new()
{
VillaList = _villaService.GetAllVillas().Select(u => new SelectListItem
{
Text = u.Name,
Value = u.Id.ToString()
}),
Amenity = _amenityService.GetAmenityById(amenityId)
};
if (amenityVM.Amenity == null)
{
return RedirectToAction("Error", "Home");
}
return View(amenityVM);
}
[HttpPost]
public IActionResult Update(AmenityVM amenityVM)
{
if (ModelState.IsValid)
{
_amenityService.UpdateAmenity(amenityVM.Amenity);
TempData["success"] = "The amenity has been updated successfully.";
return RedirectToAction(nameof(Index));
}
amenityVM.VillaList = _villaService.GetAllVillas().Select(u => new SelectListItem
{
Text = u.Name,
Value = u.Id.ToString()
});
return View(amenityVM);
}
public IActionResult Delete(int amenityId)
{
AmenityVM amenityVM = new()
{
VillaList = _villaService.GetAllVillas().Select(u => new SelectListItem
{
Text = u.Name,
Value = u.Id.ToString()
}),
Amenity = _amenityService.GetAmenityById(amenityId)
};
if (amenityVM.Amenity == null)
{
return RedirectToAction("Error", "Home");
}
return View(amenityVM);
}
[HttpPost]
public IActionResult Delete(AmenityVM amenityVM)
{
Amenity? objFromDb = _amenityService.GetAmenityById(amenityVM.Amenity.Id);
if (objFromDb is not null)
{
_amenityService.DeleteAmenity(objFromDb.Id);
TempData["success"] = "The amenity has been deleted successfully.";
return RedirectToAction(nameof(Index));
}
TempData["error"] = "The amenity could not be deleted.";
return View();
}
}
}
@@ -0,0 +1,362 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Stripe;
using Stripe.Checkout;
using Syncfusion.DocIO;
using Syncfusion.DocIO.DLS;
using Syncfusion.DocIORenderer;
using Syncfusion.Drawing;
using Syncfusion.Pdf;
using System.Security.Claims;
using WhiteLagoon.Application.Common.Interfaces;
using WhiteLagoon.Application.Common.Utility;
using WhiteLagoon.Application.Contract;
using WhiteLagoon.Application.Services.Interface;
using WhiteLagoon.Domain.Entities;
using WhiteLagoon.Infrastructure.Repository;
namespace WhiteLagoon.Web.Controllers
{
public class BookingController : Controller
{
private readonly IBookingService _bookingService;
private readonly IWebHostEnvironment _webHostEnvironment;
private readonly IVillaService _villaService;
private readonly UserManager<ApplicationUser> _userManager;
private readonly IVillaNumberService _villaNumberService;
private readonly IPaymentService _paymentService;
private readonly IEmailService _emailService;
public BookingController(IBookingService bookingService,
IPaymentService paymentService,
IVillaService villaService, IVillaNumberService villaNumberService,
IWebHostEnvironment webHostEnvironment, UserManager<ApplicationUser> userManager,
IEmailService emailService)
{
_emailService = emailService;
_paymentService = paymentService;
_userManager = userManager;
_villaService = villaService;
_villaNumberService = villaNumberService;
_bookingService = bookingService;
_webHostEnvironment = webHostEnvironment;
}
[Authorize]
public IActionResult Index()
{
return View();
}
[Authorize]
public IActionResult FinalizeBooking(int villaId, DateOnly checkInDate, int nights)
{
var claimsIdentity = (ClaimsIdentity)User.Identity;
var userId = claimsIdentity.FindFirst(ClaimTypes.NameIdentifier).Value;
ApplicationUser user = _userManager.FindByIdAsync(userId).GetAwaiter().GetResult();
Booking booking = new()
{
VillaId = villaId,
Villa = _villaService.GetVillaById(villaId),
CheckInDate = checkInDate,
Nights = nights,
CheckOutDate = checkInDate.AddDays(nights),
UserId = userId,
Phone=user.PhoneNumber,
Email=user.Email,
Name=user.Name
};
booking.TotalCost = booking.Villa.Price * nights;
return View(booking);
}
[Authorize]
[HttpPost]
public IActionResult FinalizeBooking(Booking booking)
{
var villa = _villaService.GetVillaById(booking.VillaId);
booking.TotalCost = villa.Price * booking.Nights;
booking.Status=SD.StatusPending;
booking.BookingDate = DateTime.Now;
if (!_villaService.IsVillaAvailableByDate(villa.Id,booking.Nights,booking.CheckInDate))
{
TempData["error"] = "Room has been sold out!";
//no rooms available
return RedirectToAction(nameof(FinalizeBooking), new
{
villaId = booking.VillaId,
checkInDate = booking.CheckInDate,
nights = booking.Nights
});
}
_bookingService.CreateBooking(booking);
var domain = Request.Scheme+"://"+Request.Host.Value+"/";
var options = _paymentService.CreateStripeSessionOptions(booking, villa, domain);
var session = _paymentService.CreateStripeSession(options);
_bookingService.UpdateStripePaymentID(booking.Id, session.Id, session.PaymentIntentId);
Response.Headers.Add("Location", session.Url);
return new StatusCodeResult(303);
}
[Authorize]
public IActionResult BookingConfirmation(int bookingId)
{
Booking bookingFromDb = _bookingService.GetBookingById(bookingId);
if (bookingFromDb.Status == SD.StatusPending)
{
//this is a pending order, we need to confirm if payment was successful
var service = new SessionService();
Session session = service.Get(bookingFromDb.StripeSessionId);
if (session.PaymentStatus == "paid")
{
_bookingService.UpdateStatus(bookingFromDb.Id, SD.StatusApproved,0);
_bookingService.UpdateStripePaymentID(bookingFromDb.Id,session.Id,session.PaymentIntentId);
_emailService.SendEmailAsync(bookingFromDb.Email,"Booking Confirmation - White Lagoon", "<p>Your booking has been confirmed. Booking ID - " + bookingFromDb.Id+"</p>");
}
}
return View(bookingId);
}
[Authorize]
public IActionResult BookingDetails(int bookingId)
{
Booking bookingFromDb = _bookingService.GetBookingById(bookingId);
if (bookingFromDb.VillaNumber==0 && bookingFromDb.Status == SD.StatusApproved)
{
var availableVillaNumber = AssignAvailableVillaNumberByVilla(bookingFromDb.VillaId);
bookingFromDb.VillaNumbers = _villaNumberService.GetAllVillaNumbers().Where(u => u.VillaId == bookingFromDb.VillaId
&& availableVillaNumber.Any(x => x == u.Villa_Number)).ToList();
}
return View(bookingFromDb);
}
[HttpPost]
[Authorize]
public IActionResult GenerateInvoice(int id, string downloadType)
{
string basePath = _webHostEnvironment.WebRootPath;
WordDocument document = new WordDocument();
// Load the template.
string dataPath = basePath + @"/exports/BookingDetails.docx";
using FileStream fileStream = new (dataPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
document.Open(fileStream, FormatType.Automatic);
//Update Template
Booking bookingFromDb = _bookingService.GetBookingById(id);
TextSelection textSelection = document.Find("xx_customer_name", false, true);
WTextRange textRange = textSelection.GetAsOneRange();
textRange.Text = bookingFromDb.Name;
textSelection = document.Find("xx_customer_phone", false, true);
textRange = textSelection.GetAsOneRange();
textRange.Text = bookingFromDb.Phone;
textSelection = document.Find("xx_customer_email", false, true);
textRange = textSelection.GetAsOneRange();
textRange.Text = bookingFromDb.Email;
textSelection = document.Find("XX_BOOKING_NUMBER", false, true);
textRange = textSelection.GetAsOneRange();
textRange.Text = "BOOKING ID - " + bookingFromDb.Id;
textSelection = document.Find("XX_BOOKING_DATE", false, true);
textRange = textSelection.GetAsOneRange();
textRange.Text = "BOOKING DATE - " + bookingFromDb.BookingDate.ToShortDateString();
textSelection = document.Find("xx_payment_date", false, true);
textRange = textSelection.GetAsOneRange();
textRange.Text = bookingFromDb.PaymentDate.ToShortDateString();
textSelection = document.Find("xx_checkin_date", false, true);
textRange = textSelection.GetAsOneRange();
textRange.Text = bookingFromDb.CheckInDate.ToShortDateString();
textSelection = document.Find("xx_checkout_date", false, true);
textRange = textSelection.GetAsOneRange();
textRange.Text = bookingFromDb.CheckOutDate.ToShortDateString(); ;
textSelection = document.Find("xx_booking_total", false, true);
textRange = textSelection.GetAsOneRange();
textRange.Text = bookingFromDb.TotalCost.ToString("c");
WTable table = new(document);
table.TableFormat.Borders.LineWidth = 1f;
table.TableFormat.Borders.Color = Color.Black;
table.TableFormat.Paddings.Top = 7f;
table.TableFormat.Paddings.Bottom = 7f;
table.TableFormat.Borders.Horizontal.LineWidth = 1f;
int rows = bookingFromDb.VillaNumber > 0 ? 3 : 2;
table.ResetCells(rows, 4);
WTableRow row0 = table.Rows[0];
row0.Cells[0].AddParagraph().AppendText("NIGHTS");
row0.Cells[0].Width=80;
row0.Cells[1].AddParagraph().AppendText("VILLA");
row0.Cells[1].Width = 220;
row0.Cells[2].AddParagraph().AppendText("PRICE PER NIGHT");
row0.Cells[3].AddParagraph().AppendText("TOTAL");
row0.Cells[3].Width = 80;
WTableRow row1 = table.Rows[1];
row1.Cells[0].AddParagraph().AppendText(bookingFromDb.Nights.ToString());
row1.Cells[0].Width = 80;
row1.Cells[1].AddParagraph().AppendText(bookingFromDb.Villa.Name);
row1.Cells[1].Width = 220;
row1.Cells[2].AddParagraph().AppendText((bookingFromDb.TotalCost/bookingFromDb.Nights).ToString("c"));
row1.Cells[3].AddParagraph().AppendText(bookingFromDb.TotalCost.ToString("c"));
row1.Cells[3].Width = 80;
if (bookingFromDb.VillaNumber > 0)
{
WTableRow row2 = table.Rows[2];
row2.Cells[0].Width = 80;
row2.Cells[1].AddParagraph().AppendText("Villa Number - " + bookingFromDb.VillaNumber.ToString());
row2.Cells[1].Width = 220;
row2.Cells[3].Width = 80;
}
WTableStyle tableStyle = document.AddTableStyle("CustomStyle") as WTableStyle;
tableStyle.TableProperties.RowStripe = 1;
tableStyle.TableProperties.ColumnStripe = 2;
tableStyle.TableProperties.Paddings.Top = 2;
tableStyle.TableProperties.Paddings.Bottom = 1;
tableStyle.TableProperties.Paddings.Left = 5.4f;
tableStyle.TableProperties.Paddings.Right = 5.4f;
ConditionalFormattingStyle firstRowStyle = tableStyle.ConditionalFormattingStyles.Add(ConditionalFormattingType.FirstRow);
firstRowStyle.CharacterFormat.Bold = true;
firstRowStyle.CharacterFormat.TextColor = Color.FromArgb(255, 255, 255, 255);
firstRowStyle.CellProperties.BackColor = Color.Black;
table.ApplyStyle("CustomStyle");
TextBodyPart bodyPart = new(document);
bodyPart.BodyItems.Add(table);
document.Replace("<ADDTABLEHERE>", bodyPart, false, false);
using DocIORenderer renderer = new ();
MemoryStream stream = new();
if (downloadType == "word")
{
document.Save(stream, FormatType.Docx);
stream.Position = 0;
return File(stream, "application/docx", "BookingDetails.docx");
}
else
{
PdfDocument pdfDocument = renderer.ConvertToPDF(document);
pdfDocument.Save(stream);
stream.Position = 0;
return File(stream, "application/pdf", "BookingDetails.pdf");
}
}
[HttpPost]
[Authorize(Roles = SD.Role_Admin)]
public IActionResult CheckIn(Booking booking)
{
_bookingService.UpdateStatus(booking.Id, SD.StatusCheckedIn, booking.VillaNumber);
TempData["Success"] = "Booking Updated Successfully.";
return RedirectToAction(nameof(BookingDetails), new { bookingId = booking.Id });
}
[HttpPost]
[Authorize(Roles = SD.Role_Admin)]
public IActionResult CheckOut(Booking booking)
{
_bookingService.UpdateStatus(booking.Id, SD.StatusCompleted , booking.VillaNumber);
TempData["Success"] = "Booking Completed Successfully.";
return RedirectToAction(nameof(BookingDetails), new { bookingId = booking.Id });
}
[HttpPost]
[Authorize(Roles = SD.Role_Admin)]
public IActionResult CancelBooking(Booking booking)
{
_bookingService.UpdateStatus(booking.Id, SD.StatusCancelled, 0);
TempData["Success"] = "Booking Cancelled Successfully.";
return RedirectToAction(nameof(BookingDetails), new { bookingId = booking.Id });
}
private List<int> AssignAvailableVillaNumberByVilla(int villaId)
{
List<int> availableVillaNumbers = new();
var villaNumbers = _villaNumberService.GetAllVillaNumbers().Where(u => u.VillaId == villaId);
var checkedInVilla = _bookingService.GetCheckedInVillaNumbers(villaId);
foreach(var villaNumber in villaNumbers)
{
if (!checkedInVilla.Contains(villaNumber.Villa_Number))
{
availableVillaNumbers.Add(villaNumber.Villa_Number);
}
}
return availableVillaNumbers;
}
#region API Calls
[HttpGet]
[Authorize]
public IActionResult GetAll(string status)
{
IEnumerable<Booking> objBookings;
string userId = "";
if (string.IsNullOrEmpty(status))
{
status = "";
}
if (!User.IsInRole(SD.Role_Admin))
{
var claimsIdentity = (ClaimsIdentity)User.Identity;
userId = claimsIdentity.FindFirst(ClaimTypes.NameIdentifier).Value;
}
objBookings = _bookingService.GetAllBookings(userId, status);
return Json(new { data = objBookings });
}
#endregion
}
}
@@ -0,0 +1,51 @@
using Microsoft.AspNetCore.Mvc;
using Stripe;
using WhiteLagoon.Application.Common.Interfaces;
using WhiteLagoon.Application.Common.Utility;
using WhiteLagoon.Application.Services.Interface;
using WhiteLagoon.Web.ViewModels;
namespace WhiteLagoon.Web.Controllers
{
public class DashboardController : Controller
{
private readonly IDashboardService _dashboardService;
public DashboardController(IDashboardService dashboardService)
{
_dashboardService = dashboardService;
}
public IActionResult Index()
{
return View();
}
public async Task<IActionResult> GetTotalBookingRadialChartData()
{
return Json(await _dashboardService.GetTotalBookingRadialChartData());
}
public async Task<IActionResult> GetRegisteredUserChartData()
{
return Json(await _dashboardService.GetRegisteredUserChartData());
}
public async Task<IActionResult> GetRevenueChartData()
{
return Json(await _dashboardService.GetRevenueChartData());
}
public async Task<IActionResult> GetBookingPieChartData()
{
return Json(await _dashboardService.GetBookingPieChartData());
}
public async Task<IActionResult> GetMemberAndBookingLineChartData()
{
return Json(await _dashboardService.GetMemberAndBookingLineChartData());
}
}
}
@@ -0,0 +1,158 @@
using Microsoft.AspNetCore.Mvc;
using Syncfusion.Presentation;
using WhiteLagoon.Application.Common.Interfaces;
using WhiteLagoon.Application.Common.Utility;
using WhiteLagoon.Application.Services.Interface;
using WhiteLagoon.Web.ViewModels;
namespace WhiteLagoon.Web.Controllers
{
public class HomeController : Controller
{
private readonly IVillaService _villaService;
private readonly IWebHostEnvironment _webHostEnvironment;
public HomeController(IVillaService villaService, IWebHostEnvironment webHostEnvironment)
{
_villaService = villaService;
_webHostEnvironment = webHostEnvironment;
}
public IActionResult Index()
{
HomeVM homeVM = new()
{
VillaList = _villaService.GetAllVillas(),
Nights=1,
CheckInDate =DateOnly.FromDateTime(DateTime.Now),
};
return View(homeVM);
}
[HttpPost]
public IActionResult GetVillasByDate(int nights, DateOnly checkInDate)
{
HomeVM homeVM = new()
{
CheckInDate = checkInDate,
VillaList = _villaService.GetVillasAvailabilityByDate(nights,checkInDate),
Nights = nights
};
return PartialView("_VillaList",homeVM);
}
[HttpPost]
public IActionResult GeneratePPTExport(int id)
{
var villa = _villaService.GetVillaById(id);
if (villa is null)
{
return RedirectToAction(nameof(Error));
}
string basePath = _webHostEnvironment.WebRootPath;
string filePath = basePath + @"/Exports/ExportVillaDetails.pptx";
using IPresentation presentation = Presentation.Open(filePath);
ISlide slide = presentation.Slides[0];
IShape? shape = slide.Shapes.FirstOrDefault(u=>u.ShapeName== "txtVillaName") as IShape;
if(shape is not null)
{
shape.TextBody.Text = villa.Name;
}
shape = slide.Shapes.FirstOrDefault(u => u.ShapeName == "txtVillaDescription") as IShape;
if (shape is not null)
{
shape.TextBody.Text = villa.Description;
}
shape = slide.Shapes.FirstOrDefault(u => u.ShapeName == "txtOccupancy") as IShape;
if (shape is not null)
{
shape.TextBody.Text = string.Format("Max Occupancy : {0} adults", villa.Occupancy);
}
shape = slide.Shapes.FirstOrDefault(u => u.ShapeName == "txtVillaSize") as IShape;
if (shape is not null)
{
shape.TextBody.Text = string.Format("Villa Size: {0} sqft", villa.Sqft);
}
shape = slide.Shapes.FirstOrDefault(u => u.ShapeName == "txtPricePerNight") as IShape;
if (shape is not null)
{
shape.TextBody.Text = string.Format("USD {0}/night", villa.Price.ToString("C"));
}
shape = slide.Shapes.FirstOrDefault(u => u.ShapeName == "txtVillaAmenitiesHeading") as IShape;
if(shape is not null)
{
List<string> listItems = villa.VillaAmenity.Select(x => x.Name).ToList();
shape.TextBody.Text = "";
foreach (var item in listItems)
{
IParagraph paragraph = shape.TextBody.AddParagraph();
ITextPart textPart = paragraph.AddTextPart(item);
paragraph.ListFormat.Type = ListType.Bulleted;
paragraph.ListFormat.BulletCharacter = '\u2022';
textPart.Font.FontName = "system-ui";
textPart.Font.FontSize = 18;
textPart.Font.Color = ColorObject.FromArgb(144, 148, 152);
}
}
shape = slide.Shapes.FirstOrDefault(u => u.ShapeName == "imgVilla") as IShape;
if(shape is not null)
{
byte[] imageData;
string imageUrl;
try
{
imageUrl= string.Format("{0}{1}", basePath, villa.ImageUrl);
imageData = System.IO.File.ReadAllBytes(imageUrl);
}
catch (Exception)
{
imageUrl = string.Format("{0}{1}", basePath, "/images/placeholder.png");
imageData = System.IO.File.ReadAllBytes(imageUrl);
}
slide.Shapes.Remove(shape);
using MemoryStream imageStream = new(imageData);
IPicture newPicture = slide.Pictures.AddPicture(imageStream, 60,120,300,200);
}
MemoryStream memoryStream = new();
presentation.Save(memoryStream);
memoryStream.Position = 0;
return File(memoryStream,"application/pptx","villa.pptx");
}
public IActionResult Privacy()
{
return View();
}
public IActionResult Error()
{
return View();
}
}
}
@@ -0,0 +1,99 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using WhiteLagoon.Application.Common.Interfaces;
using WhiteLagoon.Application.Services.Interface;
using WhiteLagoon.Domain.Entities;
using WhiteLagoon.Infrastructure.Data;
namespace WhiteLagoon.Web.Controllers
{
[Authorize]
public class VillaController : Controller
{
private readonly IVillaService _villaService;
public VillaController(IVillaService villaService)
{
_villaService = villaService;
}
public IActionResult Index()
{
var villas = _villaService.GetAllVillas();
return View(villas);
}
public IActionResult Create()
{
return View();
}
[HttpPost]
public IActionResult Create(Villa obj)
{
if (obj.Name == obj.Description)
{
ModelState.AddModelError("name", "The description cannot exactly match the Name.");
}
if (ModelState.IsValid)
{
_villaService.CreateVilla(obj);
TempData["success"] = "The villa has been created successfully.";
return RedirectToAction(nameof(Index));
}
return View();
}
public IActionResult Update(int villaId)
{
Villa? obj = _villaService.GetVillaById(villaId);
if (obj == null)
{
return RedirectToAction("Error", "Home");
}
return View(obj);
}
[HttpPost]
public IActionResult Update(Villa obj)
{
if (ModelState.IsValid && obj.Id > 0)
{
_villaService.UpdateVilla(obj);
TempData["success"] = "The villa has been updated successfully.";
return RedirectToAction(nameof(Index));
}
return View();
}
public IActionResult Delete(int villaId)
{
Villa? obj = _villaService.GetVillaById(villaId);
if (obj is null)
{
return RedirectToAction("Error", "Home");
}
return View(obj);
}
[HttpPost]
public IActionResult Delete(Villa obj)
{
bool deleted = _villaService.DeleteVilla(obj.Id);
if (deleted)
{
TempData["success"] = "The villa has been deleted successfully.";
return RedirectToAction(nameof(Index));
}
else
{
TempData["error"] = "Failed to delete the villa.";
}
return View();
}
}
}
@@ -0,0 +1,142 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using WhiteLagoon.Application.Common.Interfaces;
using WhiteLagoon.Application.Services.Interface;
using WhiteLagoon.Domain.Entities;
using WhiteLagoon.Infrastructure.Data;
using WhiteLagoon.Web.ViewModels;
namespace WhiteLagoon.Web.Controllers
{
public class VillaNumberController : Controller
{
private readonly IVillaNumberService _villaNumberService;
private readonly IVillaService _villaService;
public VillaNumberController(IVillaNumberService villaNumberService, IVillaService villaService)
{
_villaService = villaService;
_villaNumberService = villaNumberService;
}
public IActionResult Index()
{
var villaNumbers = _villaNumberService.GetAllVillaNumbers();
return View(villaNumbers);
}
public IActionResult Create()
{
VillaNumberVM villaNumberVM = new()
{
VillaList = _villaService.GetAllVillas().Select(u => new SelectListItem
{
Text = u.Name,
Value = u.Id.ToString()
})
};
return View(villaNumberVM);
}
[HttpPost]
public IActionResult Create(VillaNumberVM obj)
{
//ModelState.Remove("Villa");
bool roomNumberExists = _villaNumberService.CheckVillaNumberExists(obj.VillaNumber.Villa_Number);
if (ModelState.IsValid && !roomNumberExists)
{
_villaNumberService.CreateVillaNumber(obj.VillaNumber);
TempData["success"] = "The villa Number has been created successfully.";
return RedirectToAction(nameof(Index));
}
if (roomNumberExists)
{
TempData["error"] = "The villa Number already exists.";
}
obj.VillaList = _villaService.GetAllVillas().Select(u => new SelectListItem
{
Text = u.Name,
Value = u.Id.ToString()
});
return View(obj);
}
public IActionResult Update(int villaNumberId)
{
VillaNumberVM villaNumberVM = new()
{
VillaList = _villaService.GetAllVillas().Select(u => new SelectListItem
{
Text = u.Name,
Value = u.Id.ToString()
}),
VillaNumber = _villaNumberService.GetVillaNumberById(villaNumberId)
};
if (villaNumberVM.VillaNumber == null)
{
return RedirectToAction("Error", "Home");
}
return View(villaNumberVM);
}
[HttpPost]
public IActionResult Update(VillaNumberVM villaNumberVM)
{
if (ModelState.IsValid)
{
_villaNumberService.UpdateVillaNumber(villaNumberVM.VillaNumber);
TempData["success"] = "The villa Number has been updated successfully.";
return RedirectToAction(nameof(Index));
}
villaNumberVM.VillaList = _villaService.GetAllVillas().Select(u => new SelectListItem
{
Text = u.Name,
Value = u.Id.ToString()
});
return View(villaNumberVM);
}
public IActionResult Delete(int villaNumberId)
{
VillaNumberVM villaNumberVM = new()
{
VillaList = _villaService.GetAllVillas().Select(u => new SelectListItem
{
Text = u.Name,
Value = u.Id.ToString()
}),
VillaNumber = _villaNumberService.GetVillaNumberById(villaNumberId)
};
if (villaNumberVM.VillaNumber == null)
{
return RedirectToAction("Error", "Home");
}
return View(villaNumberVM);
}
[HttpPost]
public IActionResult Delete(VillaNumberVM villaNumberVM)
{
VillaNumber? objFromDb = _villaNumberService.GetVillaNumberById(villaNumberVM.VillaNumber.Villa_Number);
if (objFromDb is not null)
{
_villaNumberService.DeleteVillaNumber(objFromDb.Villa_Number);
TempData["success"] = "The villa number has been deleted successfully.";
return RedirectToAction(nameof(Index));
}
TempData["error"] = "The villa number could not be deleted.";
return View();
}
}
}
+9
View File
@@ -0,0 +1,9 @@
namespace WhiteLagoon.Web.Models
{
public class ErrorViewModel
{
public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
}
}
+77
View File
@@ -0,0 +1,77 @@
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Stripe;
using Syncfusion.Licensing;
using WhiteLagoon.Application.Common.Interfaces;
using WhiteLagoon.Application.Contract;
using WhiteLagoon.Application.Services.Implementation;
using WhiteLagoon.Application.Services.Interface;
using WhiteLagoon.Domain.Entities;
using WhiteLagoon.Infrastructure.Data;
using WhiteLagoon.Infrastructure.Emails;
using WhiteLagoon.Infrastructure.Repository;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
builder.Services.AddDbContext<ApplicationDbContext>(option =>
option.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
builder.Services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.ConfigureApplicationCookie(option =>
{
option.AccessDeniedPath = "/Account/AccessDenied";
option.LoginPath = "/Account/Login";
});
builder.Services.Configure<IdentityOptions>(option =>
{
option.Password.RequiredLength = 6;
});
builder.Services.AddScoped<IUnitOfWork,UnitOfWork>();
builder.Services.AddScoped<IDashboardService, DashboardService>();
builder.Services.AddScoped<IDbInitializer, DbInitializer>();
builder.Services.AddScoped<IVillaService, VillaService>();
builder.Services.AddScoped<IVillaNumberService, VillaNumberService>();
builder.Services.AddScoped<IAmenityService, AmenityService>();
builder.Services.AddScoped<IBookingService, BookingService>();
builder.Services.AddScoped<IPaymentService, PaymentService>();
builder.Services.AddScoped<IEmailService, EmailService>();
var app = builder.Build();
StripeConfiguration.ApiKey=builder.Configuration.GetSection("Stripe:SecretKey").Get<string>();
SyncfusionLicenseProvider.RegisterLicense(builder.Configuration.GetSection("Syncfusion:Licensekey").Get<string>());
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
SeedDatabase();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
void SeedDatabase()
{
using (var scope = app.Services.CreateScope())
{
var dbInitializer = scope.ServiceProvider.GetRequiredService<IDbInitializer>();
dbInitializer.Initialize();
}
}
@@ -0,0 +1,38 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:46078",
"sslPort": 44385
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:5137",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:7254;http://localhost:5137",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
+13
View File
@@ -0,0 +1,13 @@
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.AspNetCore.Mvc.Rendering;
using WhiteLagoon.Domain.Entities;
namespace WhiteLagoon.Web.ViewModels
{
public class AmenityVM
{
public Amenity? Amenity { get; set; }
[ValidateNever]
public IEnumerable<SelectListItem>? VillaList { get; set; }
}
}
+12
View File
@@ -0,0 +1,12 @@
using WhiteLagoon.Domain.Entities;
namespace WhiteLagoon.Web.ViewModels
{
public class HomeVM
{
public IEnumerable<Villa>? VillaList { get; set; }
public DateOnly CheckInDate { get; set; }
public DateOnly? CheckOutDate { get; set; }
public int Nights { get; set; }
}
}
+18
View File
@@ -0,0 +1,18 @@
using System.ComponentModel.DataAnnotations;
namespace WhiteLagoon.Web.ViewModels
{
public class LoginVM
{
[Required]
public string Email { get; set; }
[Required]
[DataType(DataType.Password)]
public string Password { get; set; }
public bool RememberMe { get; set; }
public string? RedirectUrl { get; set; }
}
}
+33
View File
@@ -0,0 +1,33 @@
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.AspNetCore.Mvc.Rendering;
using System.ComponentModel.DataAnnotations;
namespace WhiteLagoon.Web.ViewModels
{
public class RegisterVM
{
[Required]
public string Email { get; set; }
[Required]
[DataType(DataType.Password)]
public string Password { get; set; }
[Required]
[DataType(DataType.Password)]
[Compare(nameof(Password))]
[Display(Name = "Confirm password")]
public string ConfirmPassword { get; set; }
[Required]
public string Name { get; set; }
[Display(Name="Phone Number")]
public string? PhoneNumber { get; set; }
public string? RedirectUrl { get; set; }
public string? Role { get; set; }
[ValidateNever]
public IEnumerable<SelectListItem>? RoleList { get; set; }
}
}
@@ -0,0 +1,13 @@
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.AspNetCore.Mvc.Rendering;
using WhiteLagoon.Domain.Entities;
namespace WhiteLagoon.Web.ViewModels
{
public class VillaNumberVM
{
public VillaNumber? VillaNumber { get; set; }
[ValidateNever]
public IEnumerable<SelectListItem>? VillaList { get; set; }
}
}
@@ -0,0 +1,3 @@
<div class="container pt-2">
<img src="~/images/accessDenied.jpg" width="100%"/>
</div>
@@ -0,0 +1,58 @@
@model LoginVM
<div class="container pt-5">
<div class="card shadow border">
<div class="card-header bg-success bg-gradient ml-0 py-4">
<div class="row">
<div class="col-12 text-center">
<h2 class="py-2 text-white">Login</h2>
</div>
</div>
</div>
<div class="card-body p-4">
<div class="row">
<div class="col-md-12">
<section>
<form method="post">
<input asp-for="RedirectUrl" hidden />
<div asp-validation-summary="ModelOnly" class="text-danger" ></div>
<div class="form-floating mb-3">
<input asp-for="Email" class="form-control" aria-required="true" />
<label asp-for="Email" class="form-label"></label>
<span asp-validation-for="Email" class="text-danger"></span>
</div>
<div class="form-floating mb-3">
<input asp-for="Password" class="form-control" aria-required="true" />
<label asp-for="Password" class="form-label"></label>
<span asp-validation-for="Password" class="text-danger"></span>
</div>
<div class="checkbox mb-3">
<input class="form-check-input" asp-for="RememberMe" />
<label class="form-label">
Remember Me
</label>
</div>
<div>
<button type="submit" class="w-100 btn btn-lg btn-outline-success">Log in</button>
</div>
<div class="d-flex justify-content-between pt-2">
<p>
<a asp-action="ForgotPassword">Forgot your password?</a>
</p>
<p>
<a asp-action="Register" asp-route-returnUrl="@Model.RedirectUrl">Register as a new user</a>
</p>
</div>
</form>
</section>
</div>
</div>
</div>
</div>
</div>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}
@@ -0,0 +1,62 @@
@model RegisterVM
<div class="container pt-5">
<div class="card shadow border ">
<div class="card-header bg-success bg-gradient ml-0 py-4">
<div class="row">
<div class="col-12 text-center">
<h2 class="py-2 text-white">Register</h2>
</div>
</div>
</div>
<div class="card-body p-4">
<div class="row pt-3">
<div class="col-md-12">
<form class="row" method="post">
<input asp-for="RedirectUrl" hidden />
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-floating mb-3 col-md-12">
<input asp-for="Email" class="form-control" aria-required="true" />
<label asp-for="Email" class="ms-2 text-muted"></label>
<span asp-validation-for="Email" class="text-danger"/>
</div>
<div class="form-floating mb-3 col-md-6">
<input asp-for="Name" class="form-control" />
<label asp-for="Name" class="ms-2 text-muted"></label>
<span asp-validation-for="Name" class="text-danger" />
</div>
<div class="form-floating mb-3 col-md-6">
<input asp-for="PhoneNumber" class="form-control" />
<label asp-for="PhoneNumber" class="ms-2 text-muted"></label>
<span asp-validation-for="PhoneNumber" class="text-danger" />
</div>
<div class="form-floating mb-3 col-md-6">
<input asp-for="Password" class="form-control" />
<label asp-for="Password" class="ms-2 text-muted"></label>
<span asp-validation-for="Password" class="text-danger" />
</div>
<div class="form-floating mb-3 col-md-6">
<input asp-for="ConfirmPassword" class="form-control" />
<label asp-for="ConfirmPassword" class="ms-2 text-muted">Confirm Password</label>
<span asp-validation-for="ConfirmPassword" class="text-danger" />
</div>
<div class="form-floating mb-3 col-md-6">
<select asp-for="Role" asp-items="@Model.RoleList" class="form-select">
<option disabled selected>-Select Role-</option>
</select>
</div>
<div class="col-12">
<button type="submit" class="w-100 btn btn-lg btn-outline-success">Register</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}
@@ -0,0 +1,55 @@
@model AmenityVM
<div class="w-100 card border-0 p-4">
<div class="card-header bg-success bg-gradient ml-0 py-3">
<div class="row">
<div class="col-12 text-center">
<h2 class="text-white py-2">Create Amenity</h2>
</div>
</div>
</div>
<div class="card-body border p-4">
<form method="post" class="row">
<div class="p-3">
@* <div asp-validation-summary="All"></div> *@
<div class="form-floating py-1 col-12">
<select asp-for="@Model.Amenity.VillaId" asp-items="@Model.VillaList"
class="form-select border shadow">
<option disabled selected>--Select Villa--</option>
</select>
<label asp-for="Amenity.VillaId" class="ms-2"></label>
<span asp-validation-for="Amenity.VillaId" class="text-danger"></span>
</div>
<div class="form-floating py-1 col-12">
<input asp-for="Amenity.Name" class="form-control border shadow" />
<label asp-for="Amenity.Name" class="ms-2"></label>
<span asp-validation-for="Amenity.Name" class="text-danger"></span>
</div>
<div class="form-floating py-1 col-12">
<input asp-for="Amenity.Description" class="form-control border shadow" />
<label asp-for="Amenity.Description" class="ms-2"></label>
<span asp-validation-for="Amenity.Description" class="text-danger"></span>
</div>
<div class="row pt-2">
<div class="col-6 col-md-3">
<button type="submit" class="btn btn-success w-100">
<i class="bi bi-check-circle"></i> Create
</button>
</div>
<div class="col-6 col-md-3">
<a asp-controller="Amenity" asp-action="Index" class="btn btn-secondary w-100">
<i class="bi bi-x-circle"></i> Cancel
</a>
</div>
</div>
</div>
</form>
</div>
</div>
@section Scripts{
@{
<partial name="_ValidationScriptsPartial" />
}
}
@@ -0,0 +1,56 @@
@model AmenityVM
<div class="w-100 card border-0 p-4">
<div class="card-header bg-success bg-gradient ml-0 py-3">
<div class="row">
<div class="col-12 text-center">
<h2 class="text-white py-2">Update Amenity</h2>
</div>
</div>
</div>
<div class="card-body border p-4">
<form method="post" class="row">
<input hidden asp-for="Amenity.Id" />
<div class="p-3">
@* <div asp-validation-summary="All"></div> *@
<div class="form-floating py-1 col-12">
<select asp-for="@Model.Amenity.VillaId" disabled asp-items="@Model.VillaList"
class="form-select border shadow">
<option disabled selected>--Select Villa--</option>
</select>
<label asp-for="Amenity.VillaId" class="ms-2"></label>
<span asp-validation-for="Amenity.VillaId" class="text-danger"></span>
</div>
<div class="form-floating py-1 col-12">
<input asp-for="Amenity.Name" readonly class="form-control border shadow" />
<label asp-for="Amenity.Name" class="ms-2"></label>
<span asp-validation-for="Amenity.Name" class="text-danger"></span>
</div>
<div class="form-floating py-1 col-12">
<input asp-for="Amenity.Description" readonly class="form-control border shadow" />
<label asp-for="Amenity.Description" class="ms-2"></label>
<span asp-validation-for="Amenity.Description" class="text-danger"></span>
</div>
<div class="row pt-2">
<div class="col-6 col-md-3">
<button type="submit" class="btn btn-danger w-100">
<i class="bi bi-check-circle"></i> Delete
</button>
</div>
<div class="col-6 col-md-3">
<a asp-controller="Amenity" asp-action="Index" class="btn btn-secondary w-100">
<i class="bi bi-x-circle"></i> Cancel
</a>
</div>
</div>
</div>
</form>
</div>
</div>
@section Scripts{
@{
<partial name="_ValidationScriptsPartial" />
}
}
@@ -0,0 +1,55 @@
@model IEnumerable<Amenity>
<div class="w-100 card border-0 p-4">
<div class="card-header bg-success bg-gradient ml-0 py-3">
<div class="row">
<div class="col-12 text-center">
<h2 class="text-white py-2">Amenity List</h2>
</div>
</div>
</div>
<div class="card-body border p-4">
<div class="row pb-3">
<div class="col-6 offset-6 text-end">
<a asp-controller="Amenity" asp-action="Create" class="btn btn-secondary">
<i class="bi bi-plus-circle"></i> Create New Amenity
</a>
</div>
</div>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>
Id
</th>
<th>Name</th>
<th>Villa Name</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var obj in Model)
{
<tr>
<td>@obj.Id</td>
<td>@obj.Name</td>
<td>@obj.Villa.Name</td>
<td>
<div class="w-75 btn-group" role="group">
<a asp-controller="Amenity" asp-action="Update" asp-route-amenityId="@obj.Id"
class="btn btn-success mx-2">
<i class="bi bi-pencil-square"></i> Edit
</a>
<a asp-controller="Amenity" asp-action="Delete" asp-route-amenityId="@obj.Id"
class="btn btn-danger mx-2">
<i class="bi bi-trash-fill"></i> Delete
</a>
</div>
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
@@ -0,0 +1,56 @@
@model AmenityVM
<div class="w-100 card border-0 p-4">
<div class="card-header bg-success bg-gradient ml-0 py-3">
<div class="row">
<div class="col-12 text-center">
<h2 class="text-white py-2">Update Amenity</h2>
</div>
</div>
</div>
<div class="card-body border p-4">
<form method="post" class="row">
<input hidden asp-for="Amenity.Id" />
<div class="p-3">
@* <div asp-validation-summary="All"></div> *@
<div class="form-floating py-1 col-12">
<select asp-for="@Model.Amenity.VillaId" asp-items="@Model.VillaList"
class="form-select border shadow">
<option disabled selected>--Select Villa--</option>
</select>
<label asp-for="Amenity.VillaId" class="ms-2"></label>
<span asp-validation-for="Amenity.VillaId" class="text-danger"></span>
</div>
<div class="form-floating py-1 col-12">
<input asp-for="Amenity.Name" class="form-control border shadow" />
<label asp-for="Amenity.Name" class="ms-2"></label>
<span asp-validation-for="Amenity.Name" class="text-danger"></span>
</div>
<div class="form-floating py-1 col-12">
<input asp-for="Amenity.Description" class="form-control border shadow" />
<label asp-for="Amenity.Description" class="ms-2"></label>
<span asp-validation-for="Amenity.Description" class="text-danger"></span>
</div>
<div class="row pt-2">
<div class="col-6 col-md-3">
<button type="submit" class="btn btn-success w-100">
<i class="bi bi-check-circle"></i> Update
</button>
</div>
<div class="col-6 col-md-3">
<a asp-controller="Amenity" asp-action="Index" class="btn btn-secondary w-100">
<i class="bi bi-x-circle"></i> Cancel
</a>
</div>
</div>
</div>
</form>
</div>
</div>
@section Scripts{
@{
<partial name="_ValidationScriptsPartial" />
}
}
@@ -0,0 +1,14 @@
@model int
<div class="container pt-4">
<div class="col-12 text-center">
<h1 class="text-success text-center">Your Vacation is Confirmed!</h1>
Your Order Number is : @Model <br />
<p>You can view all order details in Manage Order Section.</p>
<img src="~/images/orderConfirmed.jpg" style="border-radius:20px" width="65%" />
</div>
<div class="col-12 text-center text-warning">
<p class="pt-1">Pack your bags! You are one step closer to an amazing vacation!</p>
</div>
</div>
@@ -0,0 +1,185 @@
@model Booking
<div class="p-4 mt-0 mt-lg-4">
<div class="row" style="border: 1px solid #aaa;">
<div class="col-12 col-lg-6 p-4 2 mt-2 mt-md-0">
<div class="row p-1 " style="border-radius:20px; ">
<div class="col-6">
<h3 class="text-success">Villa Details</h3>
</div>
<div class="col-6 text-end">
<a class="btn btn-secondary my-2"
asp-controller="Booking" asp-action="Index"
><i class="bi bi-arrow-left-circle"></i> Back to Bookings</a>
</div>
<hr />
<partial name="_VillaDetail" model="@Model.Villa"/>
<hr />
<div class="text-end">
<h4 class="text-danger font-weight-bold ">
Booking Total :
<span style="border-bottom:1px solid #ff6a00">
@Model.TotalCost.ToString("c")
</span>
</h4>
</div>
<hr/>
<form method="post">
<div class="row pt-1 mb-3 " style="border-radius:20px; ">
<div class="col-12 text-center">
<button asp-action="GenerateInvoice" asp-route-id="@Model.Id"
asp-route-downloadType="word" type="submit"
class="btn btn-sm btn-secondary my-1">
<i class="bi bi-file-earmark-word"></i> Generate Invoice (word)
</button>
<button asp-action="GenerateInvoice" asp-route-id="@Model.Id"
asp-route-downloadType="pdf" type="submit"
class="btn btn-sm btn-secondary my-1">
<i class="bi bi-file-earmark-pdf"></i> Generate Invoice (pdf)
</button>
</div>
</div>
</form>
</div>
</div>
<div class="col-12 col-lg-6 p-4 2 mt-4 mt-md-0" style="border-left:1px solid #aaa">
<form method="post">
<input asp-for="Id" hidden />
<input asp-for="VillaId" hidden />
<input asp-for="UserId" hidden />
<input asp-for="CheckInDate" hidden />
<input asp-for="CheckOutDate" hidden />
<input asp-for="Nights" hidden />
<div class="row pt-1 mb-3 " style="border-radius:20px; ">
<div class="col-6">
<h3 class="text-success">Enter Booking Details</h3>
</div>
<div class="col-6">
@if ((Model.Status == SD.StatusApproved || Model.Status == SD.StatusPending)
&& User.IsInRole(SD.Role_Admin))
{
<button type="submit" asp-controller="Booking" asp-action="CancelBooking" class="btn btn-sm btn-outline-danger form-control my-1">
<i class="bi bi-x-circle"></i> &nbsp; Cancel Booking
</button>
}
</div>
</div>
<div class="row">
<div class="form-group pt-2 col-6">
<label class="text-warning">Name</label>
<input asp-for="Name" class="form-control" />
</div>
<div class="form-group pt-2 col-6">
<label class="text-warning">Phone</label>
<input asp-for="Phone" class="form-control" />
</div>
<div class="form-group pt-2 col-6">
<label class="text-warning">Email</label>
<input asp-for="Email" class="form-control" />
</div>
<div class="form-group pt-2 col-6">
<label class="text-warning">No. of nights</label>
<input asp-for="Nights" disabled class="form-control" />
</div>
<div class="form-group pt-2 col-6">
<label class="text-warning">Status</label>
<input asp-for="Status" disabled class="form-control" />
</div>
<div class="form-group pt-2 col-6">
<label class="text-warning">Booking Date</label>
<input asp-for="BookingDate" disabled class="form-control" />
</div>
<div class="form-group pt-2 col-6">
<label class="text-warning">Check-in Date</label>
<input asp-for="CheckInDate" disabled class="form-control" />
</div>
<div class="form-group pt-2 col-6">
<label class="text-warning">Actual Check-in Date</label>
<input asp-for="ActualCheckInDate" disabled class="form-control" />
</div>
<div class="form-group pt-2 col-6">
<label class="text-warning">Check-out Date</label>
<input asp-for="CheckOutDate" disabled class="form-control" />
</div>
<div class="form-group pt-2 col-6">
<label class="text-warning">Actual Check-out Date</label>
<input asp-for="ActualCheckOutDate" disabled class="form-control" />
</div>
@if(Model.Status==SD.StatusApproved && User.IsInRole(SD.Role_Admin))
{
<div class="form-group pt-2 col-6">
<label class="text-danger" asp-for="VillaNumber"></label>
<select class="form-select" asp-for="VillaNumber">
@foreach (var item in Model.VillaNumbers)
{
<option value="@item.Villa_Number">@item.Villa_Number</option>
}
</select>
</div>
}
else
{
<input asp-for="VillaNumber" hidden />
@if (Model.Status == SD.StatusCheckedIn || Model.Status == SD.StatusCompleted)
{
<div class="form-group pt-2 col-6">
<label class="text-warning">Villa Number</label>
<input asp-for="VillaNumber" disabled class="form-control" />
</div>
}
}
@if (Model.IsPaymentSuccessful && User.IsInRole(SD.Role_Admin))
{
<div class="form-group pt-2 col-6">
<label class="text-warning">Stripe PaymentIntent Id</label>
<input asp-for="StripePaymentIntentId" disabled class="form-control" />
</div>
<div class="form-group pt-2 col-6">
<label class="text-warning">Stripe Session Id</label>
<input asp-for="StripeSessionId" disabled class="form-control" />
</div>
<div class="form-group pt-2 col-6">
<label class="text-warning">Payment Date</label>
<input asp-for="PaymentDate" disabled class="form-control" />
</div>
}
<div class="form-group pt-2 col-6">
<label class="text-warning">Status</label>
<input asp-for="Status" disabled class="form-control" />
</div>
</div>
<div class="form-group pt-2 pt-md-4">
@if (User.IsInRole(SD.Role_Admin))
{
@if (Model.Status == SD.StatusApproved)
{
<button type="submit" asp-controller="Booking" asp-action="CheckIn"
class="btn btn-warning form-control my-1">
<i class="bi bi-check2-square"></i> &nbsp; Check In
</button>
}
@if (Model.Status == SD.StatusCheckedIn)
{
<button type="submit" asp-controller="Booking" asp-action="CheckOut"
class="btn btn-success form-control my-1">
<i class="bi bi-clipboard2-check"></i> &nbsp; Check Out / Complete Booking
</button>
}
}
</div>
</form>
</div>
</div>
</div>
@@ -0,0 +1,88 @@
@model Booking
<div class="container pt-4 mt-0 mt-lg-4">
<div class="row" style="border: 1px solid #aaa;">
<div class="col-12 col-lg-7 p-4 2 mt-4 mt-md-0">
<div class="row p-1 my-1 " style="border-radius:20px; ">
<div class="col-6">
<h3 class="text-success">Villa Details</h3>
</div>
<div class="text-end col-6 ">
<a asp-controller="Home" asp-action="Index"
class="btn btn-sm btn-outline-danger" style="width:200px;">
<i class="bi bi-arrow-left-square"></i> &nbsp; Modify Selection
</a>
</div>
<hr />
<partial name="_VillaDetail" model="@Model.Villa" />
<hr />
<div class="text-end">
<h4 class="text-danger font-weight-bold ">
Booking Total :
<span style="border-bottom:1px solid #ff6a00">
@Model.TotalCost.ToString("c")
</span>
</h4>
</div>
</div>
</div>
<div class="col-12 col-lg-5 p-4 2 mt-4 mt-md-0" style="border-left:1px solid #aaa">
<form method="post">
<input asp-for="VillaId" hidden />
<input asp-for="UserId" hidden />
<input asp-for="CheckInDate" hidden />
<input asp-for="CheckOutDate" hidden />
<input asp-for="Nights" hidden />
<div class="row pt-1 mb-3 " style="border-radius:20px; ">
<div class="col-12">
<h3 class="text-success">Enter Booking Details</h3>
</div>
</div>
<div class="form-group pt-0">
<label asp-for="Name" class="text-warning">Name</label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group pt-2">
<label asp-for="Phone" class="text-warning">Phone</label>
<input asp-for="Phone" class="form-control" />
<span asp-validation-for="Phone" class="text-danger"></span>
</div>
<div class="form-group pt-2">
<label asp-for="Email" class="text-warning">Email</label>
<input asp-for="Email" class="form-control" />
<span asp-validation-for="Email" class="text-danger"></span>
</div>
<div class="form-group pt-2">
<label asp-for="CheckInDate" class="text-warning">Check in Date</label>
<input asp-for="CheckInDate" disabled class="form-control" />
</div>
<div class="form-group pt-2">
<label asp-for="CheckOutDate" class="text-warning">Check Out Date</label>
<input asp-for="CheckOutDate" disabled class="form-control" />
</div>
<div class="form-group pt-2">
<label asp-for="Nights" class="text-warning">No. of nights</label>
<input asp-for="Nights" disabled class="form-control" />
</div>
<div class="form-group pt-2 pt-md-4">
@if (Model.Villa.IsAvailable)
{
<button type="submit" class="btn btn-success form-control">Looks Good! Checkout Now</button>
}
else
{
<input class="btn btn-danger disabled form-control" value="Sold Out" />
}
</div>
</form>
</div>
</div>
</div>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}
@@ -0,0 +1,89 @@
@{
var status = Context.Request.Query["status"];
var approved = "";
var pending = "";
var checkedIn = "";
var completed = "";
var cancelled = "";
switch (status)
{
case SD.StatusPending:
pending = "text-white bg-success";
break;
case SD.StatusApproved:
approved = "text-white bg-success";
break;
case SD.StatusCheckedIn:
checkedIn = "text-white bg-success";
break;
case SD.StatusCompleted:
completed = "text-white bg-success";
break;
case SD.StatusCancelled:
cancelled = "text-white bg-success";
break;
default:
break;
}
}
<div class="w-100 card border-0 p-4">
<div class="card-header bg-success bg-gradient ml-0 py-3">
<div class="row">
<div class="col-12 text-center">
<h2 class="text-white py-2">Booking List</h2>
</div>
</div>
</div>
<div class="card-body border p-4">
<div class="d-flex justify-content-end pb-4 pt-2">
<ul class="list-group list-group-horizontal-sm">
<a style="text-decoration:none;" asp-controller="Booking" asp-action="Index"
asp-route-status="@SD.StatusPending">
<li class="list-group-item @pending"> @SD.StatusPending </li>
</a>
<a style="text-decoration:none;" asp-controller="Booking" asp-action="Index"
asp-route-status="@SD.StatusApproved">
<li class="list-group-item @approved"> @SD.StatusApproved </li>
</a>
<a style="text-decoration:none;" asp-controller="Booking" asp-action="Index"
asp-route-status="@SD.StatusCheckedIn">
<li class="list-group-item @checkedIn"> @SD.StatusCheckedIn </li>
</a>
<a style="text-decoration:none;" asp-controller="Booking" asp-action="Index"
asp-route-status="@SD.StatusCompleted">
<li class="list-group-item @completed"> @SD.StatusCompleted </li>
</a>
<a style="text-decoration:none;" asp-controller="Booking" asp-action="Index"
asp-route-status="@SD.StatusCancelled">
<li class="list-group-item @cancelled"> @SD.StatusCancelled </li>
</a>
</ul>
</div>
<table id="tblBookings" class="table table-bordered table-striped">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Phone</th>
<th>Email</th>
<th>Status</th>
<th>Check In Date</th>
<th>Nights</th>
<th>Total</th>
<th></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
@section Scripts{
<script src="~/js/booking.js"></script>
}
@@ -0,0 +1,122 @@
<div class="container-fluid">
<div class="row">
<div class="page-title-box d-flex align-items-center justify-content-between">
<h4 class="mb-0">Dashboard</h4>
</div>
</div>
<div class="row">
<div class="col-md-6 col-xl-4 mt-2">
<div class="card">
<div class="card-body">
<div class="float-end mt-2">
<div id="totalBookingsRadialChart" data-colors='["--bs-success"]'></div>
</div>
<div>
<p class="text-muted mb-0">Total Bookings</p>
<h4 class="my-1">
<span id="spanTotalBookingCount">XX</span>
</h4>
</div>
<p class="text-muted mt-3 mb-0" id="sectionBookingCount"></p>
<div class="justify-content-center text-center chart-spinner" style="display:none">
<div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-6 col-xl-4 mt-2">
<div class="card">
<div class="card-body">
<div class="float-end mt-2">
<div id="totalUserRadialChart" data-colors='["--bs-warning"]'></div>
</div>
<div>
<p class="text-muted mb-0">Total Users</p>
<h4 class="my-1">
<span id="spanTotalUserCount">XX</span>
</h4>
</div>
<p class="text-muted mt-3 mb-0" id="sectionUserCount"></p>
<div class="justify-content-center text-center chart-spinner" style="display:none">
<div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-6 col-xl-4 mt-2">
<div class="card">
<div class="card-body">
<div class="float-end mt-2">
<div id="totalRevenueRadialChart" data-colors='["#F0006B"]'></div>
</div>
<div>
<p class="text-muted mb-0">Total Revenue</p>
<h4 class="my-1">
<span id="spanTotalRevenueCount">XX</span>
</h4>
</div>
<p class="text-muted mt-3 mb-0" id="sectionRevenueCount"></p>
<div class="justify-content-center text-center chart-spinner" style="display:none">
<div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-12 col-xl-8 mt-2">
<div class="card">
<div class="card-body">
<div>
<p class="text-muted mb-0">New Members And Bookings In Past 30 Days</p>
</div>
<div id="newMembersAndBookingsLineChart" data-colors='["--bs-warning","--bs-primary"]'>
</div>
<div class="justify-content-center text-center chart-spinner" style="display:none">
<div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-12 col-xl-4 mt-2">
<div class="card">
<div class="card-body">
<div class="">
<p class="text-muted mb-0">Customer Bookings</p>
</div>
<div id="customerBookingsPieChart" data-colors='["--bs-warning","--bs-primary"]'>
</div>
<div class="justify-content-center text-center chart-spinner" style="display:none">
<div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@section scripts{
<script src="~/js/dashboard/radailChart.js"></script>
<script src="~/js/dashboard/getTotalBookingsRadial.js"></script>
<script src="~/js/dashboard/getTotalRevenueRadial.js"></script>
<script src="~/js/dashboard/getTotalUserRadial.js"></script>
<script src="~/js/dashboard/getCustomerBookingPieChart.js"></script>
<script src="~/js/dashboard/getCustomerAndBookingLineChart.js"></script>
}
+93
View File
@@ -0,0 +1,93 @@
@model HomeVM
<div>
<div id="carouselExampleIndicators" class="carousel slide">
<div class="carousel-indicators">
<button type="button" data-bs-target="#carouselExampleIndicators" data-bs-slide-to="0" class="active" aria-current="true" aria-label="Slide 1"></button>
<button type="button" data-bs-target="#carouselExampleIndicators" data-bs-slide-to="1" aria-label="Slide 2"></button>
<button type="button" data-bs-target="#carouselExampleIndicators" data-bs-slide-to="2" aria-label="Slide 3"></button>
</div>
<div class="carousel-inner">
<div class="carousel-item active">
<img src="~/images/slide2.jpg" class="d-block w-100" alt="...">
</div>
<div class="carousel-item">
<img src="~/images/slide1.jpg" class="d-block w-100" alt="...">
</div>
</div>
<button class="carousel-control-prev" type="button" data-bs-target="#carouselExampleIndicators" data-bs-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="visually-hidden">Previous</span>
</button>
<button class="carousel-control-next" type="button" data-bs-target="#carouselExampleIndicators" data-bs-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="visually-hidden">Next</span>
</button>
</div>
<form method="post"
asp-action="GetVillasByDate" >
<div class="row p-0 mx-0 py-4">
<div class="col-12 col-md-5 offset-md-1 pl-2 pr-2 pr-md-0">
<div class="form-group">
<label>Check In Date</label>
<input asp-for="CheckInDate" type="date" class="form-control" />
</div>
</div>
<div class="col-8 col-md-3 pl-2 pr-2">
<div class="form-group">
<label>No. of nights</label>
<select class="form-select" asp-for="Nights">
@for(var i = 1; i < 11; i++)
{
<option value="@i">@i</option>
}
</select>
</div>
</div>
<div class="col-4 col-md-2 pt-4 pr-2">
<div class="form-group">
<button type="button" onclick="fnLoadVillaList()" class="btn btn-success btn-block">
<i class="bi bi-search"></i> &nbsp; Check Availability
</button>
</div>
</div>
</div>
<partial name="_VillaList" model="Model"/>
</form>
</div>
@section scripts{
<script>
function fnLoadVillaList() {
$('.spinner').show();
var objData = {
checkInDate: $("#CheckInDate").val(),
nights: $("#Nights").val()
};
$.ajax({
type: "POST",
data:objData,
url: "@Url.Action("GetVillasByDate","Home")",
success: function (data) {
$("#VillasList").empty();
$("#VillasList").html(data);
$('.spinner').hide();
},
failure: function (response) {
$('.spinner').hide();
alert(response.responseText);
},
error: function (response) {
$('.spinner').hide();
alert(response.responseText);
}
});
}
</script>
}
@@ -0,0 +1,6 @@
@{
ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>
<p>Use this page to detail your site's privacy policy.</p>
@@ -0,0 +1,3 @@
<div class="container">
<img src="~/images/notfound.jpg" width="100%" />
</div>
@@ -0,0 +1,79 @@
<!DOCTYPE html>
<html lang="en" data-bs-theme="dark">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - WhiteLagoon.Web</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.1/css/bootstrap.min.css" integrity="sha512-Z/def5z5u2aR89OuzYcxmDJ0Bnd5V1cKqBEbvLOiUNWdg9PQeXVvXLI90SE4QOHGlfLqUnDNVAYyZi8UwUTmWQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
<link rel="stylesheet" href="~/WhiteLagoon.Web.styles.css" asp-append-version="true" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.css" integrity="sha512-3pIirOrwegjM6erE5gPSwkUzO+3cTjpnV9lexlNZqvupR64iZBnOOTiiLPb9M36zpMScbmUNIcHUqKD47M719g==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="stylesheet" href="~/css/spinner.css"/>
<link rel="stylesheet" href="//cdn.datatables.net/1.13.6/css/jquery.dataTables.min.css" />
</head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light border-bottom box-shadow">
<div class="container-fluid">
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index"><img src="~/images/resort.png" style="width:35px"/></a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" asp-controller="Booking" asp-action="Index">Manage Bookings</a>
</li>
</ul>
<div class="p-2 border rounded">
<div class="form-check form-switch" id="btnSwitch">
<input class="form-check-input" type="checkbox" role="switch" id="flexSwitchCheckDefault">
<label class="form-check-label" for="flexSwitchCheckDefault">Mode</label>
</div>
</div>
<partial name="_LoginPartial" />
</div>
</div>
</nav>
</header>
<div class="">
<main role="main">
<div class="loading spinner" style="display:none;"></div>
<partial name="_Notification" />
@RenderBody()
</main>
</div>
<footer class="border-top footer text-muted">
<div class="container text-center">
Made with <i class="bi bi-heart-fill"></i> by DotNetMastery
</div>
</footer>
@* jquery-ajax-unobtrusive@3.2.6 *@
<script type="text/javascript">
document.getElementById('btnSwitch').addEventListener('click', () => {
if (document.documentElement.getAttribute('data-bs-theme') == 'dark') {
document.documentElement.setAttribute('data-bs-theme', 'light')
}
else {
document.documentElement.setAttribute('data-bs-theme', 'dark')
}
})
</script>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.0.1/js/bootstrap.bundle.min.js" integrity="sha512-sH8JPhKJUeA9PWk3eOcOl8U+lfZTgtBXD41q6cO/slwxGHCxKcW45K4oPCUhHG7NMB4mbKEddVmPuTXtpbCbFA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
<script src="//cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js" asp-append-version="true"></script>
@* <script src="~/js/jquery.unobtrusive-ajax.min.js"></script> *@
@await RenderSectionAsync("Scripts", required: false)
</body>
</html>
@@ -0,0 +1,40 @@
/* Please see documentation at https://learn.microsoft.com/aspnet/core/client-side/bundling-and-minification
for details on configuring this project to bundle and minify static web assets. */
.btn-primary {
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
}
.nav-pills .nav-link.active, .nav-pills .show > .nav-link {
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
}
.border-top {
border-top: 1px solid #e5e5e5;
}
.border-bottom {
border-bottom: 1px solid #e5e5e5;
}
.box-shadow {
box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
}
button.accept-policy {
font-size: 1rem;
line-height: inherit;
}
.footer {
position: absolute;
bottom: 0;
width: 100%;
white-space: nowrap;
line-height: 60px;
}
@@ -0,0 +1,102 @@
<!DOCTYPE html>
<html lang="en" data-bs-theme="dark">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - WhiteLagoon.Web</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.1/css/bootstrap.min.css" integrity="sha512-Z/def5z5u2aR89OuzYcxmDJ0Bnd5V1cKqBEbvLOiUNWdg9PQeXVvXLI90SE4QOHGlfLqUnDNVAYyZi8UwUTmWQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
<link rel="stylesheet" href="~/WhiteLagoon.Web.styles.css" asp-append-version="true" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.css" integrity="sha512-3pIirOrwegjM6erE5gPSwkUzO+3cTjpnV9lexlNZqvupR64iZBnOOTiiLPb9M36zpMScbmUNIcHUqKD47M719g==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="stylesheet" href="~/css/spinner.css"/>
<link rel="stylesheet" href="//cdn.datatables.net/1.13.6/css/jquery.dataTables.min.css" />
<link rel="stylesheet" href="~/css/apexcharts.css" />
</head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light border-bottom box-shadow">
<div class="container-fluid d-flex justify-content-between">
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index"><img src="~/images/resort.png" style="width:35px"/></a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#sidebarMenu" aria-controls="sidebarMenu"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
</div>
<partial name="_LoginPartialAdmin" />
</nav>
</header>
<div class="container-fluid">
<div class="loading spinner" style="display:none;"></div>
<div class="row">
<nav id="sidebarMenu" class="col-md-3 col-lg-2 d-md-block bg-dark sidebar collapse">
<div class="position-static pt-3">
<ul class="navbar-nav">
<li>
<div class="text-muted small fw-bold text-uppercase px-3">
Menu
</div>
</li>
<li class="nav-item">
<a class="nav-link" asp-controller="Dashboard" asp-action="Index">
<span class="me-2"><i class="bi bi-speedometer2"></i></span>
<span>Dashboard</span>
</a>
</li>
<li>
<div class="text-muted small fw-bold text-uppercase px-3 mt-2">
Content Management
</div>
</li>
<li class="nav-item">
<a class="nav-link" asp-controller="Villa" asp-action="Index">
<span class="me-2"><i class="bi bi-house-door"></i></span>
<span>Villa</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" asp-controller="VillaNumber" asp-action="Index">
<span class="me-2"><i class="bi bi-list-ol"></i></i></span>
<span>VillaNumber</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" asp-controller="Amenity" asp-action="Index">
<span class="me-2"><i class="bi bi-building"></i></span>
<span>Amenity</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" asp-controller="Booking" asp-action="Index" asp-route-status="@SD.StatusApproved">
<span class="me-2"><i class="bi bi-journal-plus"></i></span>
<span>Booking</span>
</a>
</li>
</ul>
</div>
</nav>
<main class="col-md-9 ms-sm-auto col-lg-10 px-md-4">
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 w-100">
<partial name="_Notification" />
@RenderBody()
</div>
</main>
</div>
</div>
<footer class="border-top footer bg-dark text-muted">
<div class="container text-center">
Made with <i class="bi bi-heart-fill"></i> by DotNetMastery
</div>
</footer>
@* jquery-ajax-unobtrusive@3.2.6 *@
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.0.1/js/bootstrap.bundle.min.js" integrity="sha512-sH8JPhKJUeA9PWk3eOcOl8U+lfZTgtBXD41q6cO/slwxGHCxKcW45K4oPCUhHG7NMB4mbKEddVmPuTXtpbCbFA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
<script src="//cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js" asp-append-version="true"></script>
@* <script src="~/js/jquery.unobtrusive-ajax.min.js"></script> *@
<script src="~/js/apexcharts.js"></script>
@await RenderSectionAsync("Scripts", required: false)
</body>
</html>
@@ -0,0 +1,40 @@
/* Please see documentation at https://learn.microsoft.com/aspnet/core/client-side/bundling-and-minification
for details on configuring this project to bundle and minify static web assets. */
.btn-primary {
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
}
.nav-pills .nav-link.active, .nav-pills .show > .nav-link {
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
}
.border-top {
border-top: 1px solid #e5e5e5;
}
.border-bottom {
border-bottom: 1px solid #e5e5e5;
}
.box-shadow {
box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
}
button.accept-policy {
font-size: 1rem;
line-height: inherit;
}
.footer {
position: absolute;
bottom: 0;
width: 100%;
white-space: nowrap;
line-height: 60px;
}
@@ -0,0 +1,26 @@
@using Microsoft.AspNetCore.Identity
@inject SignInManager<ApplicationUser> SignInManager
@inject UserManager<ApplicationUser> UserManager
<ul class="navbar-nav">
@if (SignInManager.IsSignedIn(User))
{
<li class="nav-item">
<a class="nav-link" href="#">Hello @UserManager.GetUserName(User)</a>
</li>
<li class="nav-item">
<a class="nav-link" asp-controller="Account" asp-action="Logout">Logout</a>
</li>
}
else
{
<li class="nav-item">
<a class="nav-link" asp-controller="Account" asp-action="Register">Register</a>
</li>
<li class="nav-item">
<a class="nav-link" asp-controller="Account" asp-action="Login">Login</a>
</li>
}
</ul>
@@ -0,0 +1,17 @@
@using Microsoft.AspNetCore.Identity
@inject SignInManager<ApplicationUser> SignInManager
@inject UserManager<ApplicationUser> UserManager
<ul class="navbar-nav d-none d-md-flex nav-login">
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button"
data-bs-toggle="dropdown" aria-expanded="false">
Hello @UserManager.GetUserName(User)
</a>
<ul class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="nav-link text-center" asp-controller="Account" asp-action="Logout">Logout</a>
</ul>
</li>
</ul>
@@ -0,0 +1,16 @@
@if (TempData["error"] != null)
{
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js" integrity="sha512-VEd+nq25CkR676O+pLBnDW09R7VQX9Mdiij052gVCp5yVH3jGtH70Ho/UUv4mJDsEdTvqRCFZg0NKGiojGnUCw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script type="text/javascript">
toastr.error('@TempData["error"]');
</script>
}
@if (TempData["success"] != null)
{
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js" integrity="sha512-VEd+nq25CkR676O+pLBnDW09R7VQX9Mdiij052gVCp5yVH3jGtH70Ho/UUv4mJDsEdTvqRCFZg0NKGiojGnUCw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script type="text/javascript">
toastr.success('@TempData["success"]');
</script>
}
@@ -0,0 +1,2 @@
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
@@ -0,0 +1,39 @@
@model Villa
<div class="row">
<div class="col-12 col-md-5">
<img src="@Model.ImageUrl" style="border-radius:10px;" width="100%" />
</div>
<div class="col-12 col-md-7">
<div class="row p-2">
<div class="col-12">
<p class="card-title text-warning" style="font-size:xx-large">@Model.Name</p>
<p class="card-text" style="font-size:large">
@Html.Raw(Model.Description)
</p>
@if (Model.VillaAmenity != null && Model.VillaAmenity.Count() > 0)
{
<p class="h5 text-white">Villa Amenities</p>
<ul>
@foreach (var amenity in Model.VillaAmenity)
{
<li>@amenity.Name</li>
}
</ul>
}
</div>
</div>
<div class="row col-12">
<span class="text-end p-0 pt-3 m-0">
<span class="float-right">Max Occupancy : @Model.Occupancy adults </span><br />
<span class="float-right pt-1">Villa Size : @Model.Sqft sqft</span><br />
<p class="text-warning font-weight-bold pt-1">
USD
<span style=" #ff6a00">
@Model.Price.ToString("c") / night
</span>
</p>
</span>
</div>
</div>
</div>
@@ -0,0 +1,89 @@
@model HomeVM
<div id="VillasList">
<div class="row px-lg-5 m-lg-4 m-sm-0 px-sm-0" style="--bs-gutter-x:0">
@foreach (var villa in Model.VillaList)
{
<div class="p-4 col-md-12 col-lg-6">
<div class="row" style="border-radius:5px; border: 1px solid #aaa">
<div class="col-4 p-2">
<img class="d-block w-100" style="border-radius:5px;" src="@villa.ImageUrl">
</div>
<div class="col-8">
<div class="d-flex justify-content-between">
<p class="card-title text-warning" style="font-size:xx-large">@villa.Name</p>
<div class="pt-2">
<button type="button" class="btn btn-sm btn-outline-success" data-bs-toggle="modal" data-bs-target='#exampleModal-@(villa.Id)'>
Details
</button>
</div>
</div>
<p class="card-text">
@Html.Raw(villa.Description)
</p>
</div>
<div class="col-12">
<div class="row pb-3 pt-2">
<div class="col-4">
@if (Model.CheckInDate > DateOnly.FromDateTime(DateTime.Now))
{
if (villa.IsAvailable)
{
<a asp-controller="Booking" asp-action="FinalizeBooking"
asp-route-villaId="@villa.Id" asp-route-checkInDate="@Model.CheckInDate"
asp-route-nights="@Model.Nights"
class="btn btn-success form-control btn-block">
Book
</a>
}
else
{
<a class="btn btn-outline-danger disabled form-control btn-block">
Sold Out
</a>
}
}
</div>
<div class="col-4">
<span class="">Max Occupancy : @villa.Occupancy adults </span><br />
<span class=" pt-1">Villa Size : @villa.Sqft sqft</span><br />
</div>
<div class="col-4">
<span class="text-warning float-end font-weight-bold pt-1" style="font-size:25px;">
USD
<span style="border-bottom:1px solid #ff6a00">
@villa.Price.ToString("c")
</span>
</span>
</div>
</div>
</div>
</div>
</div>
<div class="modal fade" id="exampleModal-@(villa.Id)" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-xl" style="border: 1px solid #aaa; border-radius:7px;">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-3 text-success" id="exampleModalLabel">Villa Details</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body m-0">
<partial name="_VillaDetail" model="@villa" />
</div>
<div class="modal-footer">
<button asp-controller="Home" asp-action="GeneratePPTExport"
asp-route-id="@villa.Id" type="submit" class="btn btn-outline-warning">
<i class="bi bi-file-earmark-ppt"></i> Download Villa PPT
</button>
<button type="button" class="btn btn-outline-danger" data-bs-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
}
</div>
</div>
+68
View File
@@ -0,0 +1,68 @@
@model Villa
<div class="w-100 card border-0 p-4">
<div class="card-header bg-success bg-gradient ml-0 py-3">
<div class="row">
<div class="col-12 text-center">
<h2 class="text-white py-2">Create Villa</h2>
</div>
</div>
</div>
<div class="card-body border p-4">
<form method="post" class="row" enctype="multipart/form-data">
<div class="p-3">
@* <div asp-validation-summary="All"></div> *@
<div class="form-floating py-1 col-12">
<input asp-for="Name" class="form-control border shadow" />
<label asp-for="Name" class="ms-2"></label>
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-floating py-1 col-12">
<input asp-for="Description" class="form-control border shadow" />
<label asp-for="Description" class="ms-2"></label>
<span asp-validation-for="Description" class="text-danger"></span>
</div>
<div class="form-floating py-1 col-12">
<input asp-for="Price" class="form-control border shadow" />
<label asp-for="Price" class="ms-2"></label>
<span asp-validation-for="Price" class="text-danger"></span>
</div>
<div class="form-floating py-1 col-12">
<input asp-for="Sqft" class="form-control border shadow" />
<label asp-for="Sqft" class="ms-2"></label>
<span asp-validation-for="Sqft" class="text-danger"></span>
</div>
<div class="form-floating py-1 col-12">
<input asp-for="Occupancy" class="form-control border shadow" />
<label asp-for="Occupancy" class="ms-2"></label>
<span asp-validation-for="Occupancy" class="text-danger"></span>
</div>
<div class="form-floating py-1 col-12">
<input asp-for="ImageUrl" hidden class="form-control border shadow" />
<input asp-for="Image" class="form-control border shadow" />
<label asp-for="ImageUrl" class="ms-2 "></label>
<span asp-validation-for="ImageUrl" class="text-danger"></span>
</div>
<div class="row pt-2">
<div class="col-6 col-md-3">
<button type="submit" class="btn btn-success w-100">
<i class="bi bi-check-circle"></i> Create
</button>
</div>
<div class="col-6 col-md-3">
<a asp-controller="Villa" asp-action="Index" class="btn btn-secondary w-100">
<i class="bi bi-x-circle"></i> Cancel
</a>
</div>
</div>
</div>
</form>
</div>
</div>
@section Scripts{
@{
<partial name="_ValidationScriptsPartial" />
}
}
+67
View File
@@ -0,0 +1,67 @@
@model Villa
<div class="w-100 card border-0 p-4">
<div class="card-header bg-success bg-gradient ml-0 py-3">
<div class="row">
<div class="col-12 text-center">
<h2 class="text-white py-2">Delete Villa</h2>
</div>
</div>
</div>
<div class="card-body border p-4">
<form method="post" class="row">
<input asp-for="Id" hidden />
<div class="col-10">
<div class="p-3">
@* <div asp-validation-summary="All"></div> *@
<div class="form-floating py-1 col-12">
<input asp-for="Name" disabled class="form-control border shadow" />
<label asp-for="Name" class="ms-2"></label>
</div>
<div class="form-floating py-1 col-12">
<input asp-for="Description" disabled class="form-control border shadow" />
<label asp-for="Description" class="ms-2"></label>
</div>
<div class="form-floating py-1 col-12">
<input asp-for="Price" disabled class="form-control border shadow" />
<label asp-for="Price" class="ms-2"></label>
</div>
<div class="form-floating py-1 col-12">
<input asp-for="Sqft" disabled class="form-control border shadow" />
<label asp-for="Sqft" class="ms-2"></label>
</div>
<div class="form-floating py-1 col-12">
<input asp-for="Occupancy" disabled class="form-control border shadow" />
<label asp-for="Occupancy" class="ms-2"></label>
</div>
<div class="form-floating py-1 col-12">
<input asp-for="ImageUrl" disabled class="form-control border shadow" />
<label asp-for="ImageUrl" class="ms-2"></label>
</div>
<div class="row pt-2">
<div class="col-6 col-md-3">
<button type="submit" class="btn btn-danger w-100">
<i class="bi bi-trash-fill"></i> Delete
</button>
</div>
<div class="col-6 col-md-3">
<a asp-controller="Villa" asp-action="Index" class="btn btn-secondary w-100">
<i class="bi bi-x-circle"></i> Cancel
</a>
</div>
</div>
</div>
</div>
<div class="col-2">
<img src="@Model.ImageUrl" width="100%"
style="border-radius:5px; border:1px solid #bbb9b9" />
</div>
</form>
</div>
</div>
@section Scripts{
@{
<partial name="_ValidationScriptsPartial" />
}
}
+57
View File
@@ -0,0 +1,57 @@
@model IEnumerable<WhiteLagoon.Domain.Entities.Villa>
<div class="w-100 card border-0 p-4">
<div class="card-header bg-success bg-gradient ml-0 py-3">
<div class="row">
<div class="col-12 text-center">
<h2 class="text-white py-2">Villa List</h2>
</div>
</div>
</div>
<div class="card-body border p-4">
<div class="row pb-3">
<div class="col-6 offset-6 text-end">
<a asp-controller="Villa" asp-action="Create" class="btn btn-secondary">
<i class="bi bi-plus-circle"></i> Create New Villa
</a>
</div>
</div>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>
Name
</th>
<th>Price</th>
<th>Sqft</th>
<th>Occupancy</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var obj in Model)
{
<tr>
<td>@obj.Name</td>
<td>@obj.Price</td>
<td>@obj.Sqft</td>
<td>@obj.Occupancy</td>
<td>
<div class="w-75 btn-group" role="group">
<a asp-controller="Villa" asp-action="Update" asp-route-villaId="@obj.Id"
class="btn btn-success mx-2">
<i class="bi bi-pencil-square"></i> Edit
</a>
<a asp-controller="Villa" asp-action="Delete" asp-route-villaId="@obj.Id"
class="btn btn-danger mx-2">
<i class="bi bi-trash-fill"></i> Delete
</a>
</div>
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
+75
View File
@@ -0,0 +1,75 @@
@model Villa
<div class="w-100 card border-0 p-4">
<div class="card-header bg-success bg-gradient ml-0 py-3">
<div class="row">
<div class="col-12 text-center">
<h2 class="text-white py-2">Update Villa</h2>
</div>
</div>
</div>
<div class="card-body border p-4">
<form method="post" class="row" enctype="multipart/form-data">
<input asp-for="Id" hidden />
<div class="col-10">
<div class="p-3">
@* <div asp-validation-summary="All"></div> *@
<div class="form-floating py-1 col-12">
<input asp-for="Name" class="form-control border shadow" />
<label asp-for="Name" class="ms-2"></label>
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-floating py-1 col-12">
<input asp-for="Description" class="form-control border shadow" />
<label asp-for="Description" class="ms-2"></label>
<span asp-validation-for="Description" class="text-danger"></span>
</div>
<div class="form-floating py-1 col-12">
<input asp-for="Price" class="form-control border shadow" />
<label asp-for="Price" class="ms-2"></label>
<span asp-validation-for="Price" class="text-danger"></span>
</div>
<div class="form-floating py-1 col-12">
<input asp-for="Sqft" class="form-control border shadow" />
<label asp-for="Sqft" class="ms-2"></label>
<span asp-validation-for="Sqft" class="text-danger"></span>
</div>
<div class="form-floating py-1 col-12">
<input asp-for="Occupancy" class="form-control border shadow" />
<label asp-for="Occupancy" class="ms-2"></label>
<span asp-validation-for="Occupancy" class="text-danger"></span>
</div>
<div class="form-floating py-1 col-12">
<input asp-for="Image" class="form-control border shadow" />
<input asp-for="ImageUrl" hidden class="form-control border shadow" />
<label asp-for="ImageUrl" class="ms-2"></label>
<span asp-validation-for="ImageUrl" class="text-danger"></span>
</div>
<div class="row pt-2">
<div class="col-6 col-md-3">
<button type="submit" class="btn btn-success w-100">
<i class="bi bi-check-circle"></i> Update
</button>
</div>
<div class="col-6 col-md-3">
<a asp-controller="Villa" asp-action="Index" class="btn btn-secondary w-100">
<i class="bi bi-x-circle"></i> Cancel
</a>
</div>
</div>
</div>
</div>
<div class="col-2">
<img src="@Model.ImageUrl" width="100%"
style="border-radius:5px; border:1px solid #bbb9b9" />
</div>
</form>
</div>
</div>
@section Scripts{
@{
<partial name="_ValidationScriptsPartial" />
}
}
@@ -0,0 +1,54 @@
@model VillaNumberVM
<div class="w-100 card border-0 p-4">
<div class="card-header bg-success bg-gradient ml-0 py-3">
<div class="row">
<div class="col-12 text-center">
<h2 class="text-white py-2">Create Villa Number</h2>
</div>
</div>
</div>
<div class="card-body border p-4">
<form method="post" class="row">
<div class="p-3">
@* <div asp-validation-summary="All"></div> *@
<div class="form-floating py-1 col-12">
<select asp-for="@Model.VillaNumber.VillaId" asp-items="@Model.VillaList"
class="form-select border shadow">
<option disabled selected>--Select Villa--</option>
</select>
<label asp-for="VillaNumber.VillaId" class="ms-2"></label>
<span asp-validation-for="VillaNumber.VillaId" class="text-danger"></span>
</div>
<div class="form-floating py-1 col-12">
<input asp-for="VillaNumber.Villa_Number" class="form-control border shadow" />
<label asp-for="VillaNumber.Villa_Number" class="ms-2"></label>
<span asp-validation-for="VillaNumber.Villa_Number" class="text-danger"></span>
</div>
<div class="form-floating py-1 col-12">
<input asp-for="VillaNumber.SpecialDetails" class="form-control border shadow" />
<label asp-for="VillaNumber.SpecialDetails" class="ms-2"></label>
<span asp-validation-for="VillaNumber.SpecialDetails" class="text-danger"></span>
</div>
<div class="row pt-2">
<div class="col-6 col-md-3">
<button type="submit" class="btn btn-success w-100">
<i class="bi bi-check-circle"></i> Create
</button>
</div>
<div class="col-6 col-md-3">
<a asp-controller="VillaNumber" asp-action="Index" class="btn btn-secondary w-100">
<i class="bi bi-x-circle"></i> Cancel
</a>
</div>
</div>
</div>
</form>
</div>
</div>
@section Scripts{
@{
<partial name="_ValidationScriptsPartial" />
}
}
@@ -0,0 +1,55 @@
@model VillaNumberVM
<div class="w-100 card border-0 p-4">
<div class="card-header bg-success bg-gradient ml-0 py-3">
<div class="row">
<div class="col-12 text-center">
<h2 class="text-white py-2">Update Villa Number</h2>
</div>
</div>
</div>
<div class="card-body border p-4">
<form method="post" class="row">
<input asp-for="VillaNumber.Villa_Number" hidden />
<div class="p-3">
<div class="form-floating py-1 col-12">
<select disabled asp-for="@Model.VillaNumber.VillaId" asp-items="@Model.VillaList"
class="form-select border shadow">
<option disabled selected>--Select Villa--</option>
</select>
<label asp-for="VillaNumber.VillaId" class="ms-2"></label>
<span asp-validation-for="VillaNumber.VillaId" class="text-danger"></span>
</div>
<div class="form-floating py-1 col-12">
<input asp-for="VillaNumber.Villa_Number" disabled class="form-control border shadow" />
<label asp-for="VillaNumber.Villa_Number" class="ms-2"></label>
<span asp-validation-for="VillaNumber.Villa_Number" class="text-danger"></span>
</div>
<div class="form-floating py-1 col-12">
<input asp-for="VillaNumber.SpecialDetails" disabled class="form-control border shadow" />
<label asp-for="VillaNumber.SpecialDetails" class="ms-2"></label>
<span asp-validation-for="VillaNumber.SpecialDetails" class="text-danger"></span>
</div>
<div class="row pt-2">
<div class="col-6 col-md-3">
<button type="submit" class="btn btn-danger w-100">
<i class="bi bi-check-circle"></i> Delete
</button>
</div>
<div class="col-6 col-md-3">
<a asp-controller="VillaNumber" asp-action="Index" class="btn btn-secondary w-100">
<i class="bi bi-x-circle"></i> Cancel
</a>
</div>
</div>
</div>
</form>
</div>
</div>
@section Scripts{
@{
<partial name="_ValidationScriptsPartial" />
}
}
@@ -0,0 +1,55 @@
@model IEnumerable<VillaNumber>
<div class="w-100 card border-0 p-4">
<div class="card-header bg-success bg-gradient ml-0 py-3">
<div class="row">
<div class="col-12 text-center">
<h2 class="text-white py-2">Villa Number List</h2>
</div>
</div>
</div>
<div class="card-body border p-4">
<div class="row pb-3">
<div class="col-6 offset-6 text-end">
<a asp-controller="VillaNumber" asp-action="Create" class="btn btn-secondary">
<i class="bi bi-plus-circle"></i> Create New Villa Number
</a>
</div>
</div>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>
Villa Name
</th>
<th>Villa Number</th>
<th>Speical Details</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var obj in Model)
{
<tr>
<td>@obj.Villa.Name</td>
<td>@obj.Villa_Number</td>
<td>@obj.SpecialDetails</td>
<td>
<div class="w-75 btn-group" role="group">
<a asp-controller="VillaNumber" asp-action="Update" asp-route-villaNumberId="@obj.Villa_Number"
class="btn btn-success mx-2">
<i class="bi bi-pencil-square"></i> Edit
</a>
<a asp-controller="VillaNumber" asp-action="Delete" asp-route-villaNumberId="@obj.Villa_Number"
class="btn btn-danger mx-2">
<i class="bi bi-trash-fill"></i> Delete
</a>
</div>
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
@@ -0,0 +1,55 @@
@model VillaNumberVM
<div class="w-100 card border-0 p-4">
<div class="card-header bg-success bg-gradient ml-0 py-3">
<div class="row">
<div class="col-12 text-center">
<h2 class="text-white py-2">Update Villa Number</h2>
</div>
</div>
</div>
<div class="card-body border p-4">
<form method="post" class="row">
<input asp-for="VillaNumber.Villa_Number" hidden />
<div class="p-3">
<div class="form-floating py-1 col-12">
<select asp-for="@Model.VillaNumber.VillaId" asp-items="@Model.VillaList"
class="form-select border shadow">
<option disabled selected>--Select Villa--</option>
</select>
<label asp-for="VillaNumber.VillaId" class="ms-2"></label>
<span asp-validation-for="VillaNumber.VillaId" class="text-danger"></span>
</div>
<div class="form-floating py-1 col-12">
<input asp-for="VillaNumber.Villa_Number" disabled class="form-control border shadow" />
<label asp-for="VillaNumber.Villa_Number" class="ms-2"></label>
<span asp-validation-for="VillaNumber.Villa_Number" class="text-danger"></span>
</div>
<div class="form-floating py-1 col-12">
<input asp-for="VillaNumber.SpecialDetails" class="form-control border shadow" />
<label asp-for="VillaNumber.SpecialDetails" class="ms-2"></label>
<span asp-validation-for="VillaNumber.SpecialDetails" class="text-danger"></span>
</div>
<div class="row pt-2">
<div class="col-6 col-md-3">
<button type="submit" class="btn btn-success w-100">
<i class="bi bi-check-circle"></i> Update
</button>
</div>
<div class="col-6 col-md-3">
<a asp-controller="VillaNumber" asp-action="Index" class="btn btn-secondary w-100">
<i class="bi bi-x-circle"></i> Cancel
</a>
</div>
</div>
</div>
</form>
</div>
</div>
@section Scripts{
@{
<partial name="_ValidationScriptsPartial" />
}
}
@@ -0,0 +1,6 @@
@using WhiteLagoon.Web
@using WhiteLagoon.Web.Models
@using WhiteLagoon.Domain.Entities
@using WhiteLagoon.Web.ViewModels
@using WhiteLagoon.Application.Common.Utility
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
+8
View File
@@ -0,0 +1,8 @@
@if(User.IsInRole(SD.Role_Admin))
{
Layout = "_LayoutAdmin";
}
else
{
Layout = "_Layout";
}
+28
View File
@@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.0-preview.6.23329.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.0-preview.6.23329.4" />
<PackageReference Include="Stripe.net" Version="41.27.0" />
<PackageReference Include="Syncfusion.DocIO.Net.Core" Version="22.2.8" />
<PackageReference Include="Syncfusion.DocIORenderer.Net.Core" Version="22.2.8" />
<PackageReference Include="Syncfusion.Licensing" Version="22.2.8" />
<PackageReference Include="Syncfusion.Pdf.Net.Core" Version="22.2.8" />
<PackageReference Include="Syncfusion.Presentation.Net.Core" Version="22.2.8" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WhiteLagoon.Infrastructure\WhiteLagoon.Infrastructure.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="wwwroot\images\VillaImage\" />
<Folder Include="wwwroot\exports\" />
</ItemGroup>
</Project>
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
+22
View File
@@ -0,0 +1,22 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=WhiteLagoon;Trusted_Connection=True;TrustServerCertificate=True"
},
"Stripe": {
"SecretKey": "sk_test_51NcXISFiAM4djdaQCMdReHXvyGLRLB73zyRPt8R67JyStbyISjIMxhbVFYFEVrBN4UYjIJrhiwgBRRVteGnTkSpd00N5iMEtPw",
"PublishableKey": "pk_test_51NcXISFiAM4djdaQcnZBBwMWOXUD1FW4zUrcOfsMLwJwJR0djCIhKlDo21gauM7JnVAODa0t4rx2VOuaGz9rpVOX00k4NhOH9n"
},
"Syncfusion": {
"Licensekey": "Mgo+DSMBMAY9C3t2V1hhQlJAfV5AQmBIYVp/TGpJfl96cVxMZVVBJAtUQF1hSn5bd0FiWn1Zc3RQTmFd"
},
"SendGrid": {
"Key": "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"
}
}
+10
View File
@@ -0,0 +1,10 @@
{
"version": "1.0",
"defaultProvider": "jsdelivr",
"libraries": [
{
"library": "jquery-ajax-unobtrusive@3.2.6",
"destination": "wwwroot/jquery-ajax-unobtrusive/"
}
]
}
+585
View File
@@ -0,0 +1,585 @@
@keyframes opaque {
0% {
opacity: 0
}
to {
opacity: 1
}
}
@keyframes resizeanim {
0%,to {
opacity: 0
}
}
.apexcharts-canvas {
position: relative;
user-select: none
}
.apexcharts-canvas ::-webkit-scrollbar {
-webkit-appearance: none;
width: 6px
}
.apexcharts-canvas ::-webkit-scrollbar-thumb {
border-radius: 4px;
background-color: rgba(0,0,0,.5);
box-shadow: 0 0 1px rgba(255,255,255,.5);
-webkit-box-shadow: 0 0 1px rgba(255,255,255,.5)
}
.apexcharts-inner {
position: relative
}
.apexcharts-text tspan {
font-family: inherit
}
.legend-mouseover-inactive {
transition: .15s ease all;
opacity: .2
}
.apexcharts-legend-text {
padding-left: 15px;
margin-left: -15px;
}
.apexcharts-series-collapsed {
opacity: 0
}
.apexcharts-tooltip {
border-radius: 5px;
box-shadow: 2px 2px 6px -4px #999;
cursor: default;
font-size: 14px;
left: 62px;
opacity: 0;
pointer-events: none;
position: absolute;
top: 20px;
display: flex;
flex-direction: column;
overflow: hidden;
white-space: nowrap;
z-index: 12;
transition: .15s ease all
}
.apexcharts-tooltip.apexcharts-active {
opacity: 1;
transition: .15s ease all
}
.apexcharts-tooltip.apexcharts-theme-light {
border: 1px solid #e3e3e3;
background: rgba(255,255,255,.96)
}
.apexcharts-tooltip.apexcharts-theme-dark {
color: #fff;
background: rgba(30,30,30,.8)
}
.apexcharts-tooltip * {
font-family: inherit
}
.apexcharts-tooltip-title {
padding: 6px;
font-size: 15px;
margin-bottom: 4px
}
.apexcharts-tooltip.apexcharts-theme-light .apexcharts-tooltip-title {
background: #eceff1;
border-bottom: 1px solid #ddd
}
.apexcharts-tooltip.apexcharts-theme-dark .apexcharts-tooltip-title {
background: rgba(0,0,0,.7);
border-bottom: 1px solid #333
}
.apexcharts-tooltip-text-goals-value,.apexcharts-tooltip-text-y-value,.apexcharts-tooltip-text-z-value {
display: inline-block;
margin-left: 5px;
font-weight: 600
}
.apexcharts-tooltip-text-goals-label:empty,.apexcharts-tooltip-text-goals-value:empty,.apexcharts-tooltip-text-y-label:empty,.apexcharts-tooltip-text-y-value:empty,.apexcharts-tooltip-text-z-value:empty,.apexcharts-tooltip-title:empty {
display: none
}
.apexcharts-tooltip-text-goals-label,.apexcharts-tooltip-text-goals-value {
padding: 6px 0 5px
}
.apexcharts-tooltip-goals-group,.apexcharts-tooltip-text-goals-label,.apexcharts-tooltip-text-goals-value {
display: flex
}
.apexcharts-tooltip-text-goals-label:not(:empty),.apexcharts-tooltip-text-goals-value:not(:empty) {
margin-top: -6px
}
.apexcharts-tooltip-marker {
width: 12px;
height: 12px;
position: relative;
top: 0;
margin-right: 10px;
border-radius: 50%
}
.apexcharts-tooltip-series-group {
padding: 0 10px;
display: none;
text-align: left;
justify-content: left;
align-items: center
}
.apexcharts-tooltip-series-group.apexcharts-active .apexcharts-tooltip-marker {
opacity: 1
}
.apexcharts-tooltip-series-group.apexcharts-active,.apexcharts-tooltip-series-group:last-child {
padding-bottom: 4px
}
.apexcharts-tooltip-series-group-hidden {
opacity: 0;
height: 0;
line-height: 0;
padding: 0!important
}
.apexcharts-tooltip-y-group {
padding: 6px 0 5px
}
.apexcharts-custom-tooltip,.apexcharts-tooltip-box {
padding: 4px 8px
}
.apexcharts-tooltip-boxPlot {
display: flex;
flex-direction: column-reverse
}
.apexcharts-tooltip-box>div {
margin: 4px 0
}
.apexcharts-tooltip-box span.value {
font-weight: 700
}
.apexcharts-tooltip-rangebar {
padding: 5px 8px
}
.apexcharts-tooltip-rangebar .category {
font-weight: 600;
color: #777
}
.apexcharts-tooltip-rangebar .series-name {
font-weight: 700;
display: block;
margin-bottom: 5px
}
.apexcharts-xaxistooltip,.apexcharts-yaxistooltip {
opacity: 0;
pointer-events: none;
color: #373d3f;
font-size: 13px;
text-align: center;
border-radius: 2px;
position: absolute;
z-index: 10;
background: #eceff1;
border: 1px solid #90a4ae
}
.apexcharts-xaxistooltip {
padding: 9px 10px;
transition: .15s ease all
}
.apexcharts-xaxistooltip.apexcharts-theme-dark {
background: rgba(0,0,0,.7);
border: 1px solid rgba(0,0,0,.5);
color: #fff
}
.apexcharts-xaxistooltip:after,.apexcharts-xaxistooltip:before {
left: 50%;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none
}
.apexcharts-xaxistooltip:after {
border-color: transparent;
border-width: 6px;
margin-left: -6px
}
.apexcharts-xaxistooltip:before {
border-color: transparent;
border-width: 7px;
margin-left: -7px
}
.apexcharts-xaxistooltip-bottom:after,.apexcharts-xaxistooltip-bottom:before {
bottom: 100%
}
.apexcharts-xaxistooltip-top:after,.apexcharts-xaxistooltip-top:before {
top: 100%
}
.apexcharts-xaxistooltip-bottom:after {
border-bottom-color: #eceff1
}
.apexcharts-xaxistooltip-bottom:before {
border-bottom-color: #90a4ae
}
.apexcharts-xaxistooltip-bottom.apexcharts-theme-dark:after,.apexcharts-xaxistooltip-bottom.apexcharts-theme-dark:before {
border-bottom-color: rgba(0,0,0,.5)
}
.apexcharts-xaxistooltip-top:after {
border-top-color: #eceff1
}
.apexcharts-xaxistooltip-top:before {
border-top-color: #90a4ae
}
.apexcharts-xaxistooltip-top.apexcharts-theme-dark:after,.apexcharts-xaxistooltip-top.apexcharts-theme-dark:before {
border-top-color: rgba(0,0,0,.5)
}
.apexcharts-xaxistooltip.apexcharts-active {
opacity: 1;
transition: .15s ease all
}
.apexcharts-yaxistooltip {
padding: 4px 10px
}
.apexcharts-yaxistooltip.apexcharts-theme-dark {
background: rgba(0,0,0,.7);
border: 1px solid rgba(0,0,0,.5);
color: #fff
}
.apexcharts-yaxistooltip:after,.apexcharts-yaxistooltip:before {
top: 50%;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none
}
.apexcharts-yaxistooltip:after {
border-color: transparent;
border-width: 6px;
margin-top: -6px
}
.apexcharts-yaxistooltip:before {
border-color: transparent;
border-width: 7px;
margin-top: -7px
}
.apexcharts-yaxistooltip-left:after,.apexcharts-yaxistooltip-left:before {
left: 100%
}
.apexcharts-yaxistooltip-right:after,.apexcharts-yaxistooltip-right:before {
right: 100%
}
.apexcharts-yaxistooltip-left:after {
border-left-color: #eceff1
}
.apexcharts-yaxistooltip-left:before {
border-left-color: #90a4ae
}
.apexcharts-yaxistooltip-left.apexcharts-theme-dark:after,.apexcharts-yaxistooltip-left.apexcharts-theme-dark:before {
border-left-color: rgba(0,0,0,.5)
}
.apexcharts-yaxistooltip-right:after {
border-right-color: #eceff1
}
.apexcharts-yaxistooltip-right:before {
border-right-color: #90a4ae
}
.apexcharts-yaxistooltip-right.apexcharts-theme-dark:after,.apexcharts-yaxistooltip-right.apexcharts-theme-dark:before {
border-right-color: rgba(0,0,0,.5)
}
.apexcharts-yaxistooltip.apexcharts-active {
opacity: 1
}
.apexcharts-yaxistooltip-hidden {
display: none
}
.apexcharts-xcrosshairs,.apexcharts-ycrosshairs {
pointer-events: none;
opacity: 0;
transition: .15s ease all
}
.apexcharts-xcrosshairs.apexcharts-active,.apexcharts-ycrosshairs.apexcharts-active {
opacity: 1;
transition: .15s ease all
}
.apexcharts-ycrosshairs-hidden {
opacity: 0
}
.apexcharts-selection-rect {
cursor: move
}
.svg_select_boundingRect,.svg_select_points_rot {
pointer-events: none;
opacity: 0;
visibility: hidden
}
.apexcharts-selection-rect+g .svg_select_boundingRect,.apexcharts-selection-rect+g .svg_select_points_rot {
opacity: 0;
visibility: hidden
}
.apexcharts-selection-rect+g .svg_select_points_l,.apexcharts-selection-rect+g .svg_select_points_r {
cursor: ew-resize;
opacity: 1;
visibility: visible
}
.svg_select_points {
fill: #efefef;
stroke: #333;
rx: 2
}
.apexcharts-svg.apexcharts-zoomable.hovering-zoom {
cursor: crosshair
}
.apexcharts-svg.apexcharts-zoomable.hovering-pan {
cursor: move
}
.apexcharts-menu-icon,.apexcharts-pan-icon,.apexcharts-reset-icon,.apexcharts-selection-icon,.apexcharts-toolbar-custom-icon,.apexcharts-zoom-icon,.apexcharts-zoomin-icon,.apexcharts-zoomout-icon {
cursor: pointer;
width: 20px;
height: 20px;
line-height: 24px;
color: #6e8192;
text-align: center
}
.apexcharts-menu-icon svg,.apexcharts-reset-icon svg,.apexcharts-zoom-icon svg,.apexcharts-zoomin-icon svg,.apexcharts-zoomout-icon svg {
fill: #6e8192
}
.apexcharts-selection-icon svg {
fill: #444;
transform: scale(.76)
}
.apexcharts-theme-dark .apexcharts-menu-icon svg,.apexcharts-theme-dark .apexcharts-pan-icon svg,.apexcharts-theme-dark .apexcharts-reset-icon svg,.apexcharts-theme-dark .apexcharts-selection-icon svg,.apexcharts-theme-dark .apexcharts-toolbar-custom-icon svg,.apexcharts-theme-dark .apexcharts-zoom-icon svg,.apexcharts-theme-dark .apexcharts-zoomin-icon svg,.apexcharts-theme-dark .apexcharts-zoomout-icon svg {
fill: #f3f4f5
}
.apexcharts-canvas .apexcharts-reset-zoom-icon.apexcharts-selected svg,.apexcharts-canvas .apexcharts-selection-icon.apexcharts-selected svg,.apexcharts-canvas .apexcharts-zoom-icon.apexcharts-selected svg {
fill: #008ffb
}
.apexcharts-theme-light .apexcharts-menu-icon:hover svg,.apexcharts-theme-light .apexcharts-reset-icon:hover svg,.apexcharts-theme-light .apexcharts-selection-icon:not(.apexcharts-selected):hover svg,.apexcharts-theme-light .apexcharts-zoom-icon:not(.apexcharts-selected):hover svg,.apexcharts-theme-light .apexcharts-zoomin-icon:hover svg,.apexcharts-theme-light .apexcharts-zoomout-icon:hover svg {
fill: #333
}
.apexcharts-menu-icon,.apexcharts-selection-icon {
position: relative
}
.apexcharts-reset-icon {
margin-left: 5px
}
.apexcharts-menu-icon,.apexcharts-reset-icon,.apexcharts-zoom-icon {
transform: scale(.85)
}
.apexcharts-zoomin-icon,.apexcharts-zoomout-icon {
transform: scale(.7)
}
.apexcharts-zoomout-icon {
margin-right: 3px
}
.apexcharts-pan-icon {
transform: scale(.62);
position: relative;
left: 1px;
top: 0
}
.apexcharts-pan-icon svg {
fill: #fff;
stroke: #6e8192;
stroke-width: 2
}
.apexcharts-pan-icon.apexcharts-selected svg {
stroke: #008ffb
}
.apexcharts-pan-icon:not(.apexcharts-selected):hover svg {
stroke: #333
}
.apexcharts-toolbar {
position: absolute;
z-index: 11;
max-width: 176px;
text-align: right;
border-radius: 3px;
padding: 0 6px 2px;
display: flex;
justify-content: space-between;
align-items: center
}
.apexcharts-menu {
background: #fff;
position: absolute;
top: 100%;
border: 1px solid #ddd;
border-radius: 3px;
padding: 3px;
right: 10px;
opacity: 0;
min-width: 110px;
transition: .15s ease all;
pointer-events: none
}
.apexcharts-menu.apexcharts-menu-open {
opacity: 1;
pointer-events: all;
transition: .15s ease all
}
.apexcharts-menu-item {
padding: 6px 7px;
font-size: 12px;
cursor: pointer
}
.apexcharts-theme-light .apexcharts-menu-item:hover {
background: #eee
}
.apexcharts-theme-dark .apexcharts-menu {
background: rgba(0,0,0,.7);
color: #fff
}
@media screen and (min-width:768px) {
.apexcharts-canvas:hover .apexcharts-toolbar {
opacity: 1
}
}
.apexcharts-canvas .apexcharts-element-hidden,.apexcharts-datalabel.apexcharts-element-hidden,.apexcharts-hide .apexcharts-series-points {
opacity: 0
}
.apexcharts-hidden-element-shown {
opacity: 1;
transition: 0.25s ease all;
}
.apexcharts-datalabel,.apexcharts-datalabel-label,.apexcharts-datalabel-value,.apexcharts-datalabels,.apexcharts-pie-label {
cursor: default;
pointer-events: none
}
.apexcharts-pie-label-delay {
opacity: 0;
animation-name: opaque;
animation-duration: .3s;
animation-fill-mode: forwards;
animation-timing-function: ease
}
.apexcharts-annotation-rect,.apexcharts-area-series .apexcharts-area,.apexcharts-area-series .apexcharts-series-markers .apexcharts-marker.no-pointer-events,.apexcharts-gridline,.apexcharts-line,.apexcharts-line-series .apexcharts-series-markers .apexcharts-marker.no-pointer-events,.apexcharts-point-annotation-label,.apexcharts-radar-series path,.apexcharts-radar-series polygon,.apexcharts-toolbar svg,.apexcharts-tooltip .apexcharts-marker,.apexcharts-xaxis-annotation-label,.apexcharts-yaxis-annotation-label,.apexcharts-zoom-rect {
pointer-events: none
}
.apexcharts-marker {
transition: .15s ease all
}
.resize-triggers {
animation: 1ms resizeanim;
visibility: hidden;
opacity: 0;
height: 100%;
width: 100%;
overflow: hidden
}
.contract-trigger:before,.resize-triggers,.resize-triggers>div {
content: " ";
display: block;
position: absolute;
top: 0;
left: 0
}
.resize-triggers>div {
height: 100%;
width: 100%;
background: #eee;
overflow: auto
}
.contract-trigger:before {
overflow: hidden;
width: 200%;
height: 200%
}
+26
View File
@@ -0,0 +1,26 @@
html {
font-size: 14px;
}
@media (min-width: 768px) {
html {
font-size: 16px;
}
}
.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
}
html {
position: relative;
min-height: 100%;
}
body {
margin-bottom: 60px;
}
.dataTables_filter{
margin-bottom:20px;
}
+123
View File
@@ -0,0 +1,123 @@
/* Absolute Center Spinner */
.loading {
position: fixed;
z-index: 999;
overflow: show;
margin: auto;
top: 0;
left: 0;
bottom: 0;
right: 0;
width: 50px;
height: 50px;
}
/* Transparent Overlay */
.loading:before {
content: '';
display: block;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(255,255,255,0.5);
}
/* :not(:required) hides these rules from IE9 and below */
.loading:not(:required) {
/* hide "loading..." text */
font: 0/0 a;
color: transparent;
text-shadow: none;
background-color: transparent;
border: 0;
}
.loading:not(:required):after {
content: '';
display: block;
font-size: 10px;
width: 50px;
height: 50px;
margin-top: -0.5em;
border: 5px solid rgba(33, 150, 243, 1.0);
border-radius: 100%;
border-bottom-color: transparent;
-webkit-animation: spinner 1s linear 0s infinite;
animation: spinner 1s linear 0s infinite;
}
/* Animation */
@-webkit-keyframes spinner {
0% {
-webkit-transform: rotate(0deg);
-moz-transform: rotate(0deg);
-ms-transform: rotate(0deg);
-o-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
-moz-transform: rotate(360deg);
-ms-transform: rotate(360deg);
-o-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@-moz-keyframes spinner {
0% {
-webkit-transform: rotate(0deg);
-moz-transform: rotate(0deg);
-ms-transform: rotate(0deg);
-o-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
-moz-transform: rotate(360deg);
-ms-transform: rotate(360deg);
-o-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@-o-keyframes spinner {
0% {
-webkit-transform: rotate(0deg);
-moz-transform: rotate(0deg);
-ms-transform: rotate(0deg);
-o-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
-moz-transform: rotate(360deg);
-ms-transform: rotate(360deg);
-o-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes spinner {
0% {
-webkit-transform: rotate(0deg);
-moz-transform: rotate(0deg);
-ms-transform: rotate(0deg);
-o-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
-moz-transform: rotate(360deg);
-ms-transform: rotate(360deg);
-o-transform: rotate(360deg);
transform: rotate(360deg);
}
}
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 364 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 369 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 364 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 439 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 375 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

@@ -0,0 +1,12 @@
Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
these files except in compliance with the License. You may obtain a copy of the
License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.
@@ -0,0 +1,10 @@
jQuery Unobtrusive Ajax
=============================
The jQuery Unobtrusive Ajax library complements jQuery Ajax methods by adding support for specifying options for HTML replacement via Ajax calls as HTML5 `data-*` elements.
This project is part of ASP.NET Core. You can find samples, documentation and getting started instructions for ASP.NET Core at the [Home](https://github.com/aspnet/home) repo.
Remember to make your changes to only the src file. Use ".\build.cmd" to automatically generate the js file in dist directory, minify the js file, create a .nupkg and change the version in the package.json if needed.
To stage for a release, update the "version.props" file and run ".\build.cmd" (see Release Checklist [here](https://github.com/aspnet/jquery-ajax-unobtrusive/wiki/Release-checklist)).
@@ -0,0 +1,205 @@
// Unobtrusive Ajax support library for jQuery
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// @version v3.2.6
//
// Microsoft grants you the right to use these script files for the sole
// purpose of either: (i) interacting through your browser with the Microsoft
// website or online service, subject to the applicable licensing or use
// terms; or (ii) using the files as included with a Microsoft product subject
// to that product's license terms. Microsoft reserves all other rights to the
// files not expressly granted by Microsoft, whether by implication, estoppel
// or otherwise. Insofar as a script file is dual licensed under GPL,
// Microsoft neither took the code under GPL nor distributes it thereunder but
// under the terms set out in this paragraph. All notices and licenses
// below are for informational purposes only.
/*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */
/*global window: false, jQuery: false */
(function ($) {
var data_click = "unobtrusiveAjaxClick",
data_target = "unobtrusiveAjaxClickTarget",
data_validation = "unobtrusiveValidation";
function getFunction(code, argNames) {
var fn = window, parts = (code || "").split(".");
while (fn && parts.length) {
fn = fn[parts.shift()];
}
if (typeof (fn) === "function") {
return fn;
}
argNames.push(code);
return Function.constructor.apply(null, argNames);
}
function isMethodProxySafe(method) {
return method === "GET" || method === "POST";
}
function asyncOnBeforeSend(xhr, method) {
if (!isMethodProxySafe(method)) {
xhr.setRequestHeader("X-HTTP-Method-Override", method);
}
}
function asyncOnSuccess(element, data, contentType) {
var mode;
if (contentType.indexOf("application/x-javascript") !== -1) { // jQuery already executes JavaScript for us
return;
}
mode = (element.getAttribute("data-ajax-mode") || "").toUpperCase();
$(element.getAttribute("data-ajax-update")).each(function (i, update) {
var top;
switch (mode) {
case "BEFORE":
$(update).prepend(data);
break;
case "AFTER":
$(update).append(data);
break;
case "REPLACE-WITH":
$(update).replaceWith(data);
break;
default:
$(update).html(data);
break;
}
});
}
function asyncRequest(element, options) {
var confirm, loading, method, duration;
confirm = element.getAttribute("data-ajax-confirm");
if (confirm && !window.confirm(confirm)) {
return;
}
loading = $(element.getAttribute("data-ajax-loading"));
duration = parseInt(element.getAttribute("data-ajax-loading-duration"), 10) || 0;
$.extend(options, {
type: element.getAttribute("data-ajax-method") || undefined,
url: element.getAttribute("data-ajax-url") || undefined,
cache: (element.getAttribute("data-ajax-cache") || "").toLowerCase() === "true",
beforeSend: function (xhr) {
var result;
asyncOnBeforeSend(xhr, method);
result = getFunction(element.getAttribute("data-ajax-begin"), ["xhr"]).apply(element, arguments);
if (result !== false) {
loading.show(duration);
}
return result;
},
complete: function () {
loading.hide(duration);
getFunction(element.getAttribute("data-ajax-complete"), ["xhr", "status"]).apply(element, arguments);
},
success: function (data, status, xhr) {
asyncOnSuccess(element, data, xhr.getResponseHeader("Content-Type") || "text/html");
getFunction(element.getAttribute("data-ajax-success"), ["data", "status", "xhr"]).apply(element, arguments);
},
error: function () {
getFunction(element.getAttribute("data-ajax-failure"), ["xhr", "status", "error"]).apply(element, arguments);
}
});
options.data.push({ name: "X-Requested-With", value: "XMLHttpRequest" });
method = options.type.toUpperCase();
if (!isMethodProxySafe(method)) {
options.type = "POST";
options.data.push({ name: "X-HTTP-Method-Override", value: method });
}
// change here:
// Check for a Form POST with enctype=multipart/form-data
// add the input file that were not previously included in the serializeArray()
// set processData and contentType to false
var $element = $(element);
if ($element.is("form") && $element.attr("enctype") == "multipart/form-data") {
var formdata = new FormData();
$.each(options.data, function (i, v) {
formdata.append(v.name, v.value);
});
$("input[type=file]", $element).each(function () {
var file = this;
$.each(file.files, function (n, v) {
formdata.append(file.name, v);
});
});
$.extend(options, {
processData: false,
contentType: false,
data: formdata
});
}
// end change
$.ajax(options);
}
function validate(form) {
var validationInfo = $(form).data(data_validation);
return !validationInfo || !validationInfo.validate || validationInfo.validate();
}
$(document).on("click", "a[data-ajax=true]", function (evt) {
evt.preventDefault();
asyncRequest(this, {
url: this.href,
type: "GET",
data: []
});
});
$(document).on("click", "form[data-ajax=true] input[type=image]", function (evt) {
var name = evt.target.name,
target = $(evt.target),
form = $(target.parents("form")[0]),
offset = target.offset();
form.data(data_click, [
{ name: name + ".x", value: Math.round(evt.pageX - offset.left) },
{ name: name + ".y", value: Math.round(evt.pageY - offset.top) }
]);
setTimeout(function () {
form.removeData(data_click);
}, 0);
});
$(document).on("click", "form[data-ajax=true] :submit", function (evt) {
var name = evt.currentTarget.name,
target = $(evt.target),
form = $(target.parents("form")[0]);
form.data(data_click, name ? [{ name: name, value: evt.currentTarget.value }] : []);
form.data(data_target, target);
setTimeout(function () {
form.removeData(data_click);
form.removeData(data_target);
}, 0);
});
$(document).on("submit", "form[data-ajax=true]", function (evt) {
var clickInfo = $(this).data(data_click) || [],
clickTarget = $(this).data(data_target),
isCancel = clickTarget && (clickTarget.hasClass("cancel") || clickTarget.attr('formnovalidate') !== undefined);
evt.preventDefault();
if (!isCancel && !validate(this)) {
return;
}
asyncRequest(this, {
url: this.action,
type: this.method || "GET",
data: clickInfo.concat($(this).serializeArray())
});
});
}(jQuery));
@@ -0,0 +1,16 @@
// Unobtrusive Ajax support library for jQuery
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// @version v3.2.6
//
// Microsoft grants you the right to use these script files for the sole
// purpose of either: (i) interacting through your browser with the Microsoft
// website or online service, subject to the applicable licensing or use
// terms; or (ii) using the files as included with a Microsoft product subject
// to that product's license terms. Microsoft reserves all other rights to the
// files not expressly granted by Microsoft, whether by implication, estoppel
// or otherwise. Insofar as a script file is dual licensed under GPL,
// Microsoft neither took the code under GPL nor distributes it thereunder but
// under the terms set out in this paragraph. All notices and licenses
// below are for informational purposes only.
!function(t){function a(t,a){for(var e=window,r=(t||"").split(".");e&&r.length;)e=e[r.shift()];return"function"==typeof e?e:(a.push(t),Function.constructor.apply(null,a))}function e(t){return"GET"===t||"POST"===t}function r(t,a){e(a)||t.setRequestHeader("X-HTTP-Method-Override",a)}function n(a,e,r){var n;r.indexOf("application/x-javascript")===-1&&(n=(a.getAttribute("data-ajax-mode")||"").toUpperCase(),t(a.getAttribute("data-ajax-update")).each(function(a,r){switch(n){case"BEFORE":t(r).prepend(e);break;case"AFTER":t(r).append(e);break;case"REPLACE-WITH":t(r).replaceWith(e);break;default:t(r).html(e)}}))}function i(i,u){var o,c,d,s;if(o=i.getAttribute("data-ajax-confirm"),!o||window.confirm(o)){c=t(i.getAttribute("data-ajax-loading")),s=parseInt(i.getAttribute("data-ajax-loading-duration"),10)||0,t.extend(u,{type:i.getAttribute("data-ajax-method")||void 0,url:i.getAttribute("data-ajax-url")||void 0,cache:"true"===(i.getAttribute("data-ajax-cache")||"").toLowerCase(),beforeSend:function(t){var e;return r(t,d),e=a(i.getAttribute("data-ajax-begin"),["xhr"]).apply(i,arguments),e!==!1&&c.show(s),e},complete:function(){c.hide(s),a(i.getAttribute("data-ajax-complete"),["xhr","status"]).apply(i,arguments)},success:function(t,e,r){n(i,t,r.getResponseHeader("Content-Type")||"text/html"),a(i.getAttribute("data-ajax-success"),["data","status","xhr"]).apply(i,arguments)},error:function(){a(i.getAttribute("data-ajax-failure"),["xhr","status","error"]).apply(i,arguments)}}),u.data.push({name:"X-Requested-With",value:"XMLHttpRequest"}),d=u.type.toUpperCase(),e(d)||(u.type="POST",u.data.push({name:"X-HTTP-Method-Override",value:d}));var p=t(i);if(p.is("form")&&"multipart/form-data"==p.attr("enctype")){var f=new FormData;t.each(u.data,function(t,a){f.append(a.name,a.value)}),t("input[type=file]",p).each(function(){var a=this;t.each(a.files,function(t,e){f.append(a.name,e)})}),t.extend(u,{processData:!1,contentType:!1,data:f})}t.ajax(u)}}function u(a){var e=t(a).data(d);return!e||!e.validate||e.validate()}var o="unobtrusiveAjaxClick",c="unobtrusiveAjaxClickTarget",d="unobtrusiveValidation";t(document).on("click","a[data-ajax=true]",function(t){t.preventDefault(),i(this,{url:this.href,type:"GET",data:[]})}),t(document).on("click","form[data-ajax=true] input[type=image]",function(a){var e=a.target.name,r=t(a.target),n=t(r.parents("form")[0]),i=r.offset();n.data(o,[{name:e+".x",value:Math.round(a.pageX-i.left)},{name:e+".y",value:Math.round(a.pageY-i.top)}]),setTimeout(function(){n.removeData(o)},0)}),t(document).on("click","form[data-ajax=true] :submit",function(a){var e=a.currentTarget.name,r=t(a.target),n=t(r.parents("form")[0]);n.data(o,e?[{name:e,value:a.currentTarget.value}]:[]),n.data(c,r),setTimeout(function(){n.removeData(o),n.removeData(c)},0)}),t(document).on("submit","form[data-ajax=true]",function(a){var e=t(this).data(o)||[],r=t(this).data(c),n=r&&(r.hasClass("cancel")||void 0!==r.attr("formnovalidate"));a.preventDefault(),(n||u(this))&&i(this,{url:this.action,type:this.method||"GET",data:e.concat(t(this).serializeArray())})})}(jQuery);
@@ -0,0 +1,41 @@
{
"name": "jquery-ajax-unobtrusive",
"version": "3.2.6",
"description": "Add-on to jQuery Ajax to enable unobtrusive options in data-* attributes",
"main": "dist/jquery.unobtrusive-ajax.js",
"repository": {
"type": "git",
"url": "https://github.com/aspnet/jquery-ajax-unobtrusive"
},
"keywords": [
"unobtrusive",
"ajax",
"mvc",
"asp.net",
"jquery"
],
"author": "Microsoft",
"license": "https://aka.ms/jquery-ajax-license",
"bugs": {
"url": "https://github.com/aspnet/jquery-ajax-unobtrusive/issues"
},
"homepage": "https://github.com/aspnet/jquery-ajax-unobtrusive",
"files": [
"dist/jquery.unobtrusive-ajax.js",
"dist/jquery.unobtrusive-ajax.min.js"
],
"dependencies": {
"jquery": ">=1.8"
},
"devDependencies": {
"gulp": "^4.0.0",
"gulp-cli": "1.2.2",
"gulp-line-ending-corrector": "1.0.1",
"gulp-rename": "1.2.2",
"gulp-replace": "0.5.4",
"gulp-uglify": "2.0.0"
},
"scripts": {
"build": "npm install && gulp"
}
}
File diff suppressed because one or more lines are too long
+38
View File
@@ -0,0 +1,38 @@
var dataTable;
$(document).ready(function () {
const urlParams = new URLSearchParams(window.location.search);
const status = urlParams.get('status');
loadDataTable(status);
});
function loadDataTable(status) {
dataTable = $('#tblBookings').DataTable({
"ajax": {
url: '/booking/getall?status='+status
},
"columns": [
{ data: 'id', "width": "5%" },
{ data: 'name', "width": "15%" },
{ data: 'phone', "width": "10%" },
{ data: 'email', "width": "15%" },
{ data: 'status', "width": "10%" },
{ data: 'checkInDate', "width": "10%" },
{ data: 'nights', "width": "10%" },
{ data: 'totalCost', render: $.fn.dataTable.render.number(',', '.', 2) , "width": "10%" },
{
data: 'id',
"render": function (data) {
return `<div class="w-75 btn-group">
<a href="/booking/bookingDetails?bookingId=${data}" class="btn btn-outline-warning mx-2">
<i class="bi bi-pencil-square"></i> Details
</a>
</div>`
}
}
]
});
}
@@ -0,0 +1,80 @@
$(document).ready(function () {
loadCustomerAndBookingLineChart();
});
function loadCustomerAndBookingLineChart() {
$(".chart-spinner").show();
$.ajax({
url: "/Dashboard/GetMemberAndBookingLineChartData",
type: 'GET',
dataType: 'json',
success: function (data) {
loadLineChart("newMembersAndBookingsLineChart", data);
$(".chart-spinner").hide();
}
});
}
function loadLineChart(id, data) {
var chartColors = getChartColorsArray(id);
var options = {
colors: chartColors,
chart: {
height: 350,
//show area later
type: 'line',
zoom: {
type: 'x',
enabled: true,
autoScaleYaxis: true
},
},
stroke: {
curve: 'smooth',
width: 2
},
series: data.series,
dataLabels: {
enabled: false,
},
markers: {
size: 6,
strokeWidth: 0,
hover: {
size: 9
}
},
xaxis: {
categories: data.categories,
labels: {
style: {
colors: "#fff",
},
}
},
yaxis: {
labels: {
//formatter: function (val) {
// return val.toFixed(0);
//},
style: {
colors: "#fff",
},
}
},
legend: {
labels: {
colors: "#fff",
},
},
tooltip: {
theme: 'dark'
}
};
var chart = new ApexCharts(document.querySelector("#" + id), options);
chart.render();
}
@@ -0,0 +1,46 @@
$(document).ready(function () {
loadCustomerBookingPieChart();
});
function loadCustomerBookingPieChart() {
$(".chart-spinner").show();
$.ajax({
url: "/Dashboard/GetBookingPieChartData",
type: 'GET',
dataType: 'json',
success: function (data) {
loadPieChart("customerBookingsPieChart", data);
$(".chart-spinner").hide();
}
});
}
function loadPieChart(id, data) {
var chartColors = getChartColorsArray(id);
var options = {
colors: chartColors,
series: data.series,
labels: data.labels,
chart: {
width: 380,
type: 'pie',
},
stroke: {
show: false
},
legend: {
position: 'bottom',
horizontalAlign: 'center',
labels: {
colors: "#fff",
useSeriesColors: true
},
},
};
var chart = new ApexCharts(document.querySelector("#" + id), options);
chart.render();
}
@@ -0,0 +1,35 @@
$(document).ready(function () {
loadTotalBookingRadialChart();
});
function loadTotalBookingRadialChart() {
$(".chart-spinner").show();
$.ajax({
url: "/Dashboard/GetTotalBookingRadialChartData",
type: 'GET',
dataType: 'json',
success: function (data) {
document.querySelector("#spanTotalBookingCount").innerHTML = data.totalCount;
var sectionCurrentCount = document.createElement("span");
if (data.hasRatioIncreased) {
sectionCurrentCount.className = "text-success me-1";
sectionCurrentCount.innerHTML = '<i class="bi bi-arrow-up-right-circle me-1"></i> <span> ' + data.countInCurrentMonth + '</span>';
}
else {
sectionCurrentCount.className = "text-danger me-1";
sectionCurrentCount.innerHTML = '<i class="bi bi-arrow-down-right-circle me-1"></i> <span> ' + data.countInCurrentMonth + '</span>';
}
document.querySelector("#sectionBookingCount").append(sectionCurrentCount);
document.querySelector("#sectionBookingCount").append("since last month");
loadRadialBarChart("totalBookingsRadialChart", data);
$(".chart-spinner").hide();
}
});
}
@@ -0,0 +1,35 @@
$(document).ready(function () {
loadRevenueRadialChart();
});
function loadRevenueRadialChart() {
$(".chart-spinner").show();
$.ajax({
url: "/Dashboard/GetRevenueChartData",
type: 'GET',
dataType: 'json',
success: function (data) {
document.querySelector("#spanTotalRevenueCount").innerHTML = data.totalCount;
var sectionCurrentCount = document.createElement("span");
if (data.hasRatioIncreased) {
sectionCurrentCount.className = "text-success me-1";
sectionCurrentCount.innerHTML = '<i class="bi bi-arrow-up-right-circle me-1"></i> <span> ' + data.countInCurrentMonth + '</span>';
}
else {
sectionCurrentCount.className = "text-danger me-1";
sectionCurrentCount.innerHTML = '<i class="bi bi-arrow-down-right-circle me-1"></i> <span> ' + data.countInCurrentMonth + '</span>';
}
document.querySelector("#sectionRevenueCount").append(sectionCurrentCount);
document.querySelector("#sectionRevenueCount").append("since last month");
loadRadialBarChart("totalRevenueRadialChart", data);
$(".chart-spinner").hide();
}
});
}
@@ -0,0 +1,35 @@
$(document).ready(function () {
loadUserRadialChart();
});
function loadUserRadialChart() {
$(".chart-spinner").show();
$.ajax({
url: "/Dashboard/GetRegisteredUserChartData",
type: 'GET',
dataType: 'json',
success: function (data) {
document.querySelector("#spanTotalUserCount").innerHTML = data.totalCount;
var sectionCurrentCount = document.createElement("span");
if (data.hasRatioIncreased) {
sectionCurrentCount.className = "text-success me-1";
sectionCurrentCount.innerHTML = '<i class="bi bi-arrow-up-right-circle me-1"></i> <span> ' + data.countInCurrentMonth + '</span>';
}
else {
sectionCurrentCount.className = "text-danger me-1";
sectionCurrentCount.innerHTML = '<i class="bi bi-arrow-down-right-circle me-1"></i> <span> ' + data.countInCurrentMonth + '</span>';
}
document.querySelector("#sectionUserCount").append(sectionCurrentCount);
document.querySelector("#sectionUserCount").append("since last month");
loadRadialBarChart("totalUserRadialChart", data);
$(".chart-spinner").hide();
}
});
}
@@ -0,0 +1,52 @@
function loadRadialBarChart(id, data) {
var chartColors = getChartColorsArray(id);
var options = {
fill: {
colors: chartColors
},
chart: {
height: 90,
width: 90,
type: "radialBar",
sparkline: {
enabled: true
},
offsetY: -10,
},
series: data.series,
plotOptions: {
radialBar: {
dataLabels: {
value: {
offsetY: -10,
color: chartColors[0],
}
}
}
},
labels: [""]
};
var chart = new ApexCharts(document.querySelector("#" + id), options);
chart.render();
}
function getChartColorsArray(id) {
if (document.getElementById(id) !== null) {
var colors = document.getElementById(id).getAttribute("data-colors");
if (colors) {
colors = JSON.parse(colors);
return colors.map(function (value) {
var newValue = value.replace(" ", "");
if (newValue.indexOf(",") === -1) {
var color = getComputedStyle(document.documentElement).getPropertyValue(newValue);
if (color) return color;
else return newValue;
}
});
}
}
}
@@ -0,0 +1,16 @@
// Unobtrusive Ajax support library for jQuery
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// @version v3.2.6
//
// Microsoft grants you the right to use these script files for the sole
// purpose of either: (i) interacting through your browser with the Microsoft
// website or online service, subject to the applicable licensing or use
// terms; or (ii) using the files as included with a Microsoft product subject
// to that product's license terms. Microsoft reserves all other rights to the
// files not expressly granted by Microsoft, whether by implication, estoppel
// or otherwise. Insofar as a script file is dual licensed under GPL,
// Microsoft neither took the code under GPL nor distributes it thereunder but
// under the terms set out in this paragraph. All notices and licenses
// below are for informational purposes only.
!function(t){function a(t,a){for(var e=window,r=(t||"").split(".");e&&r.length;)e=e[r.shift()];return"function"==typeof e?e:(a.push(t),Function.constructor.apply(null,a))}function e(t){return"GET"===t||"POST"===t}function r(t,a){e(a)||t.setRequestHeader("X-HTTP-Method-Override",a)}function n(a,e,r){var n;r.indexOf("application/x-javascript")===-1&&(n=(a.getAttribute("data-ajax-mode")||"").toUpperCase(),t(a.getAttribute("data-ajax-update")).each(function(a,r){switch(n){case"BEFORE":t(r).prepend(e);break;case"AFTER":t(r).append(e);break;case"REPLACE-WITH":t(r).replaceWith(e);break;default:t(r).html(e)}}))}function i(i,u){var o,c,d,s;if(o=i.getAttribute("data-ajax-confirm"),!o||window.confirm(o)){c=t(i.getAttribute("data-ajax-loading")),s=parseInt(i.getAttribute("data-ajax-loading-duration"),10)||0,t.extend(u,{type:i.getAttribute("data-ajax-method")||void 0,url:i.getAttribute("data-ajax-url")||void 0,cache:"true"===(i.getAttribute("data-ajax-cache")||"").toLowerCase(),beforeSend:function(t){var e;return r(t,d),e=a(i.getAttribute("data-ajax-begin"),["xhr"]).apply(i,arguments),e!==!1&&c.show(s),e},complete:function(){c.hide(s),a(i.getAttribute("data-ajax-complete"),["xhr","status"]).apply(i,arguments)},success:function(t,e,r){n(i,t,r.getResponseHeader("Content-Type")||"text/html"),a(i.getAttribute("data-ajax-success"),["data","status","xhr"]).apply(i,arguments)},error:function(){a(i.getAttribute("data-ajax-failure"),["xhr","status","error"]).apply(i,arguments)}}),u.data.push({name:"X-Requested-With",value:"XMLHttpRequest"}),d=u.type.toUpperCase(),e(d)||(u.type="POST",u.data.push({name:"X-HTTP-Method-Override",value:d}));var p=t(i);if(p.is("form")&&"multipart/form-data"==p.attr("enctype")){var f=new FormData;t.each(u.data,function(t,a){f.append(a.name,a.value)}),t("input[type=file]",p).each(function(){var a=this;t.each(a.files,function(t,e){f.append(a.name,e)})}),t.extend(u,{processData:!1,contentType:!1,data:f})}t.ajax(u)}}function u(a){var e=t(a).data(d);return!e||!e.validate||e.validate()}var o="unobtrusiveAjaxClick",c="unobtrusiveAjaxClickTarget",d="unobtrusiveValidation";t(document).on("click","a[data-ajax=true]",function(t){t.preventDefault(),i(this,{url:this.href,type:"GET",data:[]})}),t(document).on("click","form[data-ajax=true] input[type=image]",function(a){var e=a.target.name,r=t(a.target),n=t(r.parents("form")[0]),i=r.offset();n.data(o,[{name:e+".x",value:Math.round(a.pageX-i.left)},{name:e+".y",value:Math.round(a.pageY-i.top)}]),setTimeout(function(){n.removeData(o)},0)}),t(document).on("click","form[data-ajax=true] :submit",function(a){var e=a.currentTarget.name,r=t(a.target),n=t(r.parents("form")[0]);n.data(o,e?[{name:e,value:a.currentTarget.value}]:[]),n.data(c,r),setTimeout(function(){n.removeData(o),n.removeData(c)},0)}),t(document).on("submit","form[data-ajax=true]",function(a){var e=t(this).data(o)||[],r=t(this).data(c),n=r&&(r.hasClass("cancel")||void 0!==r.attr("formnovalidate"));a.preventDefault(),(n||u(this))&&i(this,{url:this.action,type:this.method||"GET",data:e.concat(t(this).serializeArray())})})}(jQuery);
+4
View File
@@ -0,0 +1,4 @@
// Please see documentation at https://learn.microsoft.com/aspnet/core/client-side/bundling-and-minification
// for details on configuring this project to bundle and minify static web assets.
// Write your JavaScript code.
@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2011-2021 Twitter, Inc.
Copyright (c) 2011-2021 The Bootstrap Authors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More