Merge branch 'main' into Hargata/users

# Conflicts:
#	Views/Vehicle/Index.cshtml
This commit is contained in:
DESKTOP-T0O5CDB\DESK-555BD
2024-01-14 13:08:37 -07:00
13 changed files with 153 additions and 10 deletions

View File

@@ -34,15 +34,23 @@ namespace CarCareTracker.Controllers
var result = _loginLogic.GenerateUserToken(emailAddress, autoNotify);
return Json(result);
}
[HttpPost]
public IActionResult DeleteToken(int tokenId)
{
var result = _loginLogic.DeleteUserToken(tokenId);
return Json(result);
}
[HttpPost]
public IActionResult DeleteUser(int userId)
{
var result =_userLogic.DeleteAllAccessToUser(userId) && _configHelper.DeleteUserConfig(userId) && _loginLogic.DeleteUser(userId);
return Json(result);
}
[HttpPost]
public IActionResult UpdateUserAdminStatus(int userId, bool isAdmin)
{
var result = _loginLogic.MakeUserAdmin(userId, isAdmin);
return Json(result);
}
}
}

View File

@@ -678,6 +678,16 @@ namespace CarCareTracker.Controllers
//get collaborators
var collaborators = _userLogic.GetCollaboratorsForVehicle(vehicleId);
viewModel.Collaborators = collaborators;
//get MPG per month.
var userConfig = _config.GetUserConfig(User);
var mileageData = _gasHelper.GetGasRecordViewModels(gasRecords, userConfig.UseMPG, userConfig.UseUKMPG);
mileageData.RemoveAll(x => x.MilesPerGallon == default);
var monthlyMileageData = mileageData.GroupBy(x=>x.MonthId).OrderBy(x => x.Key).Select(x => new CostForVehicleByMonth
{
MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(x.Key),
Cost = x.Average(y=>y.MilesPerGallon)
}).ToList();
viewModel.FuelMileageForVehicleByMonth = monthlyMileageData;
return PartialView("_Report", viewModel);
}
[TypeFilter(typeof(CollaboratorFilter))]
@@ -807,6 +817,25 @@ namespace CarCareTracker.Controllers
}
[TypeFilter(typeof(CollaboratorFilter))]
[HttpPost]
public IActionResult GetMonthMPGByVehicle(int vehicleId, int year = 0)
{
var gasRecords = _gasRecordDataAccess.GetGasRecordsByVehicleId(vehicleId);
var userConfig = _config.GetUserConfig(User);
var mileageData = _gasHelper.GetGasRecordViewModels(gasRecords, userConfig.UseMPG, userConfig.UseUKMPG);
if (year != 0)
{
mileageData.RemoveAll(x => DateTime.Parse(x.Date).Year != year);
}
mileageData.RemoveAll(x => x.MilesPerGallon == default);
var monthlyMileageData = mileageData.GroupBy(x => x.MonthId).OrderBy(x => x.Key).Select(x => new CostForVehicleByMonth
{
MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(x.Key),
Cost = x.Average(y => y.MilesPerGallon)
}).ToList();
return PartialView("_MPGByMonthReport", monthlyMileageData);
}
[TypeFilter(typeof(CollaboratorFilter))]
[HttpPost]
public IActionResult GetCostByMonthByVehicle(int vehicleId, List<ImportMode> selectedMetrics, int year = 0)
{
List<CostForVehicleByMonth> allCosts = new List<CostForVehicleByMonth>();

View File

@@ -36,6 +36,7 @@ namespace CarCareTracker.Helper
{
Id = currentObject.Id,
VehicleId = currentObject.VehicleId,
MonthId = currentObject.Date.Month,
Date = currentObject.Date.ToShortDateString(),
Mileage = currentObject.Mileage,
Gallons = convertedConsumption,
@@ -73,6 +74,7 @@ namespace CarCareTracker.Helper
{
Id = currentObject.Id,
VehicleId = currentObject.VehicleId,
MonthId = currentObject.Date.Month,
Date = currentObject.Date.ToShortDateString(),
Mileage = currentObject.Mileage,
Gallons = convertedConsumption,

View File

@@ -12,6 +12,7 @@ namespace CarCareTracker.Logic
{
public interface ILoginLogic
{
bool MakeUserAdmin(int userId, bool isAdmin);
OperationResponse GenerateUserToken(string emailAddress, bool autoNotify);
bool DeleteUserToken(int tokenId);
bool DeleteUser(int userId);
@@ -193,6 +194,17 @@ namespace CarCareTracker.Logic
}
}
#region "Admin Functions"
public bool MakeUserAdmin(int userId, bool isAdmin)
{
var user = _userData.GetUserRecordById(userId);
if (user == default)
{
return false;
}
user.IsAdmin = isAdmin;
var result = _userData.SaveUserRecord(user);
return result;
}
public List<UserData> GetAllUsers()
{
var result = _userData.GetUsers();

View File

@@ -9,7 +9,7 @@ namespace CarCareTracker.MapProfile
{
Map(m => m.Date).Name(["date", "fuelup_date"]);
Map(m => m.Odometer).Name(["odometer"]);
Map(m => m.FuelConsumed).Name(["gallons", "liters", "litres", "consumption", "quantity", "fueleconomy"]);
Map(m => m.FuelConsumed).Name(["gallons", "liters", "litres", "consumption", "quantity", "fueleconomy", "fuelconsumed"]);
Map(m => m.Cost).Name(["cost", "total cost", "totalcost", "total price"]);
Map(m => m.Notes).Name("notes", "note");
Map(m => m.Price).Name(["price"]);

View File

@@ -4,6 +4,7 @@
{
public int Id { get; set; }
public int VehicleId { get; set; }
public int MonthId { get; set; }
public string Date { get; set; }
/// <summary>
/// American moment

View File

@@ -3,6 +3,7 @@
public class ReportViewModel
{
public List<CostForVehicleByMonth> CostForVehicleByMonth { get; set; } = new List<CostForVehicleByMonth>();
public List<CostForVehicleByMonth> FuelMileageForVehicleByMonth { get; set; } = new List<CostForVehicleByMonth>();
public CostMakeUpForVehicle CostMakeUpForVehicle { get; set; } = new CostMakeUpForVehicle();
public ReminderMakeUpForVehicle ReminderMakeUpForVehicle { get; set; } = new ReminderMakeUpForVehicle();
public List<int> Years { get; set; } = new List<int>();

View File

@@ -76,7 +76,7 @@
<tr class="d-flex" style="cursor:pointer;">
<td class="col-4">@userData.UserName</td>
<td class="col-4">@userData.EmailAddress</td>
<td class="col-2">@userData.Id</td>
<td class="col-2"><input class="form-check-input" type="checkbox" value="" onchange="updateUserAdmin(@userData.Id, this)" @(userData.IsAdmin ? "checked" : "")/></td>
<td class="col-2"><button type="button" class="btn btn-danger" onclick="deleteUser(@userData.Id, this)"><i class="bi bi-trash"></i></button></td>
</tr>
}
@@ -86,7 +86,16 @@
</div>
</div>
<script>
function updateUserAdmin(userId, sender){
var isChecked = $(sender).is(":checked");
$.post('/Admin/UpdateUserAdminStatus', { userId: userId, isAdmin: isChecked }, function (data) {
if (data){
reloadPage();
} else {
errorToast("An error has occurred, please try again later.");
}
});
}
function reloadPage() {
window.location.reload();
}
@@ -94,6 +103,8 @@
$.post(`/Admin/DeleteToken?tokenId=${tokenId}`, function (data) {
if (data) {
reloadPage();
} else {
errorToast("An error has occurred, please try again later.");
}
});
}
@@ -101,6 +112,8 @@
$.post(`/Admin/DeleteUser?userId=${userId}`, function (data) {
if (data) {
reloadPage();
} else {
errorToast("An error has occurred, please try again later.");
}
})
}

View File

@@ -19,6 +19,9 @@
<li class="nav-item" role="presentation">
<button class="nav-link" onclick="returnToGarage()"><span class="display-3 ms-2"><i class="bi bi-arrow-left-square"></i>Garage</span></button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" onclick="editVehicle(@Model.Id)"><span class="display-3 ms-2"><i class="bi bi-pencil-square"></i>Edit Vehicle</span></button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link active" id="report-tab" data-bs-toggle="tab" data-bs-target="#report-tab-pane" type="button" role="tab" aria-selected="false"><span class="display-3 ms-2"><i class="bi bi-file-bar-graph me-2"></i>Dashboard</span></button>
</li>

View File

@@ -0,0 +1,58 @@
@model List<CostForVehicleByMonth>
@if (Model.Any())
{
<canvas id="bar-chart-mpg"></canvas>
<script>
renderChart();
function renderChart() {
var barGraphLabels = [];
var barGraphData = [];
var useDarkMode = getGlobalConfig().useDarkMode;
@foreach (CostForVehicleByMonth gasCost in Model)
{
@:barGraphLabels.push("@gasCost.MonthName");
@:barGraphData.push(@gasCost.Cost);
}
new Chart($("#bar-chart-mpg"), {
type: 'bar',
data: {
labels: barGraphLabels,
datasets: [
{
label: "Fuel Mileage by Month",
backgroundColor: ["#00876c", "#43956e", "#67a371", "#89b177", "#a9be80", "#c8cb8b", "#e6d79b", "#e4c281", "#e3ab6b", "#e2925b", "#e07952", "#db5d4f"],
data: barGraphData
}
]
},
options: {
plugins: {
legend: {
labels: {
color: useDarkMode ? "#fff" : "#000"
}
}
},
scales: {
y: {
beginAtZero: true,
ticks: {
color: useDarkMode ? "#fff" : "#000"
}
},
x: {
ticks: {
color: useDarkMode ? "#fff" : "#000"
}
}
}
}
});
}
</script>
} else
{
<div class="text-center">
<h4>No data found, insert/select some data to see visualizations here.</h4>
</div>
}

View File

@@ -69,13 +69,15 @@
</div>
<hr />
<div class="row hideOnPrint">
<div class="col-md-3 col-12" id="collaboratorContent">
<div class="col-md-3 col-12 chartContainer" id="collaboratorContent">
@await Html.PartialAsync("_Collaborators", Model.Collaborators)
</div>
<div class="col-md-6 col-12">
<div class="col-md-6 col-12 chartContainer">
<div class="d-flex justify-content-center align-items-center col-12 chartContainer" id="monthFuelMileageReportContent">
@await Html.PartialAsync("_MPGByMonthReport", Model.FuelMileageForVehicleByMonth)
</div>
</div>
<div class="col-md-3 col-12">
<div class="col-md-3 col-12 chartContainer">
<div class="d-flex justify-content-center">
<button onclick="generateVehicleHistoryReport()" class="btn btn-secondary btn-md mt-1 mb-1">Vehicle Maintenance Report<i class="bi ms-2 bi-box-arrow-in-up-right"></i></button>
</div>

View File

@@ -8,6 +8,15 @@
}
<div class="modal-header">
<h5 class="modal-title" id="addVehicleModalLabel">@(isNew ? "Add New Vehicle" : "Edit Vehicle")</h5>
@if (isNew)
{
<button type="button" class="btn-close" onclick="hideAddVehicleModal()" aria-label="Close"></button>
}
else if (!isNew)
{
<button type="button" class="btn-close" onclick="hideEditVehicleModal()" aria-label="Close"></button>
}
</div>
<div class="modal-body">
<form class="form-inline">

View File

@@ -19,6 +19,13 @@ function updateCheck(sender) {
refreshBarChart();
}, 1000);
}
function refreshMPGChart() {
var vehicleId = GetVehicleId().vehicleId;
var year = getYear();
$.post('/Vehicle/GetMonthMPGByVehicle', {vehicleId: vehicleId, year: year}, function (data) {
$("#monthFuelMileageReportContent").html(data);
})
}
function refreshBarChart(callBack) {
var selectedMetrics = [];
var vehicleId = GetVehicleId().vehicleId;
@@ -47,9 +54,7 @@ function refreshBarChart(callBack) {
year: year
}, function (data) {
$("#gasCostByMonthReportContent").html(data);
if (callBack != undefined) {
callBack();
}
refreshMPGChart();
});
}
function updateReminderPie() {