Added loader and potential scaffolding for adding file attachments
This commit is contained in:
@@ -74,9 +74,15 @@ namespace CarCareTracker.Controllers
|
||||
return Json(result);
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GetServiceRecordById(int serviceRecordId)
|
||||
public IActionResult GetAddServiceRecordPartialView()
|
||||
{
|
||||
return PartialView("_ServiceRecordModal", new ServiceRecordInput());
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GetServiceRecordForEditById(int serviceRecordId)
|
||||
{
|
||||
var result = _serviceRecordDataAccess.GetServiceRecordById(serviceRecordId);
|
||||
//retrieve uploaded files.
|
||||
//convert to Input object.
|
||||
var convertedResult = new ServiceRecordInput { Id = result.Id,
|
||||
Cost = result.Cost,
|
||||
@@ -86,7 +92,7 @@ namespace CarCareTracker.Controllers
|
||||
Notes = result.Notes,
|
||||
VehicleId = result.VehicleId
|
||||
};
|
||||
return Json(convertedResult);
|
||||
return PartialView("_ServiceRecordModal", convertedResult);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult DeleteServiceRecordById(int serviceRecordId)
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
namespace CarCareTracker.Models
|
||||
{
|
||||
public class ServiceRecordInput
|
||||
public class ServiceRecord
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public int VehicleId { get; set; }
|
||||
public string Date { get; set; }
|
||||
public DateTime Date { get; set; }
|
||||
public int Mileage { get; set; }
|
||||
public string Description { get; set; }
|
||||
public decimal Cost { get; set; }
|
||||
public string Notes { get; set; }
|
||||
public ServiceRecord ToServiceRecord() { return new ServiceRecord { Id = Id, VehicleId = VehicleId, Date = DateTime.Parse(Date), Cost = Cost, Mileage = Mileage, Description = Description, Notes = Notes }; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
namespace CarCareTracker.Models
|
||||
{
|
||||
public class ServiceRecord
|
||||
public class ServiceRecordInput
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public int VehicleId { get; set; }
|
||||
public DateTime Date { get; set; }
|
||||
public string Date { get; set; }
|
||||
public int Mileage { get; set; }
|
||||
public string Description { get; set; }
|
||||
public decimal Cost { get; set; }
|
||||
public string Notes { get; set; }
|
||||
public List<string> Files { get; set; } = new List<string>();
|
||||
public ServiceRecord ToServiceRecord() { return new ServiceRecord { Id = Id, VehicleId = VehicleId, Date = DateTime.Parse(Date), Cost = Cost, Mileage = Mileage, Description = Description, Notes = Notes }; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,12 +8,14 @@
|
||||
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap-icons.css" />
|
||||
<link rel="stylesheet" href="~/lib/bootstrap-datepicker/css/bootstrap-datepicker.min.css" />
|
||||
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
|
||||
<link rel="stylesheet" href="~/css/loader.css" asp-append-version="true" />
|
||||
<link rel="stylesheet" href="~/sweetalert/sweetalert2.min.css" asp-append-version="true" />
|
||||
<script src="~/lib/jquery/dist/jquery.min.js"></script>
|
||||
<script src="~/js/shared.js"></script>
|
||||
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="~/lib/bootstrap-datepicker/js/bootstrap-datepicker.min.js"></script>
|
||||
<script src="~/sweetalert/sweetalert2.all.min.js"></script>
|
||||
<script src="~/js/loader.js"></script>
|
||||
@await RenderSectionAsync("Scripts", required: false)
|
||||
</head>
|
||||
<body>
|
||||
|
||||
89
Views/Vehicle/_ServiceRecordModal.cshtml
Normal file
89
Views/Vehicle/_ServiceRecordModal.cshtml
Normal file
@@ -0,0 +1,89 @@
|
||||
@model ServiceRecordInput
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="addServiceRecordModalLabel">@(Model.Id == 0 ? "Add New Service Record" : "Edit Service Record")</h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-12">
|
||||
<label for="serviceRecordDate">Date</label>
|
||||
<div class="input-group">
|
||||
<input type="text" id="serviceRecordDate" class="form-control" value="@Model.Date">
|
||||
<span class="input-group-text"><i class="bi bi-calendar-event"></i></span>
|
||||
</div>
|
||||
<label for="serviceRecordMileage">Mileage</label>
|
||||
<input type="number" id="serviceRecordMileage" class="form-control" value="@Model.Mileage">
|
||||
<label for="serviceRecordDescription">Description</label>
|
||||
<input type="text" id="serviceRecordDescription" class="form-control" value="@Model.Description">
|
||||
<label for="serviceRecordCost">Cost</label>
|
||||
<input type="number" id="serviceRecordCost" class="form-control" value="@Model.Cost">
|
||||
</div>
|
||||
<div class="col-md-6 col-12">
|
||||
<label for="serviceRecordNotes">Notes(optional)</label>
|
||||
<textarea id="serviceRecordNotes" class="form-control" rows="5">@Model.Notes</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
@if (Model.Id > 0)
|
||||
{
|
||||
<button type="button" class="btn btn-danger" onclick="deleteServiceRecord(@Model.Id)" style="margin-right:auto;">Delete</button>
|
||||
}
|
||||
<button type="button" class="btn btn-secondary" onclick="hideAddServiceRecordModal()">Cancel</button>
|
||||
@if (Model.Id == 0)
|
||||
{
|
||||
<button type="button" id="addServiceRecordButton" class="btn btn-primary" onclick="saveServiceRecordToVehicle()">Add New Service Record</button>
|
||||
} else if (Model.Id > 0)
|
||||
{
|
||||
<button type="button" id="editServiceRecordButton" class="btn btn-primary" onclick="saveServiceRecordToVehicle(true)">Edit Service Record</button>
|
||||
}
|
||||
</div>
|
||||
<script>
|
||||
function getAndValidateServiceRecordValues() {
|
||||
var serviceDate = $("#serviceRecordDate").val();
|
||||
var serviceMileage = $("#serviceRecordMileage").val();
|
||||
var serviceDescription = $("#serviceRecordDescription").val();
|
||||
var serviceCost = $("#serviceRecordCost").val();
|
||||
var serviceNotes = $("#serviceRecordNotes").val();
|
||||
var vehicleId = GetVehicleId().vehicleId;
|
||||
//validation
|
||||
var hasError = false;
|
||||
if (serviceDate.trim() == '' || !isDate(serviceDate)) { //eliminates whitespace.
|
||||
hasError = true;
|
||||
$("#serviceRecordDate").addClass("is-invalid");
|
||||
} else {
|
||||
$("#serviceRecordDate").removeClass("is-invalid");
|
||||
}
|
||||
if (serviceMileage.trim() == '' || parseInt(serviceMileage) < 0) {
|
||||
hasError = true;
|
||||
$("#serviceRecordMileage").addClass("is-invalid");
|
||||
} else {
|
||||
$("#serviceRecordMileage").removeClass("is-invalid");
|
||||
}
|
||||
if (serviceDescription.trim() == '') {
|
||||
hasError = true;
|
||||
$("#serviceRecordDescription").addClass("is-invalid");
|
||||
} else {
|
||||
$("#serviceRecordDescription").removeClass("is-invalid");
|
||||
}
|
||||
if (serviceCost.trim() == '') {
|
||||
hasError = true;
|
||||
$("#serviceRecordCost").addClass("is-invalid");
|
||||
} else {
|
||||
$("#serviceRecordCost").removeClass("is-invalid");
|
||||
}
|
||||
return {
|
||||
id: @Model.Id,
|
||||
hasError: hasError,
|
||||
vehicleId: vehicleId,
|
||||
date: serviceDate,
|
||||
mileage: serviceMileage,
|
||||
description: serviceDescription,
|
||||
cost: serviceCost,
|
||||
notes: serviceNotes
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -8,32 +8,25 @@
|
||||
</div>
|
||||
<div class="row vehicleDetailTabContainer">
|
||||
<div class="col-12">
|
||||
<table class="table">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr class="d-flex">
|
||||
<th scope="col" class="col-1">Date</th>
|
||||
<th scope="col" class="col-2">Mileage</th>
|
||||
<th scope="col" class="col-4">Description</th>
|
||||
<th scope="col" class="col-2">Cost</th>
|
||||
<th scope="col" class="col-2">Notes</th>
|
||||
<th scope="col" class="col-1">Actions</th>
|
||||
<th scope="col" class="col-3">Notes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (ServiceRecord serviceRecord in Model)
|
||||
{
|
||||
<tr class="d-flex">
|
||||
<tr class="d-flex" style="cursor:pointer;" onclick="showEditServiceRecordModal(@serviceRecord.Id)">
|
||||
<td class="col-1">@serviceRecord.Date.ToShortDateString()</td>
|
||||
<td class="col-2">@serviceRecord.Mileage</td>
|
||||
<td class="col-4">@serviceRecord.Description</td>
|
||||
<td class="col-2">@serviceRecord.Cost.ToString("C")</td>
|
||||
<td class="col-2 text-truncate" onclick="showServiceRecordNotes('@serviceRecord.Notes')" style="cursor:alias;">@serviceRecord.Notes</td>
|
||||
<td class="col-1">
|
||||
<div class="btn-group">
|
||||
<button onclick="showEditServiceRecordModal(@serviceRecord.Id)" class="btn btn-warning btn-sm"><i class="bi bi-pencil-square"></i></button>
|
||||
<button onclick="deleteServiceRecord(@serviceRecord.Id)" class="btn btn-danger btn-sm"><i class="bi bi-trash"></i></button>
|
||||
</div>
|
||||
</td>
|
||||
<td class="col-3 text-truncate">@serviceRecord.Notes</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
@@ -42,38 +35,10 @@
|
||||
</div>
|
||||
|
||||
|
||||
<div class="modal fade" id="addServiceRecordModal" tabindex="-1" role="dialog" aria-labelledby="addServiceRecordModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<form>
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="addServiceRecordModalLabel">Add New Service Record</h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label for="serviceRecordDate">Date</label>
|
||||
<div class="input-group">
|
||||
<input type="text" id="serviceRecordDate" class="form-control">
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text"><i class="bi bi-grid-3x3-gap"></i></span>
|
||||
</div>
|
||||
</div>
|
||||
<label for="serviceRecordMileage">Mileage</label>
|
||||
<input type="number" id="serviceRecordMileage" class="form-control">
|
||||
<label for="serviceRecordDescription">Description</label>
|
||||
<input type="text" id="serviceRecordDescription" class="form-control">
|
||||
<label for="serviceRecordCost">Cost</label>
|
||||
<input type="number" id="serviceRecordCost" class="form-control">
|
||||
<label for="serviceRecordNotes">Notes(optional)</label>
|
||||
<textarea id="serviceRecordNotes" class="form-control" rows="5"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" onclick="hideAddServiceRecordModal()">Cancel</button>
|
||||
<button type="button" id="addServiceRecordButton" class="btn btn-primary" onclick="addServiceRecordToVehicle()">Add New Service Record</button>
|
||||
<button type="button" id="editServiceRecordButton" class="btn btn-primary" onclick="editServiceRecordToVehicle()" style="display:none;">Edit Service Record</button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="modal fade" id="serviceRecordModal" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content" id="serviceRecordModalContent">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
55
wwwroot/css/loader.css
Normal file
55
wwwroot/css/loader.css
Normal file
@@ -0,0 +1,55 @@
|
||||
.sloader {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(255,255,255,0.5);
|
||||
}
|
||||
|
||||
.loader {
|
||||
display: block;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border: 3px solid white;
|
||||
border-radius: 50%;
|
||||
animation: spin 7s ease-in-out;
|
||||
animation-iteration-count: infinite;
|
||||
transition-duration: 0.1s;
|
||||
}
|
||||
|
||||
.loader:hover {
|
||||
scale: 0.95;
|
||||
/*Loader on hover effect*/
|
||||
}
|
||||
|
||||
.loader:active {
|
||||
scale: 2.5;
|
||||
/*Loader on click effect*/
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
border-bottom: solid 3px transparent;
|
||||
border-top: solid 3px transparent;
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: rotate(1800deg);
|
||||
border: 3px solid white;
|
||||
border-left: solid 3px transparent;
|
||||
border-right: solid 3px transparent;
|
||||
}
|
||||
|
||||
100% {
|
||||
/*Reversed spinning*/
|
||||
transform: rotate(0deg);
|
||||
border-bottom: solid 3px transparent;
|
||||
border-top: solid 3px transparent;
|
||||
}
|
||||
}
|
||||
10
wwwroot/js/loader.js
Normal file
10
wwwroot/js/loader.js
Normal file
@@ -0,0 +1,10 @@
|
||||
const sloader = {
|
||||
show: function () {
|
||||
var sLoaderElement = `<div class='sloader'><div class='loader'></div></div>`
|
||||
$("body").append(sLoaderElement);
|
||||
},
|
||||
hide: function () {
|
||||
$(".sloader").remove();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -27,12 +27,4 @@ function errorToast(message) {
|
||||
toast.onmouseleave = Swal.resumeTimer;
|
||||
}
|
||||
})
|
||||
}
|
||||
function genericSwal(title, message) {
|
||||
Swal.fire({
|
||||
showConfirmButton: true,
|
||||
title: title,
|
||||
text: message,
|
||||
icon: "info"
|
||||
})
|
||||
}
|
||||
@@ -43,10 +43,6 @@ function getVehicleServiceRecords(vehicleId) {
|
||||
$.get(`/Vehicle/GetServiceRecordsByVehicleId?vehicleId=${vehicleId}`, function (data) {
|
||||
if (data) {
|
||||
$("#servicerecord-tab-pane").html(data);
|
||||
//initiate datepicker
|
||||
$('#serviceRecordDate').datepicker({
|
||||
endDate: "+0d"
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -57,53 +53,32 @@ function DeleteVehicle(vehicleId) {
|
||||
}
|
||||
})
|
||||
}
|
||||
var serviceRecordEditId = 0;
|
||||
function showEditServiceRecordModal(serviceRecordId) {
|
||||
//retrieve service record object.
|
||||
$.get(`/Vehicle/GetServiceRecordById?serviceRecordId=${serviceRecordId}`, function (data) {
|
||||
function showAddServiceRecordModal() {
|
||||
$.get('/Vehicle/GetAddServiceRecordPartialView', function (data) {
|
||||
if (data) {
|
||||
//UI elements.
|
||||
$("#addServiceRecordButton").hide();
|
||||
$("#editServiceRecordButton").show();
|
||||
//pre-populate fields.
|
||||
$("#serviceRecordDate").val(data.date);
|
||||
$("#serviceRecordMileage").val(data.mileage);
|
||||
$("#serviceRecordDescription").val(data.description);
|
||||
$("#serviceRecordCost").val(data.cost);
|
||||
$("#serviceRecordNotes").val(data.notes);
|
||||
serviceRecordEditId = serviceRecordId; //set global var.
|
||||
$('#addServiceRecordModal').modal('show');
|
||||
$("#serviceRecordModalContent").html(data);
|
||||
//initiate datepicker
|
||||
$('#serviceRecordDate').datepicker({
|
||||
endDate: "+0d"
|
||||
});
|
||||
$('#serviceRecordModal').modal('show');
|
||||
}
|
||||
});
|
||||
}
|
||||
function showAddServiceRecordModal() {
|
||||
serviceRecordEditId = 0;
|
||||
$("#addServiceRecordButton").show();
|
||||
$("#editServiceRecordButton").hide();
|
||||
$('#addServiceRecordModal').modal('show');
|
||||
function showEditServiceRecordModal(serviceRecordId) {
|
||||
$.get(`/Vehicle/GetServiceRecordForEditById?serviceRecordId=${serviceRecordId}`, function (data) {
|
||||
if (data) {
|
||||
$("#serviceRecordModalContent").html(data);
|
||||
//initiate datepicker
|
||||
$('#serviceRecordDate').datepicker({
|
||||
endDate: "+0d"
|
||||
});
|
||||
$('#serviceRecordModal').modal('show');
|
||||
}
|
||||
});
|
||||
}
|
||||
function hideAddServiceRecordModal() {
|
||||
serviceRecordEditId = 0;
|
||||
$('#addServiceRecordModal').modal('hide');
|
||||
}
|
||||
function editServiceRecordToVehicle() {
|
||||
var formValues = getAndValidateServiceRecordValues();
|
||||
//validate
|
||||
if (formValues.hasError) {
|
||||
errorToast("Please check the form data");
|
||||
return;
|
||||
}
|
||||
//save to db.
|
||||
$.post('/Vehicle/SaveServiceRecordToVehicleId', { serviceRecord: formValues }, function (data) {
|
||||
if (data) {
|
||||
successToast("Service Record updated.");
|
||||
hideAddServiceRecordModal();
|
||||
getVehicleServiceRecords(formValues.vehicleId);
|
||||
serviceRecordEditId = 0; //reset global var.
|
||||
} else {
|
||||
errorToast("An error has occurred, please try again later.");
|
||||
}
|
||||
})
|
||||
$('#serviceRecordModal').modal('hide');
|
||||
}
|
||||
function deleteServiceRecord(serviceRecordId) {
|
||||
Swal.fire({
|
||||
@@ -116,6 +91,7 @@ function deleteServiceRecord(serviceRecordId) {
|
||||
if (result.isConfirmed) {
|
||||
$.post(`/Vehicle/DeleteServiceRecordById?serviceRecordId=${serviceRecordId}`, function (data) {
|
||||
if (data) {
|
||||
hideAddServiceRecordModal();
|
||||
successToast("Service Record deleted");
|
||||
var vehicleId = GetVehicleId().vehicleId;
|
||||
getVehicleServiceRecords(vehicleId);
|
||||
@@ -126,7 +102,7 @@ function deleteServiceRecord(serviceRecordId) {
|
||||
}
|
||||
});
|
||||
}
|
||||
function addServiceRecordToVehicle() {
|
||||
function saveServiceRecordToVehicle(isEdit) {
|
||||
//get values
|
||||
var formValues = getAndValidateServiceRecordValues();
|
||||
//validate
|
||||
@@ -137,61 +113,11 @@ function addServiceRecordToVehicle() {
|
||||
//save to db.
|
||||
$.post('/Vehicle/SaveServiceRecordToVehicleId', { serviceRecord: formValues }, function (data) {
|
||||
if (data) {
|
||||
successToast("Service Record added.");
|
||||
successToast(isEdit ? "Service Record Updated" : "Service Record Added.");
|
||||
hideAddServiceRecordModal();
|
||||
getVehicleServiceRecords(formValues.vehicleId);
|
||||
} else {
|
||||
errorToast("An error has occurred, please try again later.");
|
||||
}
|
||||
})
|
||||
}
|
||||
function getAndValidateServiceRecordValues() {
|
||||
var serviceDate = $("#serviceRecordDate").val();
|
||||
var serviceMileage = $("#serviceRecordMileage").val();
|
||||
var serviceDescription = $("#serviceRecordDescription").val();
|
||||
var serviceCost = $("#serviceRecordCost").val();
|
||||
var serviceNotes = $("#serviceRecordNotes").val();
|
||||
var vehicleId = GetVehicleId().vehicleId;
|
||||
//validation
|
||||
var hasError = false;
|
||||
if (serviceDate.trim() == '') { //eliminates whitespace.
|
||||
hasError = true;
|
||||
$("#serviceRecordDate").addClass("is-invalid");
|
||||
} else {
|
||||
$("#serviceRecordDate").removeClass("is-invalid");
|
||||
}
|
||||
if (serviceMileage.trim() == '' || parseInt(serviceMileage) < 0) {
|
||||
hasError = true;
|
||||
$("#serviceRecordMileage").addClass("is-invalid");
|
||||
} else {
|
||||
$("#serviceRecordMileage").removeClass("is-invalid");
|
||||
}
|
||||
if (serviceDescription.trim() == '') {
|
||||
hasError = true;
|
||||
$("#serviceRecordDescription").addClass("is-invalid");
|
||||
} else {
|
||||
$("#serviceRecordDescription").removeClass("is-invalid");
|
||||
}
|
||||
if (serviceCost.trim() == '') {
|
||||
hasError = true;
|
||||
$("#serviceRecordCost").addClass("is-invalid");
|
||||
} else {
|
||||
$("#serviceRecordCost").removeClass("is-invalid");
|
||||
}
|
||||
return {
|
||||
id: serviceRecordEditId,
|
||||
hasError: hasError,
|
||||
vehicleId: vehicleId,
|
||||
date: serviceDate,
|
||||
mileage: serviceMileage,
|
||||
description: serviceDescription,
|
||||
cost: serviceCost,
|
||||
notes: serviceNotes
|
||||
}
|
||||
}
|
||||
function showServiceRecordNotes(note) {
|
||||
if (note.trim() == '') {
|
||||
return;
|
||||
}
|
||||
genericSwal("Note", note);
|
||||
}
|
||||
Reference in New Issue
Block a user