added backend code for gas records.
This commit is contained in:
@@ -18,16 +18,24 @@ namespace CarCareTracker.Controllers
|
||||
private readonly IVehicleDataAccess _dataAccess;
|
||||
private readonly INoteDataAccess _noteDataAccess;
|
||||
private readonly IServiceRecordDataAccess _serviceRecordDataAccess;
|
||||
private readonly IGasRecordDataAccess _gasRecordDataAccess;
|
||||
private readonly IWebHostEnvironment _webEnv;
|
||||
private readonly IFileHelper _fileHelper;
|
||||
|
||||
public VehicleController(ILogger<HomeController> logger, IFileHelper fileHelper, IVehicleDataAccess dataAccess, INoteDataAccess noteDataAccess, IServiceRecordDataAccess serviceRecordDataAccess, IWebHostEnvironment webEnv)
|
||||
public VehicleController(ILogger<HomeController> logger,
|
||||
IFileHelper fileHelper,
|
||||
IVehicleDataAccess dataAccess,
|
||||
INoteDataAccess noteDataAccess,
|
||||
IServiceRecordDataAccess serviceRecordDataAccess,
|
||||
IGasRecordDataAccess gasRecordDataAccess,
|
||||
IWebHostEnvironment webEnv)
|
||||
{
|
||||
_logger = logger;
|
||||
_dataAccess = dataAccess;
|
||||
_noteDataAccess = noteDataAccess;
|
||||
_fileHelper = fileHelper;
|
||||
_serviceRecordDataAccess = serviceRecordDataAccess;
|
||||
_gasRecordDataAccess = gasRecordDataAccess;
|
||||
_webEnv = webEnv;
|
||||
}
|
||||
[HttpGet]
|
||||
@@ -64,6 +72,52 @@ namespace CarCareTracker.Controllers
|
||||
}
|
||||
return Json("");
|
||||
}
|
||||
#region "Gas Records"
|
||||
[HttpGet]
|
||||
public IActionResult GetGasRecordsByVehicleId(int vehicleId)
|
||||
{
|
||||
var result = _gasRecordDataAccess.GetGasRecordsByVehicleId(vehicleId);
|
||||
var computedResults = new List<GasRecordViewModel>();
|
||||
//perform computation.
|
||||
for(int i = 0; i < result.Count; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
var currentObject = result[i];
|
||||
var previousObject = result[i - 1];
|
||||
var deltaMileage = currentObject.Mileage - previousObject.Mileage;
|
||||
computedResults.Add(new GasRecordViewModel()
|
||||
{
|
||||
Id = currentObject.Id,
|
||||
VehicleId = currentObject.VehicleId,
|
||||
Date = currentObject.Date.ToShortDateString(),
|
||||
Mileage = currentObject.Mileage,
|
||||
Gallons = currentObject.Gallons,
|
||||
Cost = currentObject.Cost,
|
||||
DeltaMileage = deltaMileage,
|
||||
MilesPerGallon = deltaMileage / currentObject.Gallons,
|
||||
CostPerGallon = (currentObject.Cost / currentObject.Gallons)
|
||||
});
|
||||
} else
|
||||
{
|
||||
computedResults.Add(new GasRecordViewModel()
|
||||
{
|
||||
Id = result[i].Id,
|
||||
VehicleId = result[i].VehicleId,
|
||||
Date = result[i].Date.ToShortDateString(),
|
||||
Mileage = result[i].Mileage,
|
||||
Gallons = result[i].Gallons,
|
||||
Cost = result[i].Cost,
|
||||
DeltaMileage = 0,
|
||||
MilesPerGallon = 0,
|
||||
CostPerGallon = (result[i].Cost / result[i].Gallons)
|
||||
});
|
||||
}
|
||||
}
|
||||
return PartialView("_GasRecords", result);
|
||||
}
|
||||
#endregion
|
||||
#region "Service Records"
|
||||
[HttpGet]
|
||||
public IActionResult GetServiceRecordsByVehicleId(int vehicleId)
|
||||
{
|
||||
@@ -105,5 +159,7 @@ namespace CarCareTracker.Controllers
|
||||
var result = _serviceRecordDataAccess.DeleteServiceRecordById(serviceRecordId);
|
||||
return Json(result);
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
47
External/Implementations/GasRecordDataAccess.cs
vendored
Normal file
47
External/Implementations/GasRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
using CarCareTracker.External.Interfaces;
|
||||
using CarCareTracker.Models;
|
||||
using LiteDB;
|
||||
|
||||
namespace CarCareTracker.External.Implementations
|
||||
{
|
||||
public class GasRecordDataAccess: IGasRecordDataAccess
|
||||
{
|
||||
private static string dbName = "cartracker.db";
|
||||
private static string tableName = "gasrecords";
|
||||
public List<GasRecord> GetGasRecordsByVehicleId(int vehicleId)
|
||||
{
|
||||
using (var db = new LiteDatabase(dbName))
|
||||
{
|
||||
var table = db.GetCollection<GasRecord>(tableName);
|
||||
var gasRecords = table.Find(Query.EQ(nameof(GasRecord.VehicleId), vehicleId)).OrderBy(x => x.Date);
|
||||
return gasRecords.ToList() ?? new List<GasRecord>();
|
||||
};
|
||||
}
|
||||
public GasRecord GetGasRecordById(int gasRecordId)
|
||||
{
|
||||
using (var db = new LiteDatabase(dbName))
|
||||
{
|
||||
var table = db.GetCollection<GasRecord>(tableName);
|
||||
return table.FindById(gasRecordId);
|
||||
};
|
||||
}
|
||||
public bool DeleteGasRecordById(int gasRecordId)
|
||||
{
|
||||
using (var db = new LiteDatabase(dbName))
|
||||
{
|
||||
var table = db.GetCollection<GasRecord>(tableName);
|
||||
table.Delete(gasRecordId);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
public bool SaveGasRecordToVehicle(GasRecord gasRecord)
|
||||
{
|
||||
using (var db = new LiteDatabase(dbName))
|
||||
{
|
||||
var table = db.GetCollection<GasRecord>(tableName);
|
||||
table.Upsert(gasRecord);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
12
External/Interfaces/IGasRecordDataAccess.cs
vendored
Normal file
12
External/Interfaces/IGasRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
using CarCareTracker.Models;
|
||||
|
||||
namespace CarCareTracker.External.Interfaces
|
||||
{
|
||||
public interface IGasRecordDataAccess
|
||||
{
|
||||
public List<GasRecord> GetGasRecordsByVehicleId(int vehicleId);
|
||||
public GasRecord GetGasRecordById(int gasRecordId);
|
||||
public bool DeleteGasRecordById(int gasRecordId);
|
||||
public bool SaveGasRecordToVehicle(GasRecord gasRecord);
|
||||
}
|
||||
}
|
||||
19
Models/GasRecord.cs
Normal file
19
Models/GasRecord.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
namespace CarCareTracker.Models
|
||||
{
|
||||
public class GasRecord
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public int VehicleId { get; set; }
|
||||
public DateTime Date { get; set; }
|
||||
/// <summary>
|
||||
/// American moment
|
||||
/// </summary>
|
||||
public int Mileage { get; set; }
|
||||
/// <summary>
|
||||
/// Wtf is a kilometer?
|
||||
/// </summary>
|
||||
public decimal Gallons { get; set; }
|
||||
public decimal Cost { get; set; }
|
||||
public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>();
|
||||
}
|
||||
}
|
||||
20
Models/GasRecordInput.cs
Normal file
20
Models/GasRecordInput.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
namespace CarCareTracker.Models
|
||||
{
|
||||
public class GasRecordInput
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public int VehicleId { get; set; }
|
||||
public string Date { get; set; }
|
||||
/// <summary>
|
||||
/// American moment
|
||||
/// </summary>
|
||||
public int Mileage { get; set; }
|
||||
/// <summary>
|
||||
/// Wtf is a kilometer?
|
||||
/// </summary>
|
||||
public decimal Gallons { get; set; }
|
||||
public decimal Cost { get; set; }
|
||||
public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>();
|
||||
public GasRecord ToGasRecord() { return new GasRecord { Id = Id, Cost = Cost, Date = DateTime.Parse(Date), Gallons = Gallons, Mileage = Mileage, VehicleId = VehicleId, Files = Files }; }
|
||||
}
|
||||
}
|
||||
21
Models/GasRecordViewModel.cs
Normal file
21
Models/GasRecordViewModel.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
namespace CarCareTracker.Models
|
||||
{
|
||||
public class GasRecordViewModel
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public int VehicleId { get; set; }
|
||||
public string Date { get; set; }
|
||||
/// <summary>
|
||||
/// American moment
|
||||
/// </summary>
|
||||
public int Mileage { get; set; }
|
||||
/// <summary>
|
||||
/// Wtf is a kilometer?
|
||||
/// </summary>
|
||||
public decimal Gallons { get; set; }
|
||||
public decimal Cost { get; set; }
|
||||
public int DeltaMileage { get; set; }
|
||||
public decimal MilesPerGallon { get; set; }
|
||||
public decimal CostPerGallon { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ builder.Services.AddControllersWithViews();
|
||||
builder.Services.AddSingleton<IVehicleDataAccess, VehicleDataAccess>();
|
||||
builder.Services.AddSingleton<INoteDataAccess, NoteDataAccess>();
|
||||
builder.Services.AddSingleton<IServiceRecordDataAccess, ServiceRecordDataAccess>();
|
||||
builder.Services.AddSingleton<IGasRecordDataAccess, GasRecordDataAccess>();
|
||||
builder.Services.AddSingleton<IFileHelper, FileHelper>();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
54
Views/Vehicle/_Gas.cshtml
Normal file
54
Views/Vehicle/_Gas.cshtml
Normal file
@@ -0,0 +1,54 @@
|
||||
@model List<GasRecordViewModel>
|
||||
<div class="row">
|
||||
<div class="d-flex justify-content-between">
|
||||
<div class="d-flex align-items-center">
|
||||
<span class="ms-2 badge bg-success">@($"# of Gas Records: {Model.Count()}")</span>
|
||||
<span class="badge bg-primary">@($"Average MPG: {Model.Where(y=>y.MilesPerGallon > 0).Average(x => x.MilesPerGallon)}")</span>
|
||||
<span class="badge bg-primary">@($"Min MPG: {Model.Min(x => x.MilesPerGallon)}")</span>
|
||||
<span class="badge bg-primary">@($"Max MPG: {Model.Max(x => x.MilesPerGallon)}")</span>
|
||||
<span class="ms-2 badge bg-success">@($"Total Gallons: {Model.Sum(x=>x.Gallons)}")</span>
|
||||
<span class="ms-2 badge bg-success">@($"Total Cost: {Model.Sum(x => x.Cost).ToString("C")}")</span>
|
||||
</div>
|
||||
<div>
|
||||
<button onclick="showAddGasRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square"></i>Add Gas Record</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row vehicleDetailTabContainer">
|
||||
<div class="col-12">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr class="d-flex">
|
||||
<th scope="col" class="col-2">Date Refueled</th>
|
||||
<th scope="col" class="col-2">Mileage</th>
|
||||
<th scope="col" class="col-2">Gallons</th>
|
||||
<th scope="col" class="col-2">MPG</th>
|
||||
<th scope="col" class="col-2">Cost</th>
|
||||
<th scope="col" class="col-2">Unit Cost</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (GasRecordViewModel gasRecord in Model)
|
||||
{
|
||||
<tr class="d-flex" style="cursor:pointer;" onclick="">
|
||||
<td class="col-2">@gasRecord.Date</td>
|
||||
<td class="col-2">@gasRecord.Mileage</td>
|
||||
<td class="col-2">@gasRecord.Gallons</td>
|
||||
<td class="col-2">@gasRecord.MilesPerGallon</td>
|
||||
<td class="col-2">@gasRecord.Cost.ToString("C")</td>
|
||||
<td class="col-2">@gasRecord.CostPerGallon</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="modal fade" id="gasRecordModal" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content" id="gasRecordModalContent">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
77
Views/Vehicle/_GasModal.cshtml
Normal file
77
Views/Vehicle/_GasModal.cshtml
Normal file
@@ -0,0 +1,77 @@
|
||||
@model GasRecordInput
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">@(Model.Id == 0 ? "Add New Gas Record" : "Edit Gas Record")</h5>
|
||||
<button type="button" class="btn-close" onclick="hideAddGasRecordModal()" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-12">
|
||||
<input type="text" id="workAroundInput" style="height:0px; width:0px; display:none;">
|
||||
<label for="gasRecordDate">Date</label>
|
||||
<div class="input-group">
|
||||
<input type="text" id="gasRecordDate" class="form-control" value="@Model.Date">
|
||||
<span class="input-group-text"><i class="bi bi-calendar-event"></i></span>
|
||||
</div>
|
||||
<label for="gasRecordMileage">Mileage</label>
|
||||
<input type="number" id="gasRecordMileage" class="form-control" value="@Model.Mileage">
|
||||
<label for="gasRecordGallons">Gallons</label>
|
||||
<input type="text" id="gasRecordGallons" class="form-control" value="@Model.Gallons">
|
||||
<label for="GasRecordCost">Cost</label>
|
||||
<input type="number" id="gasRecordCost" class="form-control" value="@Model.Cost">
|
||||
</div>
|
||||
<div class="col-md-6 col-12">
|
||||
@if (Model.Files.Any())
|
||||
{
|
||||
<div>
|
||||
<label>Uploaded Documents</label>
|
||||
@foreach (UploadedFiles filesUploaded in Model.Files)
|
||||
{
|
||||
<div class="d-flex justify-content-between">
|
||||
<a type="button" class="btn btn-link" href="@filesUploaded.Location" target="_blank">@filesUploaded.Name</a>
|
||||
<button type="button" class="btn btn-sm btn-outline-danger" onclick="deleteGasRecordFile('@filesUploaded.Location', this)"><i class="bi bi-trash"></i></button>
|
||||
</div>
|
||||
}
|
||||
<label for="gasRecordFiles">Upload more documents</label>
|
||||
<input onChange="uploadServiceRecordFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="gasRecordFiles">
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<label for="gasRecordFiles">Upload documents(optional)</label>
|
||||
<input onChange="uploadServiceRecordFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="gasRecordFiles">
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
@if (Model.Id > 0)
|
||||
{
|
||||
<button type="button" class="btn btn-danger" onclick="deleteGasRecord(@Model.Id)" style="margin-right:auto;">Delete</button>
|
||||
}
|
||||
<button type="button" class="btn btn-secondary" onclick="hideAddGasRecordModal()">Cancel</button>
|
||||
@if (Model.Id == 0)
|
||||
{
|
||||
<button type="button" class="btn btn-primary" onclick="saveGasRecordToVehicle()">Add New Gas Record</button>
|
||||
}
|
||||
else if (Model.Id > 0)
|
||||
{
|
||||
<button type="button" class="btn btn-primary" onclick="saveGasRecordToVehicle(true)">Edit Gas Record</button>
|
||||
}
|
||||
</div>
|
||||
<script>
|
||||
var uploadedFiles = [];
|
||||
getUploadedFilesFromModel();
|
||||
function getUploadedFilesFromModel() {
|
||||
@foreach (UploadedFiles filesUploaded in Model.Files)
|
||||
{
|
||||
@:uploadedFiles.push({ name: "@filesUploaded.Name", location: "@filesUploaded.Location" });
|
||||
}
|
||||
}
|
||||
function getGasRecordModelData(){
|
||||
return {id: @Model.Id}
|
||||
}
|
||||
</script>
|
||||
@@ -1,6 +1,6 @@
|
||||
@model ServiceRecordInput
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="addServiceRecordModalLabel">@(Model.Id == 0 ? "Add New Service Record" : "Edit Service Record")</h5>
|
||||
<h5 class="modal-title">@(Model.Id == 0 ? "Add New Service Record" : "Edit Service Record")</h5>
|
||||
<button type="button" class="btn-close" onclick="hideAddServiceRecordModal()" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
@@ -36,13 +36,13 @@
|
||||
</div>
|
||||
}
|
||||
<label for="serviceRecordFiles">Upload more documents</label>
|
||||
<input onChange="uploadServiceRecordFilesAsync()" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="serviceRecordFiles">
|
||||
<input onChange="uploadServiceRecordFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="serviceRecordFiles">
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<label for="serviceRecordFiles">Upload documents(optional)</label>
|
||||
<input onChange="uploadServiceRecordFilesAsync()" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="serviceRecordFiles">
|
||||
<input onChange="uploadServiceRecordFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="serviceRecordFiles">
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
@@ -57,11 +57,11 @@
|
||||
<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>
|
||||
<button type="button" 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>
|
||||
<button type="button" class="btn btn-primary" onclick="saveServiceRecordToVehicle(true)">Edit Service Record</button>
|
||||
}
|
||||
</div>
|
||||
<script>
|
||||
|
||||
@@ -69,9 +69,9 @@ function saveServiceRecordToVehicle(isEdit) {
|
||||
}
|
||||
})
|
||||
}
|
||||
function uploadServiceRecordFilesAsync() {
|
||||
function uploadServiceRecordFilesAsync(event) {
|
||||
let formData = new FormData();
|
||||
var files = $("#serviceRecordFiles")[0].files;
|
||||
var files = event.files;
|
||||
for (var x = 0; x < files.length; x++) {
|
||||
formData.append("file", files[x]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user