added backend code for gas records.

This commit is contained in:
ivancheahhh
2024-01-02 16:55:12 -07:00
parent 8ea619d253
commit 943dee8d74
11 changed files with 315 additions and 8 deletions

View File

@@ -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
}
}

View 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;
};
}
}
}

View 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
View 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
View 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 }; }
}
}

View 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; }
}
}

View File

@@ -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
View 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>

View 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>

View File

@@ -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>

View File

@@ -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]);
}