Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
96914b3db4 | ||
|
|
7ad6d3369d | ||
|
|
0ae28d436b | ||
|
|
4575cf338f | ||
|
|
c526a9f207 | ||
|
|
1a3282c1ef | ||
|
|
f52e5b49c7 | ||
|
|
507fb6daf6 | ||
|
|
9d3fbd05fc | ||
|
|
2a0f884e89 | ||
|
|
26012bf27a | ||
|
|
3fa3dbaa8c | ||
|
|
95cac60c71 | ||
|
|
7878ce65ca | ||
|
|
c6c57a5de6 | ||
|
|
2ece3cd113 | ||
|
|
9504674933 | ||
|
|
3c0bdcea0e | ||
|
|
a4762d5b32 | ||
|
|
dc18bb5b8f | ||
|
|
452248e681 | ||
|
|
a7ea03014f | ||
|
|
cb89ca3426 | ||
|
|
760f7e1888 | ||
|
|
ba149568a5 | ||
|
|
2ef281bd0a | ||
|
|
859796cfe8 | ||
|
|
f1e0254f95 | ||
|
|
70d0827432 | ||
|
|
851a7af287 | ||
|
|
e46be7ba0a | ||
|
|
b4258dc11a | ||
|
|
0f35621846 | ||
|
|
374f919296 | ||
|
|
33b824b316 | ||
|
|
418e468f14 | ||
|
|
0a1f6a569d | ||
|
|
2a842d1c8c |
24
.github/workflows/docker-image.yml
vendored
24
.github/workflows/docker-image.yml
vendored
@@ -11,9 +11,21 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- name: Checkout
|
||||||
- name: Build and push the Docker image
|
uses: actions/checkout@v4
|
||||||
run: |
|
- name: Set up Docker Buildx
|
||||||
docker login -u "hargata" -p "${{ secrets.GHCR_PAT }}" ghcr.io
|
uses: docker/setup-buildx-action@v3
|
||||||
docker build . --file Dockerfile --tag ghcr.io/hargata/lubelogger:latest
|
- name: Login to GitHub Container Registry
|
||||||
docker push ghcr.io/hargata/lubelogger:latest
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: "hargata"
|
||||||
|
password: "${{ secrets.GHCR_PAT }}"
|
||||||
|
- name: Build and push
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
platforms: linux/amd64
|
||||||
|
push: true
|
||||||
|
tags: |
|
||||||
|
ghcr.io/hargata/lubelogger:latest
|
||||||
@@ -45,7 +45,9 @@ namespace CarCareTracker.Controllers
|
|||||||
UseDarkMode = bool.Parse(_config[nameof(UserConfig.UseDarkMode)]),
|
UseDarkMode = bool.Parse(_config[nameof(UserConfig.UseDarkMode)]),
|
||||||
UseMPG = bool.Parse(_config[nameof(UserConfig.UseMPG)]),
|
UseMPG = bool.Parse(_config[nameof(UserConfig.UseMPG)]),
|
||||||
UseDescending = bool.Parse(_config[nameof(UserConfig.UseDescending)]),
|
UseDescending = bool.Parse(_config[nameof(UserConfig.UseDescending)]),
|
||||||
EnableAuth = bool.Parse(_config[nameof(UserConfig.EnableAuth)])
|
EnableAuth = bool.Parse(_config[nameof(UserConfig.EnableAuth)]),
|
||||||
|
HideZero = bool.Parse(_config[nameof(UserConfig.HideZero)]),
|
||||||
|
UseUKMPG = bool.Parse(_config[nameof(UserConfig.UseUKMPG)])
|
||||||
};
|
};
|
||||||
return PartialView("_Settings", userConfig);
|
return PartialView("_Settings", userConfig);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using CsvHelper;
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using CarCareTracker.External.Implementations;
|
using CarCareTracker.External.Implementations;
|
||||||
|
using CarCareTracker.MapProfile;
|
||||||
|
|
||||||
namespace CarCareTracker.Controllers
|
namespace CarCareTracker.Controllers
|
||||||
{
|
{
|
||||||
@@ -21,6 +22,7 @@ namespace CarCareTracker.Controllers
|
|||||||
private readonly ICollisionRecordDataAccess _collisionRecordDataAccess;
|
private readonly ICollisionRecordDataAccess _collisionRecordDataAccess;
|
||||||
private readonly ITaxRecordDataAccess _taxRecordDataAccess;
|
private readonly ITaxRecordDataAccess _taxRecordDataAccess;
|
||||||
private readonly IReminderRecordDataAccess _reminderRecordDataAccess;
|
private readonly IReminderRecordDataAccess _reminderRecordDataAccess;
|
||||||
|
private readonly IUpgradeRecordDataAccess _upgradeRecordDataAccess;
|
||||||
private readonly IWebHostEnvironment _webEnv;
|
private readonly IWebHostEnvironment _webEnv;
|
||||||
private readonly bool _useDescending;
|
private readonly bool _useDescending;
|
||||||
private readonly IConfiguration _config;
|
private readonly IConfiguration _config;
|
||||||
@@ -35,6 +37,7 @@ namespace CarCareTracker.Controllers
|
|||||||
ICollisionRecordDataAccess collisionRecordDataAccess,
|
ICollisionRecordDataAccess collisionRecordDataAccess,
|
||||||
ITaxRecordDataAccess taxRecordDataAccess,
|
ITaxRecordDataAccess taxRecordDataAccess,
|
||||||
IReminderRecordDataAccess reminderRecordDataAccess,
|
IReminderRecordDataAccess reminderRecordDataAccess,
|
||||||
|
IUpgradeRecordDataAccess upgradeRecordDataAccess,
|
||||||
IWebHostEnvironment webEnv,
|
IWebHostEnvironment webEnv,
|
||||||
IConfiguration config)
|
IConfiguration config)
|
||||||
{
|
{
|
||||||
@@ -47,6 +50,7 @@ namespace CarCareTracker.Controllers
|
|||||||
_collisionRecordDataAccess = collisionRecordDataAccess;
|
_collisionRecordDataAccess = collisionRecordDataAccess;
|
||||||
_taxRecordDataAccess = taxRecordDataAccess;
|
_taxRecordDataAccess = taxRecordDataAccess;
|
||||||
_reminderRecordDataAccess = reminderRecordDataAccess;
|
_reminderRecordDataAccess = reminderRecordDataAccess;
|
||||||
|
_upgradeRecordDataAccess = upgradeRecordDataAccess;
|
||||||
_webEnv = webEnv;
|
_webEnv = webEnv;
|
||||||
_config = config;
|
_config = config;
|
||||||
_useDescending = bool.Parse(config[nameof(UserConfig.UseDescending)]);
|
_useDescending = bool.Parse(config[nameof(UserConfig.UseDescending)]);
|
||||||
@@ -95,6 +99,7 @@ namespace CarCareTracker.Controllers
|
|||||||
_taxRecordDataAccess.DeleteAllTaxRecordsByVehicleId(vehicleId) &&
|
_taxRecordDataAccess.DeleteAllTaxRecordsByVehicleId(vehicleId) &&
|
||||||
_noteDataAccess.DeleteNoteByVehicleId(vehicleId) &&
|
_noteDataAccess.DeleteNoteByVehicleId(vehicleId) &&
|
||||||
_reminderRecordDataAccess.DeleteAllReminderRecordsByVehicleId(vehicleId) &&
|
_reminderRecordDataAccess.DeleteAllReminderRecordsByVehicleId(vehicleId) &&
|
||||||
|
_upgradeRecordDataAccess.DeleteAllUpgradeRecordsByVehicleId(vehicleId) &&
|
||||||
_dataAccess.DeleteVehicle(vehicleId);
|
_dataAccess.DeleteVehicle(vehicleId);
|
||||||
return Json(result);
|
return Json(result);
|
||||||
}
|
}
|
||||||
@@ -122,12 +127,12 @@ namespace CarCareTracker.Controllers
|
|||||||
}
|
}
|
||||||
#region "Bulk Imports"
|
#region "Bulk Imports"
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public IActionResult GetBulkImportModalPartialView(string mode)
|
public IActionResult GetBulkImportModalPartialView(ImportMode mode)
|
||||||
{
|
{
|
||||||
return PartialView("_BulkDataImporter", mode);
|
return PartialView("_BulkDataImporter", mode);
|
||||||
}
|
}
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public IActionResult ImportToVehicleIdFromCsv(int vehicleId, string mode, string fileName)
|
public IActionResult ImportToVehicleIdFromCsv(int vehicleId, ImportMode mode, string fileName)
|
||||||
{
|
{
|
||||||
if (vehicleId == default || string.IsNullOrWhiteSpace(fileName))
|
if (vehicleId == default || string.IsNullOrWhiteSpace(fileName))
|
||||||
{
|
{
|
||||||
@@ -145,81 +150,85 @@ namespace CarCareTracker.Controllers
|
|||||||
var config = new CsvHelper.Configuration.CsvConfiguration(System.Globalization.CultureInfo.InvariantCulture);
|
var config = new CsvHelper.Configuration.CsvConfiguration(System.Globalization.CultureInfo.InvariantCulture);
|
||||||
config.MissingFieldFound = null;
|
config.MissingFieldFound = null;
|
||||||
config.HeaderValidated = null;
|
config.HeaderValidated = null;
|
||||||
|
config.PrepareHeaderForMatch = args => { return args.Header.Trim().ToLower(); };
|
||||||
using (var csv = new CsvReader(reader, config))
|
using (var csv = new CsvReader(reader, config))
|
||||||
{
|
{
|
||||||
if (mode == "gasrecord")
|
csv.Context.RegisterClassMap<FuellyMapper>();
|
||||||
|
var records = csv.GetRecords<ImportModel>().ToList();
|
||||||
|
if (records.Any())
|
||||||
{
|
{
|
||||||
var records = csv.GetRecords<GasRecordImport>().ToList();
|
foreach (ImportModel importModel in records)
|
||||||
if (records.Any())
|
|
||||||
{
|
{
|
||||||
foreach (GasRecordImport recordToInsert in records)
|
if (mode == ImportMode.GasRecord)
|
||||||
{
|
{
|
||||||
|
//convert to gas model.
|
||||||
var convertedRecord = new GasRecord()
|
var convertedRecord = new GasRecord()
|
||||||
{
|
{
|
||||||
VehicleId = vehicleId,
|
VehicleId = vehicleId,
|
||||||
Date = recordToInsert.Date,
|
Date = DateTime.Parse(importModel.Date),
|
||||||
Mileage = recordToInsert.Odometer,
|
Mileage = int.Parse(importModel.Odometer, NumberStyles.Any),
|
||||||
Gallons = recordToInsert.FuelConsumed,
|
Gallons = decimal.Parse(importModel.FuelConsumed, NumberStyles.Any)
|
||||||
Cost = recordToInsert.Cost
|
|
||||||
};
|
};
|
||||||
_gasRecordDataAccess.SaveGasRecordToVehicle(convertedRecord);
|
if (string.IsNullOrWhiteSpace(importModel.Cost) && !string.IsNullOrWhiteSpace(importModel.Price))
|
||||||
|
{
|
||||||
|
//cost was not given but price is.
|
||||||
|
//fuelly sometimes exports CSVs without total cost.
|
||||||
|
var parsedPrice = decimal.Parse(importModel.Price, NumberStyles.Any);
|
||||||
|
convertedRecord.Cost = convertedRecord.Gallons * parsedPrice;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
convertedRecord.Cost = decimal.Parse(importModel.Cost, NumberStyles.Any);
|
||||||
|
}
|
||||||
|
if (string.IsNullOrWhiteSpace(importModel.IsFillToFull) && !string.IsNullOrWhiteSpace(importModel.PartialFuelUp))
|
||||||
|
{
|
||||||
|
var parsedBool = importModel.PartialFuelUp.Trim() == "1";
|
||||||
|
convertedRecord.IsFillToFull = !parsedBool;
|
||||||
|
} else if (!string.IsNullOrWhiteSpace(importModel.IsFillToFull))
|
||||||
|
{
|
||||||
|
var parsedBool = importModel.IsFillToFull.Trim() == "1" || importModel.IsFillToFull.Trim() == "Full";
|
||||||
|
convertedRecord.IsFillToFull = parsedBool;
|
||||||
|
}
|
||||||
|
//insert record into db, check to make sure fuelconsumed is not zero so we don't get a divide by zero error.
|
||||||
|
if (convertedRecord.Gallons > 0)
|
||||||
|
{
|
||||||
|
_gasRecordDataAccess.SaveGasRecordToVehicle(convertedRecord);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
else if (mode == ImportMode.ServiceRecord)
|
||||||
}
|
|
||||||
else if (mode == "servicerecord")
|
|
||||||
{
|
|
||||||
var records = csv.GetRecords<ServiceRecordImport>().ToList();
|
|
||||||
if (records.Any())
|
|
||||||
{
|
|
||||||
foreach (ServiceRecordImport recordToInsert in records)
|
|
||||||
{
|
{
|
||||||
var convertedRecord = new ServiceRecord()
|
var convertedRecord = new ServiceRecord()
|
||||||
{
|
{
|
||||||
VehicleId = vehicleId,
|
VehicleId = vehicleId,
|
||||||
Date = recordToInsert.Date,
|
Date = DateTime.Parse(importModel.Date),
|
||||||
Mileage = recordToInsert.Odometer,
|
Mileage = int.Parse(importModel.Odometer, NumberStyles.Any),
|
||||||
Description = recordToInsert.Description,
|
Description = string.IsNullOrWhiteSpace(importModel.Description) ? $"Service Record on {importModel.Date}" : importModel.Description,
|
||||||
Notes = recordToInsert.Notes,
|
Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes,
|
||||||
Cost = recordToInsert.Cost
|
Cost = decimal.Parse(importModel.Cost, NumberStyles.Any)
|
||||||
};
|
};
|
||||||
_serviceRecordDataAccess.SaveServiceRecordToVehicle(convertedRecord);
|
_serviceRecordDataAccess.SaveServiceRecordToVehicle(convertedRecord);
|
||||||
}
|
}
|
||||||
}
|
else if (mode == ImportMode.RepairRecord)
|
||||||
}
|
|
||||||
else if (mode == "repairrecord")
|
|
||||||
{
|
|
||||||
var records = csv.GetRecords<ServiceRecordImport>().ToList();
|
|
||||||
if (records.Any())
|
|
||||||
{
|
|
||||||
foreach (ServiceRecordImport recordToInsert in records)
|
|
||||||
{
|
{
|
||||||
var convertedRecord = new CollisionRecord()
|
var convertedRecord = new CollisionRecord()
|
||||||
{
|
{
|
||||||
VehicleId = vehicleId,
|
VehicleId = vehicleId,
|
||||||
Date = recordToInsert.Date,
|
Date = DateTime.Parse(importModel.Date),
|
||||||
Mileage = recordToInsert.Odometer,
|
Mileage = int.Parse(importModel.Odometer, NumberStyles.Any),
|
||||||
Description = recordToInsert.Description,
|
Description = string.IsNullOrWhiteSpace(importModel.Description) ? $"Repair Record on {importModel.Date}" : importModel.Description,
|
||||||
Notes = recordToInsert.Notes,
|
Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes,
|
||||||
Cost = recordToInsert.Cost
|
Cost = decimal.Parse(importModel.Cost, NumberStyles.Any)
|
||||||
};
|
};
|
||||||
_collisionRecordDataAccess.SaveCollisionRecordToVehicle(convertedRecord);
|
_collisionRecordDataAccess.SaveCollisionRecordToVehicle(convertedRecord);
|
||||||
}
|
}
|
||||||
}
|
else if (mode == ImportMode.TaxRecord)
|
||||||
}
|
|
||||||
else if (mode == "taxrecord")
|
|
||||||
{
|
|
||||||
var records = csv.GetRecords<TaxRecordImport>().ToList();
|
|
||||||
if (records.Any())
|
|
||||||
{
|
|
||||||
foreach (TaxRecordImport recordToInsert in records)
|
|
||||||
{
|
{
|
||||||
var convertedRecord = new TaxRecord()
|
var convertedRecord = new TaxRecord()
|
||||||
{
|
{
|
||||||
VehicleId = vehicleId,
|
VehicleId = vehicleId,
|
||||||
Date = recordToInsert.Date,
|
Date = DateTime.Parse(importModel.Date),
|
||||||
Description = recordToInsert.Description,
|
Description = string.IsNullOrWhiteSpace(importModel.Description) ? $"Tax Record on {importModel.Date}" : importModel.Description,
|
||||||
Notes = recordToInsert.Notes,
|
Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes,
|
||||||
Cost = recordToInsert.Cost
|
Cost = decimal.Parse(importModel.Cost, NumberStyles.Any)
|
||||||
};
|
};
|
||||||
_taxRecordDataAccess.SaveTaxRecordToVehicle(convertedRecord);
|
_taxRecordDataAccess.SaveTaxRecordToVehicle(convertedRecord);
|
||||||
}
|
}
|
||||||
@@ -245,6 +254,7 @@ namespace CarCareTracker.Controllers
|
|||||||
result = result.OrderBy(x => x.Date).ThenBy(x => x.Mileage).ToList();
|
result = result.OrderBy(x => x.Date).ThenBy(x => x.Mileage).ToList();
|
||||||
//check if the user uses MPG or Liters per 100km.
|
//check if the user uses MPG or Liters per 100km.
|
||||||
bool useMPG = bool.Parse(_config[nameof(UserConfig.UseMPG)]);
|
bool useMPG = bool.Parse(_config[nameof(UserConfig.UseMPG)]);
|
||||||
|
bool useUKMPG = bool.Parse(_config[nameof(UserConfig.UseUKMPG)]);
|
||||||
var computedResults = new List<GasRecordViewModel>();
|
var computedResults = new List<GasRecordViewModel>();
|
||||||
int previousMileage = 0;
|
int previousMileage = 0;
|
||||||
decimal unFactoredConsumption = 0.00M;
|
decimal unFactoredConsumption = 0.00M;
|
||||||
@@ -252,9 +262,19 @@ namespace CarCareTracker.Controllers
|
|||||||
//perform computation.
|
//perform computation.
|
||||||
for (int i = 0; i < result.Count; i++)
|
for (int i = 0; i < result.Count; i++)
|
||||||
{
|
{
|
||||||
|
var currentObject = result[i];
|
||||||
|
decimal convertedConsumption;
|
||||||
|
if (useUKMPG && useMPG)
|
||||||
|
{
|
||||||
|
//if we're using UK MPG and the user wants imperial calculation insteace of l/100km
|
||||||
|
//if UK MPG is selected then the gas consumption are stored in liters but need to convert into UK gallons for computation.
|
||||||
|
convertedConsumption = currentObject.Gallons / 4.546M;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
convertedConsumption = currentObject.Gallons;
|
||||||
|
}
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
{
|
{
|
||||||
var currentObject = result[i];
|
|
||||||
var deltaMileage = currentObject.Mileage - previousMileage;
|
var deltaMileage = currentObject.Mileage - previousMileage;
|
||||||
var gasRecordViewModel = new GasRecordViewModel()
|
var gasRecordViewModel = new GasRecordViewModel()
|
||||||
{
|
{
|
||||||
@@ -262,21 +282,22 @@ namespace CarCareTracker.Controllers
|
|||||||
VehicleId = currentObject.VehicleId,
|
VehicleId = currentObject.VehicleId,
|
||||||
Date = currentObject.Date.ToShortDateString(),
|
Date = currentObject.Date.ToShortDateString(),
|
||||||
Mileage = currentObject.Mileage,
|
Mileage = currentObject.Mileage,
|
||||||
Gallons = currentObject.Gallons,
|
Gallons = convertedConsumption,
|
||||||
Cost = currentObject.Cost,
|
Cost = currentObject.Cost,
|
||||||
DeltaMileage = deltaMileage,
|
DeltaMileage = deltaMileage,
|
||||||
CostPerGallon = (currentObject.Cost / currentObject.Gallons)
|
CostPerGallon = (currentObject.Cost / convertedConsumption)
|
||||||
};
|
};
|
||||||
if (currentObject.IsFillToFull)
|
if (currentObject.IsFillToFull)
|
||||||
{
|
{
|
||||||
//if user filled to full.
|
//if user filled to full.
|
||||||
gasRecordViewModel.MilesPerGallon = useMPG ? ((unFactoredMileage + deltaMileage) / (unFactoredConsumption + currentObject.Gallons)) : 100 / ((unFactoredMileage + deltaMileage) / (unFactoredConsumption + currentObject.Gallons));
|
gasRecordViewModel.MilesPerGallon = useMPG ? ((unFactoredMileage + deltaMileage) / (unFactoredConsumption + convertedConsumption)) : 100 / ((unFactoredMileage + deltaMileage) / (unFactoredConsumption + convertedConsumption));
|
||||||
//reset unFactored vars
|
//reset unFactored vars
|
||||||
unFactoredConsumption = 0;
|
unFactoredConsumption = 0;
|
||||||
unFactoredMileage = 0;
|
unFactoredMileage = 0;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
unFactoredConsumption += currentObject.Gallons;
|
unFactoredConsumption += convertedConsumption;
|
||||||
unFactoredMileage += deltaMileage;
|
unFactoredMileage += deltaMileage;
|
||||||
gasRecordViewModel.MilesPerGallon = 0;
|
gasRecordViewModel.MilesPerGallon = 0;
|
||||||
}
|
}
|
||||||
@@ -286,18 +307,18 @@ namespace CarCareTracker.Controllers
|
|||||||
{
|
{
|
||||||
computedResults.Add(new GasRecordViewModel()
|
computedResults.Add(new GasRecordViewModel()
|
||||||
{
|
{
|
||||||
Id = result[i].Id,
|
Id = currentObject.Id,
|
||||||
VehicleId = result[i].VehicleId,
|
VehicleId = currentObject.VehicleId,
|
||||||
Date = result[i].Date.ToShortDateString(),
|
Date = currentObject.Date.ToShortDateString(),
|
||||||
Mileage = result[i].Mileage,
|
Mileage = currentObject.Mileage,
|
||||||
Gallons = result[i].Gallons,
|
Gallons = convertedConsumption,
|
||||||
Cost = result[i].Cost,
|
Cost = currentObject.Cost,
|
||||||
DeltaMileage = 0,
|
DeltaMileage = 0,
|
||||||
MilesPerGallon = 0,
|
MilesPerGallon = 0,
|
||||||
CostPerGallon = (result[i].Cost / result[i].Gallons)
|
CostPerGallon = (currentObject.Cost / convertedConsumption)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
previousMileage = result[i].Mileage;
|
previousMileage = currentObject.Mileage;
|
||||||
}
|
}
|
||||||
if (_useDescending)
|
if (_useDescending)
|
||||||
{
|
{
|
||||||
@@ -524,19 +545,22 @@ namespace CarCareTracker.Controllers
|
|||||||
var gasRecords = _gasRecordDataAccess.GetGasRecordsByVehicleId(vehicleId);
|
var gasRecords = _gasRecordDataAccess.GetGasRecordsByVehicleId(vehicleId);
|
||||||
var collisionRecords = _collisionRecordDataAccess.GetCollisionRecordsByVehicleId(vehicleId);
|
var collisionRecords = _collisionRecordDataAccess.GetCollisionRecordsByVehicleId(vehicleId);
|
||||||
var taxRecords = _taxRecordDataAccess.GetTaxRecordsByVehicleId(vehicleId);
|
var taxRecords = _taxRecordDataAccess.GetTaxRecordsByVehicleId(vehicleId);
|
||||||
|
var upgradeRecords = _upgradeRecordDataAccess.GetUpgradeRecordsByVehicleId(vehicleId);
|
||||||
if (year != default)
|
if (year != default)
|
||||||
{
|
{
|
||||||
serviceRecords.RemoveAll(x => x.Date.Year != year);
|
serviceRecords.RemoveAll(x => x.Date.Year != year);
|
||||||
gasRecords.RemoveAll(x => x.Date.Year != year);
|
gasRecords.RemoveAll(x => x.Date.Year != year);
|
||||||
collisionRecords.RemoveAll(x => x.Date.Year != year);
|
collisionRecords.RemoveAll(x => x.Date.Year != year);
|
||||||
taxRecords.RemoveAll(x => x.Date.Year != year);
|
taxRecords.RemoveAll(x => x.Date.Year != year);
|
||||||
|
upgradeRecords.RemoveAll(x => x.Date.Year != year);
|
||||||
}
|
}
|
||||||
var viewModel = new CostMakeUpForVehicle
|
var viewModel = new CostMakeUpForVehicle
|
||||||
{
|
{
|
||||||
ServiceRecordSum = serviceRecords.Sum(x => x.Cost),
|
ServiceRecordSum = serviceRecords.Sum(x => x.Cost),
|
||||||
GasRecordSum = gasRecords.Sum(x => x.Cost),
|
GasRecordSum = gasRecords.Sum(x => x.Cost),
|
||||||
CollisionRecordSum = collisionRecords.Sum(x => x.Cost),
|
CollisionRecordSum = collisionRecords.Sum(x => x.Cost),
|
||||||
TaxRecordSum = taxRecords.Sum(x => x.Cost)
|
TaxRecordSum = taxRecords.Sum(x => x.Cost),
|
||||||
|
UpgradeRecordSum = upgradeRecords.Sum(x=>x.Cost)
|
||||||
};
|
};
|
||||||
return PartialView("_CostMakeUpReport", viewModel);
|
return PartialView("_CostMakeUpReport", viewModel);
|
||||||
}
|
}
|
||||||
@@ -574,6 +598,11 @@ namespace CarCareTracker.Controllers
|
|||||||
{
|
{
|
||||||
numbersArray.Add(gasRecords.Max(x => x.Mileage));
|
numbersArray.Add(gasRecords.Max(x => x.Mileage));
|
||||||
}
|
}
|
||||||
|
var upgradeRecords = _upgradeRecordDataAccess.GetUpgradeRecordsByVehicleId(vehicleId);
|
||||||
|
if (upgradeRecords.Any())
|
||||||
|
{
|
||||||
|
numbersArray.Add(upgradeRecords.Max(x => x.Mileage));
|
||||||
|
}
|
||||||
return numbersArray.Any() ? numbersArray.Max() : 0;
|
return numbersArray.Any() ? numbersArray.Max() : 0;
|
||||||
}
|
}
|
||||||
private List<ReminderRecordViewModel> GetRemindersAndUrgency(int vehicleId)
|
private List<ReminderRecordViewModel> GetRemindersAndUrgency(int vehicleId)
|
||||||
@@ -581,7 +610,7 @@ namespace CarCareTracker.Controllers
|
|||||||
var currentMileage = GetMaxMileage(vehicleId);
|
var currentMileage = GetMaxMileage(vehicleId);
|
||||||
var reminders = _reminderRecordDataAccess.GetReminderRecordsByVehicleId(vehicleId);
|
var reminders = _reminderRecordDataAccess.GetReminderRecordsByVehicleId(vehicleId);
|
||||||
List<ReminderRecordViewModel> reminderViewModels = new List<ReminderRecordViewModel>();
|
List<ReminderRecordViewModel> reminderViewModels = new List<ReminderRecordViewModel>();
|
||||||
foreach(var reminder in reminders)
|
foreach (var reminder in reminders)
|
||||||
{
|
{
|
||||||
var reminderViewModel = new ReminderRecordViewModel()
|
var reminderViewModel = new ReminderRecordViewModel()
|
||||||
{
|
{
|
||||||
@@ -622,12 +651,13 @@ namespace CarCareTracker.Controllers
|
|||||||
reminderViewModel.Urgency = ReminderUrgency.Urgent;
|
reminderViewModel.Urgency = ReminderUrgency.Urgent;
|
||||||
reminderViewModel.Metric = ReminderMetric.Date;
|
reminderViewModel.Metric = ReminderMetric.Date;
|
||||||
}
|
}
|
||||||
else if (reminder.Mileage < currentMileage + 100)
|
else if (reminder.Mileage < currentMileage + 100)
|
||||||
{
|
{
|
||||||
reminderViewModel.Urgency = ReminderUrgency.Urgent;
|
reminderViewModel.Urgency = ReminderUrgency.Urgent;
|
||||||
reminderViewModel.Metric = ReminderMetric.Odometer;
|
reminderViewModel.Metric = ReminderMetric.Odometer;
|
||||||
}
|
}
|
||||||
} else if (reminder.Metric == ReminderMetric.Date)
|
}
|
||||||
|
else if (reminder.Metric == ReminderMetric.Date)
|
||||||
{
|
{
|
||||||
if (reminder.Date < DateTime.Now)
|
if (reminder.Date < DateTime.Now)
|
||||||
{
|
{
|
||||||
@@ -641,7 +671,8 @@ namespace CarCareTracker.Controllers
|
|||||||
{
|
{
|
||||||
reminderViewModel.Urgency = ReminderUrgency.Urgent;
|
reminderViewModel.Urgency = ReminderUrgency.Urgent;
|
||||||
}
|
}
|
||||||
} else if (reminder.Metric == ReminderMetric.Odometer)
|
}
|
||||||
|
else if (reminder.Metric == ReminderMetric.Odometer)
|
||||||
{
|
{
|
||||||
if (reminder.Mileage < currentMileage)
|
if (reminder.Mileage < currentMileage)
|
||||||
{
|
{
|
||||||
@@ -665,7 +696,7 @@ namespace CarCareTracker.Controllers
|
|||||||
public IActionResult GetVehicleHaveUrgentOrPastDueReminders(int vehicleId)
|
public IActionResult GetVehicleHaveUrgentOrPastDueReminders(int vehicleId)
|
||||||
{
|
{
|
||||||
var result = GetRemindersAndUrgency(vehicleId);
|
var result = GetRemindersAndUrgency(vehicleId);
|
||||||
if (result.Where(x=>x.Urgency == ReminderUrgency.VeryUrgent || x.Urgency == ReminderUrgency.PastDue).Any())
|
if (result.Where(x => x.Urgency == ReminderUrgency.VeryUrgent || x.Urgency == ReminderUrgency.PastDue).Any())
|
||||||
{
|
{
|
||||||
return Json(true);
|
return Json(true);
|
||||||
}
|
}
|
||||||
@@ -675,7 +706,7 @@ namespace CarCareTracker.Controllers
|
|||||||
public IActionResult GetReminderRecordsByVehicleId(int vehicleId)
|
public IActionResult GetReminderRecordsByVehicleId(int vehicleId)
|
||||||
{
|
{
|
||||||
var result = GetRemindersAndUrgency(vehicleId);
|
var result = GetRemindersAndUrgency(vehicleId);
|
||||||
result = result.OrderByDescending(x=>x.Urgency).ToList();
|
result = result.OrderByDescending(x => x.Urgency).ToList();
|
||||||
return PartialView("_ReminderRecords", result);
|
return PartialView("_ReminderRecords", result);
|
||||||
}
|
}
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
@@ -720,5 +751,58 @@ namespace CarCareTracker.Controllers
|
|||||||
return Json(result);
|
return Json(result);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
#region "Upgrade Records"
|
||||||
|
[HttpGet]
|
||||||
|
public IActionResult GetUpgradeRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
var result = _upgradeRecordDataAccess.GetUpgradeRecordsByVehicleId(vehicleId);
|
||||||
|
if (_useDescending)
|
||||||
|
{
|
||||||
|
result = result.OrderByDescending(x => x.Date).ThenByDescending(x => x.Mileage).ToList();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = result.OrderBy(x => x.Date).ThenBy(x => x.Mileage).ToList();
|
||||||
|
}
|
||||||
|
return PartialView("_UpgradeRecords", result);
|
||||||
|
}
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult SaveUpgradeRecordToVehicleId(UpgradeRecordInput upgradeRecord)
|
||||||
|
{
|
||||||
|
//move files from temp.
|
||||||
|
upgradeRecord.Files = upgradeRecord.Files.Select(x => { return new UploadedFiles { Name = x.Name, Location = _fileHelper.MoveFileFromTemp(x.Location, "documents/") }; }).ToList();
|
||||||
|
var result = _upgradeRecordDataAccess.SaveUpgradeRecordToVehicle(upgradeRecord.ToUpgradeRecord());
|
||||||
|
return Json(result);
|
||||||
|
}
|
||||||
|
[HttpGet]
|
||||||
|
public IActionResult GetAddUpgradeRecordPartialView()
|
||||||
|
{
|
||||||
|
return PartialView("_UpgradeRecordModal", new UpgradeRecordInput());
|
||||||
|
}
|
||||||
|
[HttpGet]
|
||||||
|
public IActionResult GetUpgradeRecordForEditById(int upgradeRecordId)
|
||||||
|
{
|
||||||
|
var result = _upgradeRecordDataAccess.GetUpgradeRecordById(upgradeRecordId);
|
||||||
|
//convert to Input object.
|
||||||
|
var convertedResult = new UpgradeRecordInput
|
||||||
|
{
|
||||||
|
Id = result.Id,
|
||||||
|
Cost = result.Cost,
|
||||||
|
Date = result.Date.ToShortDateString(),
|
||||||
|
Description = result.Description,
|
||||||
|
Mileage = result.Mileage,
|
||||||
|
Notes = result.Notes,
|
||||||
|
VehicleId = result.VehicleId,
|
||||||
|
Files = result.Files
|
||||||
|
};
|
||||||
|
return PartialView("_UpgradeRecordModal", convertedResult);
|
||||||
|
}
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult DeleteUpgradeRecordById(int upgradeRecordId)
|
||||||
|
{
|
||||||
|
var result = _upgradeRecordDataAccess.DeleteUpgradeRecordById(upgradeRecordId);
|
||||||
|
return Json(result);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
10
Enum/ImportMode.cs
Normal file
10
Enum/ImportMode.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace CarCareTracker.Models
|
||||||
|
{
|
||||||
|
public enum ImportMode
|
||||||
|
{
|
||||||
|
ServiceRecord = 0,
|
||||||
|
RepairRecord = 1,
|
||||||
|
GasRecord = 2,
|
||||||
|
TaxRecord = 3
|
||||||
|
}
|
||||||
|
}
|
||||||
57
External/Implementations/UpgradeRecordDataAccess.cs
vendored
Normal file
57
External/Implementations/UpgradeRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Helper;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class UpgradeRecordDataAccess : IUpgradeRecordDataAccess
|
||||||
|
{
|
||||||
|
private static string dbName = StaticHelper.DbName;
|
||||||
|
private static string tableName = "upgraderecords";
|
||||||
|
public List<UpgradeRecord> GetUpgradeRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
using (var db = new LiteDatabase(dbName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<UpgradeRecord>(tableName);
|
||||||
|
var upgradeRecords = table.Find(Query.EQ(nameof(UpgradeRecord.VehicleId), vehicleId));
|
||||||
|
return upgradeRecords.ToList() ?? new List<UpgradeRecord>();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public UpgradeRecord GetUpgradeRecordById(int upgradeRecordId)
|
||||||
|
{
|
||||||
|
using (var db = new LiteDatabase(dbName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<UpgradeRecord>(tableName);
|
||||||
|
return table.FindById(upgradeRecordId);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public bool DeleteUpgradeRecordById(int upgradeRecordId)
|
||||||
|
{
|
||||||
|
using (var db = new LiteDatabase(dbName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<UpgradeRecord>(tableName);
|
||||||
|
table.Delete(upgradeRecordId);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public bool SaveUpgradeRecordToVehicle(UpgradeRecord upgradeRecord)
|
||||||
|
{
|
||||||
|
using (var db = new LiteDatabase(dbName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<UpgradeRecord>(tableName);
|
||||||
|
table.Upsert(upgradeRecord);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public bool DeleteAllUpgradeRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
using (var db = new LiteDatabase(dbName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<UpgradeRecord>(tableName);
|
||||||
|
var upgradeRecords = table.DeleteMany(Query.EQ(nameof(UpgradeRecord.VehicleId), vehicleId));
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
13
External/Interfaces/IUpgradeRecordDataAccess.cs
vendored
Normal file
13
External/Interfaces/IUpgradeRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using CarCareTracker.Models;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Interfaces
|
||||||
|
{
|
||||||
|
public interface IUpgradeRecordDataAccess
|
||||||
|
{
|
||||||
|
public List<UpgradeRecord> GetUpgradeRecordsByVehicleId(int vehicleId);
|
||||||
|
public UpgradeRecord GetUpgradeRecordById(int upgradeRecordId);
|
||||||
|
public bool DeleteUpgradeRecordById(int upgradeRecordId);
|
||||||
|
public bool SaveUpgradeRecordToVehicle(UpgradeRecord upgradeRecord);
|
||||||
|
public bool DeleteAllUpgradeRecordsByVehicleId(int vehicleId);
|
||||||
|
}
|
||||||
|
}
|
||||||
21
MapProfile/FuellyMappers.cs
Normal file
21
MapProfile/FuellyMappers.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
using CarCareTracker.Models;
|
||||||
|
using CsvHelper.Configuration;
|
||||||
|
|
||||||
|
namespace CarCareTracker.MapProfile
|
||||||
|
{
|
||||||
|
public class FuellyMapper: ClassMap<ImportModel>
|
||||||
|
{
|
||||||
|
public FuellyMapper()
|
||||||
|
{
|
||||||
|
Map(m => m.Date).Name(["date", "fuelup_date"]);
|
||||||
|
Map(m => m.Odometer).Name(["odometer"]);
|
||||||
|
Map(m => m.FuelConsumed).Name(["gallons", "liters", "litres", "consumption", "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"]);
|
||||||
|
Map(m => m.PartialFuelUp).Name(["partial_fuelup"]);
|
||||||
|
Map(m => m.IsFillToFull).Name(["isfilltofull", "filled up"]);
|
||||||
|
Map(m => m.Description).Name(["description"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
18
Models/ImportModel.cs
Normal file
18
Models/ImportModel.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
namespace CarCareTracker.Models
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Import model used for importing Gas records.
|
||||||
|
/// </summary>
|
||||||
|
public class ImportModel
|
||||||
|
{
|
||||||
|
public string Date { get; set; }
|
||||||
|
public string Odometer { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
public string Notes { get; set; }
|
||||||
|
public string FuelConsumed { get; set; }
|
||||||
|
public string Cost { get; set; }
|
||||||
|
public string Price { get; set; }
|
||||||
|
public string PartialFuelUp { get; set; }
|
||||||
|
public string IsFillToFull { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
namespace CarCareTracker.Models
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Import model used for importing Gas records.
|
|
||||||
/// </summary>
|
|
||||||
public class GasRecordImport
|
|
||||||
{
|
|
||||||
public DateTime Date { get; set; }
|
|
||||||
public int Odometer { get; set; }
|
|
||||||
public decimal FuelConsumed { get; set; }
|
|
||||||
public decimal Cost { get; set; }
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Import model used for importing Service and Repair records.
|
|
||||||
/// </summary>
|
|
||||||
public class ServiceRecordImport
|
|
||||||
{
|
|
||||||
public DateTime Date { get; set; }
|
|
||||||
public int Odometer { get; set; }
|
|
||||||
public string Description { get; set; }
|
|
||||||
public string Notes { get; set; }
|
|
||||||
public decimal Cost { get; set; }
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Import model used for importing tax records.
|
|
||||||
/// </summary>
|
|
||||||
public class TaxRecordImport
|
|
||||||
{
|
|
||||||
public DateTime Date { get; set; }
|
|
||||||
public string Description { get; set; }
|
|
||||||
public string Notes { get; set; }
|
|
||||||
public decimal Cost { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,5 +6,6 @@
|
|||||||
public decimal GasRecordSum { get; set; }
|
public decimal GasRecordSum { get; set; }
|
||||||
public decimal TaxRecordSum { get; set; }
|
public decimal TaxRecordSum { get; set; }
|
||||||
public decimal CollisionRecordSum { get; set; }
|
public decimal CollisionRecordSum { get; set; }
|
||||||
|
public decimal UpgradeRecordSum { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
14
Models/Upgrades/UpgradeRecord.cs
Normal file
14
Models/Upgrades/UpgradeRecord.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
namespace CarCareTracker.Models
|
||||||
|
{
|
||||||
|
public class UpgradeRecord
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public int VehicleId { 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 List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>();
|
||||||
|
}
|
||||||
|
}
|
||||||
15
Models/Upgrades/UpgradeReportInput.cs
Normal file
15
Models/Upgrades/UpgradeReportInput.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
namespace CarCareTracker.Models
|
||||||
|
{
|
||||||
|
public class UpgradeRecordInput
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public int VehicleId { 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<UploadedFiles> Files { get; set; } = new List<UploadedFiles>();
|
||||||
|
public UpgradeRecord ToUpgradeRecord() { return new UpgradeRecord { Id = Id, VehicleId = VehicleId, Date = DateTime.Parse(Date), Cost = Cost, Mileage = Mileage, Description = Description, Notes = Notes, Files = Files }; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,8 @@
|
|||||||
public bool UseMPG { get; set; }
|
public bool UseMPG { get; set; }
|
||||||
public bool UseDescending { get; set; }
|
public bool UseDescending { get; set; }
|
||||||
public bool EnableAuth { get; set; }
|
public bool EnableAuth { get; set; }
|
||||||
|
public bool HideZero { get; set; }
|
||||||
|
public bool UseUKMPG {get;set;}
|
||||||
public string UserNameHash { get; set; }
|
public string UserNameHash { get; set; }
|
||||||
public string UserPasswordHash { get; set;}
|
public string UserPasswordHash { get; set;}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ builder.Services.AddSingleton<IGasRecordDataAccess, GasRecordDataAccess>();
|
|||||||
builder.Services.AddSingleton<ICollisionRecordDataAccess, CollisionRecordDataAccess>();
|
builder.Services.AddSingleton<ICollisionRecordDataAccess, CollisionRecordDataAccess>();
|
||||||
builder.Services.AddSingleton<ITaxRecordDataAccess, TaxRecordDataAccess>();
|
builder.Services.AddSingleton<ITaxRecordDataAccess, TaxRecordDataAccess>();
|
||||||
builder.Services.AddSingleton<IReminderRecordDataAccess, ReminderRecordDataAccess>();
|
builder.Services.AddSingleton<IReminderRecordDataAccess, ReminderRecordDataAccess>();
|
||||||
|
builder.Services.AddSingleton<IUpgradeRecordDataAccess, UpgradeRecordDataAccess>();
|
||||||
builder.Services.AddSingleton<IFileHelper, FileHelper>();
|
builder.Services.AddSingleton<IFileHelper, FileHelper>();
|
||||||
|
|
||||||
if (!Directory.Exists("data"))
|
if (!Directory.Exists("data"))
|
||||||
|
|||||||
11
README.md
11
README.md
@@ -13,10 +13,17 @@ Because nobody should have to deal with a homemade spreadsheet or a shoebox full
|
|||||||
- CsvHelper
|
- CsvHelper
|
||||||
- Chart.js
|
- Chart.js
|
||||||
|
|
||||||
## Docker Setup (Recommended)
|
## Docker Setup (GHCR)
|
||||||
|
1. Install Docker
|
||||||
|
2. Run `docker pull ghcr.io/hargata/lubelogger:latest`
|
||||||
|
3. CHECK culture in .env file, default is en_US, this will change the currency and date formats.
|
||||||
|
4. If not using traefik, use docker-compose-notraefik.yml
|
||||||
|
5. Run `docker-compose up`
|
||||||
|
|
||||||
|
## Docker Setup (Manual Build)
|
||||||
1. Install Docker
|
1. Install Docker
|
||||||
2. Clone this repo
|
2. Clone this repo
|
||||||
3. CHECK culture in Dockerfile, default is en_US
|
3. CHECK culture in .env file, default is en_US
|
||||||
4. Run `docker build -t lubelogger -f Dockerfile .`
|
4. Run `docker build -t lubelogger -f Dockerfile .`
|
||||||
5. CHECK docker-compose.yml and make sure the mounting directories look correct.
|
5. CHECK docker-compose.yml and make sure the mounting directories look correct.
|
||||||
6. If not using traefik, use docker-compose-notraefik.yml
|
6. If not using traefik, use docker-compose-notraefik.yml
|
||||||
|
|||||||
@@ -18,12 +18,20 @@
|
|||||||
<input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="useMPG" checked="@Model.UseMPG">
|
<input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="useMPG" checked="@Model.UseMPG">
|
||||||
<label class="form-check-label" for="useMPG">Use Imperial Calculation for Fuel Economy Calculations(MPG)<br /><small class="text-body-secondary">This Will Also Change Units to Miles and Gallons</small></label>
|
<label class="form-check-label" for="useMPG">Use Imperial Calculation for Fuel Economy Calculations(MPG)<br /><small class="text-body-secondary">This Will Also Change Units to Miles and Gallons</small></label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-check form-switch">
|
||||||
|
<input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="useUKMPG" checked="@Model.UseUKMPG">
|
||||||
|
<label class="form-check-label" for="useUKMPG">Use UK MPG Calculation<br /><small class="text-body-secondary">Input Gas Consumption in Liters, it will be converted to UK Gals for MPG Calculation</small></label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6">
|
<div class="col-12 col-md-6">
|
||||||
<div class="form-check form-switch">
|
<div class="form-check form-switch">
|
||||||
<input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="useDescending" checked="@Model.UseDescending">
|
<input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="useDescending" checked="@Model.UseDescending">
|
||||||
<label class="form-check-label" for="useDescending">Sort lists in Descending Order(Newest to Oldest)</label>
|
<label class="form-check-label" for="useDescending">Sort lists in Descending Order(Newest to Oldest)</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-check form-switch">
|
||||||
|
<input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="hideZero" checked="@Model.HideZero">
|
||||||
|
<label class="form-check-label" for="hideZero">Replace @(0.ToString("C")) Costs with ---</label>
|
||||||
|
</div>
|
||||||
<div class="form-check form-switch">
|
<div class="form-check form-switch">
|
||||||
<input class="form-check-input" onChange="enableAuthCheckChanged()" type="checkbox" role="switch" id="enableAuth" checked="@Model.EnableAuth">
|
<input class="form-check-input" onChange="enableAuthCheckChanged()" type="checkbox" role="switch" id="enableAuth" checked="@Model.EnableAuth">
|
||||||
<label class="form-check-label" for="enableAuth">Enable Authentication</label>
|
<label class="form-check-label" for="enableAuth">Enable Authentication</label>
|
||||||
@@ -76,7 +84,9 @@
|
|||||||
useDarkMode: $("#enableDarkMode").is(':checked'),
|
useDarkMode: $("#enableDarkMode").is(':checked'),
|
||||||
enableCsvImports: $("#enableCsvImports").is(':checked'),
|
enableCsvImports: $("#enableCsvImports").is(':checked'),
|
||||||
useMPG: $("#useMPG").is(':checked'),
|
useMPG: $("#useMPG").is(':checked'),
|
||||||
useDescending: $("#useDescending").is(':checked')
|
useDescending: $("#useDescending").is(':checked'),
|
||||||
|
hideZero: $("#hideZero").is(":checked"),
|
||||||
|
useUKMpg: $("#useUKMPG").is(":checked")
|
||||||
}
|
}
|
||||||
$.post('/Home/WriteToSettings', { userConfig: userConfigObject}, function(data){
|
$.post('/Home/WriteToSettings', { userConfig: userConfigObject}, function(data){
|
||||||
if (data) {
|
if (data) {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
<script src="~/js/collisionrecord.js" asp-append-version="true"></script>
|
<script src="~/js/collisionrecord.js" asp-append-version="true"></script>
|
||||||
<script src="~/js/taxrecord.js" asp-append-version="true"></script>
|
<script src="~/js/taxrecord.js" asp-append-version="true"></script>
|
||||||
<script src="~/js/reminderrecord.js" asp-append-version="true"></script>
|
<script src="~/js/reminderrecord.js" asp-append-version="true"></script>
|
||||||
|
<script src="~/js/upgraderecord.js" asp-append-version="true"></script>
|
||||||
<script src="~/lib/chart-js/chart.umd.js"></script>
|
<script src="~/lib/chart-js/chart.umd.js"></script>
|
||||||
}
|
}
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@@ -27,6 +28,9 @@
|
|||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<button class="nav-link" id="accident-tab" data-bs-toggle="tab" data-bs-target="#accident-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-exclamation-octagon me-2"></i>Repairs</button>
|
<button class="nav-link" id="accident-tab" data-bs-toggle="tab" data-bs-target="#accident-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-exclamation-octagon me-2"></i>Repairs</button>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="nav-item" role="presentation">
|
||||||
|
<button class="nav-link" id="upgrade-tab" data-bs-toggle="tab" data-bs-target="#upgrade-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-wrench-adjustable me-2"></i>Upgrades</button>
|
||||||
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<button class="nav-link" id="gas-tab" data-bs-toggle="tab" data-bs-target="#gas-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-fuel-pump me-2"></i>Fuel</button>
|
<button class="nav-link" id="gas-tab" data-bs-toggle="tab" data-bs-target="#gas-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-fuel-pump me-2"></i>Fuel</button>
|
||||||
</li>
|
</li>
|
||||||
@@ -71,6 +75,7 @@
|
|||||||
<div class="tab-pane fade" id="accident-tab-pane" role="tabpanel" tabindex="0"></div>
|
<div class="tab-pane fade" id="accident-tab-pane" role="tabpanel" tabindex="0"></div>
|
||||||
<div class="tab-pane fade" id="reminder-tab-pane" role="tabpanel" tabindex="0"></div>
|
<div class="tab-pane fade" id="reminder-tab-pane" role="tabpanel" tabindex="0"></div>
|
||||||
<div class="tab-pane fade" id="report-tab-pane" role="tabpanel" tabindex="0"></div>
|
<div class="tab-pane fade" id="report-tab-pane" role="tabpanel" tabindex="0"></div>
|
||||||
|
<div class="tab-pane fade" id="upgrade-tab-pane" role="tabpanel" tabindex="0"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal fade" id="editVehicleModal" tabindex="-1" role="dialog">
|
<div class="modal fade" id="editVehicleModal" tabindex="-1" role="dialog">
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
@model string
|
@model ImportMode
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title">Import Data from CSV</h5>
|
<h5 class="modal-title">Import Data from CSV</h5>
|
||||||
<button type="button" class="btn-close" onclick="hideBulkImportModal()" aria-label="Close"></button>
|
<button type="button" class="btn-close" onclick="hideBulkImportModal()" aria-label="Close"></button>
|
||||||
@@ -16,13 +16,13 @@
|
|||||||
<div class="alert alert-danger" role="alert">
|
<div class="alert alert-danger" role="alert">
|
||||||
Failure to format the data correctly can cause data corruption. Please make sure you make a copy of the local database before proceeding.
|
Failure to format the data correctly can cause data corruption. Please make sure you make a copy of the local database before proceeding.
|
||||||
</div>
|
</div>
|
||||||
@if (Model == "gasrecord")
|
@if (Model == ImportMode.GasRecord)
|
||||||
{
|
{
|
||||||
<a class="btn btn-link" href="/defaults/gassample.csv" target="_blank">Download Sample</a>
|
<a class="btn btn-link" href="/defaults/gassample.csv" target="_blank">Download Sample</a>
|
||||||
} else if (Model == "servicerecord" || Model == "repairrecord")
|
} else if (Model == ImportMode.ServiceRecord || Model == ImportMode.RepairRecord)
|
||||||
{
|
{
|
||||||
<a class="btn btn-link" href="/defaults/servicerecordsample.csv" target="_blank">Download Sample</a>
|
<a class="btn btn-link" href="/defaults/servicerecordsample.csv" target="_blank">Download Sample</a>
|
||||||
} else if (Model == "taxrecord")
|
} else if (Model == ImportMode.TaxRecord)
|
||||||
{
|
{
|
||||||
<a class="btn btn-link" href="/defaults/taxrecordsample.csv" target="_blank">Download Sample</a>
|
<a class="btn btn-link" href="/defaults/taxrecordsample.csv" target="_blank">Download Sample</a>
|
||||||
}
|
}
|
||||||
@@ -52,13 +52,13 @@
|
|||||||
if (data) {
|
if (data) {
|
||||||
successToast("Data Imported Successfully");
|
successToast("Data Imported Successfully");
|
||||||
hideBulkImportModal();
|
hideBulkImportModal();
|
||||||
if (mode == "gasrecord") {
|
if (mode == "GasRecord") {
|
||||||
getVehicleGasRecords(vehicleId);
|
getVehicleGasRecords(vehicleId);
|
||||||
} else if (mode == "servicerecord") {
|
} else if (mode == "ServiceRecord") {
|
||||||
getVehicleServiceRecords(vehicleId);
|
getVehicleServiceRecords(vehicleId);
|
||||||
} else if (mode == "repairrecord") {
|
} else if (mode == "RepairRecord") {
|
||||||
getVehicleCollisionRecords(vehicleId);
|
getVehicleCollisionRecords(vehicleId);
|
||||||
} else if (mode == "taxrecord") {
|
} else if (mode == "TaxRecord") {
|
||||||
getVehicleTaxRecords(vehicleId);
|
getVehicleTaxRecords(vehicleId);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -30,14 +30,7 @@
|
|||||||
@if (Model.Files.Any())
|
@if (Model.Files.Any())
|
||||||
{
|
{
|
||||||
<div>
|
<div>
|
||||||
<label>Uploaded Documents</label>
|
@await Html.PartialAsync("_UploadedFiles", Model.Files)
|
||||||
@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="deleteCollisionRecordFile('@filesUploaded.Location', this)"><i class="bi bi-trash"></i></button>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
<label for="collisionRecordFiles">Upload more documents</label>
|
<label for="collisionRecordFiles">Upload more documents</label>
|
||||||
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="collisionRecordFiles">
|
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="collisionRecordFiles">
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@inject IConfiguration Configuration
|
@inject IConfiguration Configuration
|
||||||
@{
|
@{
|
||||||
var enableCsvImports = bool.Parse(Configuration[nameof(UserConfig.EnableCsvImports)]);
|
var enableCsvImports = bool.Parse(Configuration[nameof(UserConfig.EnableCsvImports)]);
|
||||||
|
var hideZero = bool.Parse(Configuration[nameof(UserConfig.HideZero)]);
|
||||||
}
|
}
|
||||||
@model List<CollisionRecord>
|
@model List<CollisionRecord>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@@ -18,7 +19,7 @@
|
|||||||
<span class="visually-hidden">Toggle Dropdown</span>
|
<span class="visually-hidden">Toggle Dropdown</span>
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li><a class="dropdown-item" href="#" onclick="showBulkImportModal('repairrecord')">Import via CSV</a></li>
|
<li><a class="dropdown-item" href="#" onclick="showBulkImportModal('RepairRecord')">Import via CSV</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@@ -48,7 +49,7 @@
|
|||||||
<td class="col-1">@collisionRecord.Date.ToShortDateString()</td>
|
<td class="col-1">@collisionRecord.Date.ToShortDateString()</td>
|
||||||
<td class="col-2">@collisionRecord.Mileage</td>
|
<td class="col-2">@collisionRecord.Mileage</td>
|
||||||
<td class="col-4">@collisionRecord.Description</td>
|
<td class="col-4">@collisionRecord.Description</td>
|
||||||
<td class="col-2">@collisionRecord.Cost.ToString("C")</td>
|
<td class="col-2">@((hideZero && collisionRecord.Cost == default) ? "---" : collisionRecord.Cost.ToString("C"))</td>
|
||||||
<td class="col-3 text-truncate">@collisionRecord.Notes</td>
|
<td class="col-3 text-truncate">@collisionRecord.Notes</td>
|
||||||
</tr>
|
</tr>
|
||||||
}
|
}
|
||||||
@@ -58,7 +59,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="modal fade" id="collisionRecordModal" tabindex="-1" role="dialog" aria-hidden="true">
|
<div class="modal fade" data-bs-focus="false" id="collisionRecordModal" tabindex="-1" role="dialog" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-lg" role="document">
|
<div class="modal-dialog modal-lg" role="document">
|
||||||
<div class="modal-content" id="collisionRecordModalContent">
|
<div class="modal-content" id="collisionRecordModalContent">
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@model CostMakeUpForVehicle
|
@model CostMakeUpForVehicle
|
||||||
@if (Model.CollisionRecordSum + Model.ServiceRecordSum + Model.GasRecordSum + Model.TaxRecordSum > 0)
|
@if (Model.CollisionRecordSum + Model.ServiceRecordSum + Model.GasRecordSum + Model.TaxRecordSum + Model.UpgradeRecordSum > 0)
|
||||||
{
|
{
|
||||||
<canvas id="pie-chart"></canvas>
|
<canvas id="pie-chart"></canvas>
|
||||||
<script>
|
<script>
|
||||||
@@ -9,17 +9,18 @@
|
|||||||
new Chart($("#pie-chart"), {
|
new Chart($("#pie-chart"), {
|
||||||
type: 'pie',
|
type: 'pie',
|
||||||
data: {
|
data: {
|
||||||
labels: ["Planned Maintenance(Service Records)", "Unplanned Maintenance(Repairs)", "Tax", "Fuel"],
|
labels: ["Planned Maintenance(Service Records)", "Unplanned Maintenance(Repairs)", "Upgrades", "Tax", "Fuel"],
|
||||||
datasets: [
|
datasets: [
|
||||||
{
|
{
|
||||||
label: "Expenses by Category",
|
label: "Expenses by Category",
|
||||||
backgroundColor: ["#003f5c", "#58508d", "#bc5090", "#ff6361"],
|
backgroundColor: ["#003f5c", "#58508d", "#bc5090", "#ff6361", "#ffa600"],
|
||||||
data: [
|
data: [
|
||||||
@Model.ServiceRecordSum,
|
@Model.ServiceRecordSum,
|
||||||
@Model.CollisionRecordSum,
|
@Model.CollisionRecordSum,
|
||||||
|
@Model.UpgradeRecordSum,
|
||||||
@Model.TaxRecordSum,
|
@Model.TaxRecordSum,
|
||||||
@Model.GasRecordSum
|
@Model.GasRecordSum
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -41,7 +42,8 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
<h1>No data found or all records have zero sums, insert records with non-zero sums to see visualizations here.</h1>
|
<h1>No data found or all records have zero sums, insert records with non-zero sums to see visualizations here.</h1>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,16 +3,30 @@
|
|||||||
@{
|
@{
|
||||||
var enableCsvImports = bool.Parse(Configuration[nameof(UserConfig.EnableCsvImports)]);
|
var enableCsvImports = bool.Parse(Configuration[nameof(UserConfig.EnableCsvImports)]);
|
||||||
var useMPG = bool.Parse(Configuration[nameof(UserConfig.UseMPG)]);
|
var useMPG = bool.Parse(Configuration[nameof(UserConfig.UseMPG)]);
|
||||||
|
var useUKMPG = bool.Parse(Configuration[nameof(UserConfig.UseUKMPG)]);
|
||||||
|
var hideZero = bool.Parse(Configuration[nameof(UserConfig.HideZero)]);
|
||||||
var useKwh = Model.UseKwh;
|
var useKwh = Model.UseKwh;
|
||||||
string consumptionUnit;
|
string consumptionUnit;
|
||||||
string fuelEconomyUnit;
|
string fuelEconomyUnit;
|
||||||
|
string distanceUnit = useMPG ? "mi." : "km";
|
||||||
if (useKwh)
|
if (useKwh)
|
||||||
{
|
{
|
||||||
consumptionUnit = "kWh";
|
consumptionUnit = "kWh";
|
||||||
fuelEconomyUnit = useMPG ? "mi/kWh" : "kWh/100km";
|
fuelEconomyUnit = useMPG ? "mi./kWh" : "kWh/100km";
|
||||||
} else
|
}
|
||||||
|
else if (useMPG && useUKMPG)
|
||||||
{
|
{
|
||||||
consumptionUnit = useMPG ? "gal" : "l";
|
consumptionUnit = "imp gal";
|
||||||
|
fuelEconomyUnit = "mpg";
|
||||||
|
} else if (useUKMPG)
|
||||||
|
{
|
||||||
|
fuelEconomyUnit = "l/100mi.";
|
||||||
|
consumptionUnit = "l";
|
||||||
|
distanceUnit = "mi.";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
consumptionUnit = useMPG ? "US gal" : "l";
|
||||||
fuelEconomyUnit = useMPG ? "mpg" : "l/100km";
|
fuelEconomyUnit = useMPG ? "mpg" : "l/100km";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -37,7 +51,7 @@
|
|||||||
<span class="visually-hidden">Toggle Dropdown</span>
|
<span class="visually-hidden">Toggle Dropdown</span>
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li><a class="dropdown-item" href="#" onclick="showBulkImportModal('gasrecord')">Import via CSV</a></li>
|
<li><a class="dropdown-item" href="#" onclick="showBulkImportModal('GasRecord')">Import via CSV</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
} else {
|
} else {
|
||||||
@@ -51,7 +65,7 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr class="d-flex">
|
<tr class="d-flex">
|
||||||
<th scope="col" class="col-2">Date Refueled</th>
|
<th scope="col" class="col-2">Date Refueled</th>
|
||||||
<th scope="col" class="col-2">Odometer(@(useMPG ? "mi." : "km"))</th>
|
<th scope="col" class="col-2">Odometer(@(distanceUnit))</th>
|
||||||
<th scope="col" class="col-2">Consumption(@(consumptionUnit))</th>
|
<th scope="col" class="col-2">Consumption(@(consumptionUnit))</th>
|
||||||
<th scope="col" class="col-4">Fuel Economy(@(fuelEconomyUnit))</th>
|
<th scope="col" class="col-4">Fuel Economy(@(fuelEconomyUnit))</th>
|
||||||
<th scope="col" class="col-1">Cost</th>
|
<th scope="col" class="col-1">Cost</th>
|
||||||
@@ -66,8 +80,8 @@
|
|||||||
<td class="col-2">@gasRecord.Mileage</td>
|
<td class="col-2">@gasRecord.Mileage</td>
|
||||||
<td class="col-2">@gasRecord.Gallons.ToString("F")</td>
|
<td class="col-2">@gasRecord.Gallons.ToString("F")</td>
|
||||||
<td class="col-4">@(gasRecord.MilesPerGallon == 0 ? "---" : gasRecord.MilesPerGallon.ToString("F"))</td>
|
<td class="col-4">@(gasRecord.MilesPerGallon == 0 ? "---" : gasRecord.MilesPerGallon.ToString("F"))</td>
|
||||||
<td class="col-1">@gasRecord.Cost.ToString("C3")</td>
|
<td class="col-1">@((hideZero && gasRecord.Cost == default) ? "---" : gasRecord.Cost.ToString("C3"))</td>
|
||||||
<td class="col-1">@gasRecord.CostPerGallon.ToString("C3")</td>
|
<td class="col-1">@((hideZero && gasRecord.CostPerGallon == default) ? "---" : gasRecord.CostPerGallon.ToString("C3"))</td>
|
||||||
</tr>
|
</tr>
|
||||||
}
|
}
|
||||||
</tbody>
|
</tbody>
|
||||||
@@ -76,7 +90,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="modal fade" id="gasRecordModal" tabindex="-1" role="dialog" aria-hidden="true">
|
<div class="modal fade" data-bs-focus="false" id="gasRecordModal" tabindex="-1" role="dialog" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-lg" role="document">
|
<div class="modal-dialog modal-lg" role="document">
|
||||||
<div class="modal-content" id="gasRecordModalContent">
|
<div class="modal-content" id="gasRecordModalContent">
|
||||||
|
|
||||||
|
|||||||
@@ -2,17 +2,30 @@
|
|||||||
@model GasRecordInputContainer
|
@model GasRecordInputContainer
|
||||||
@{
|
@{
|
||||||
var useMPG = bool.Parse(Configuration[nameof(UserConfig.UseMPG)]);
|
var useMPG = bool.Parse(Configuration[nameof(UserConfig.UseMPG)]);
|
||||||
|
var useUKMPG = bool.Parse(Configuration[nameof(UserConfig.UseUKMPG)]);
|
||||||
var useKwh = Model.UseKwh;
|
var useKwh = Model.UseKwh;
|
||||||
var isNew = Model.GasRecord.Id == 0;
|
var isNew = Model.GasRecord.Id == 0;
|
||||||
string consumptionUnit;
|
string consumptionUnit;
|
||||||
|
string distanceUnit;
|
||||||
if (useKwh)
|
if (useKwh)
|
||||||
{
|
{
|
||||||
consumptionUnit = "kWh";
|
consumptionUnit = "kWh";
|
||||||
|
} else if (useUKMPG)
|
||||||
|
{
|
||||||
|
consumptionUnit = "liters";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
consumptionUnit = useMPG ? "gallons" : "liters";
|
consumptionUnit = useMPG ? "gallons" : "liters";
|
||||||
}
|
}
|
||||||
|
if (useUKMPG)
|
||||||
|
{
|
||||||
|
distanceUnit = "miles";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
distanceUnit = useMPG ? "miles" : "kilometers";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title">@(isNew ? "Add New Gas Record" : "Edit Gas Record")</h5>
|
<h5 class="modal-title">@(isNew ? "Add New Gas Record" : "Edit Gas Record")</h5>
|
||||||
@@ -29,7 +42,7 @@
|
|||||||
<input type="text" id="gasRecordDate" placeholder="Date refueled" class="form-control" value="@Model.GasRecord.Date">
|
<input type="text" id="gasRecordDate" placeholder="Date refueled" class="form-control" value="@Model.GasRecord.Date">
|
||||||
<span class="input-group-text"><i class="bi bi-calendar-event"></i></span>
|
<span class="input-group-text"><i class="bi bi-calendar-event"></i></span>
|
||||||
</div>
|
</div>
|
||||||
<label for="gasRecordMileage">Odometer Reading(@(useMPG ? "miles" : "kilometers"))</label>
|
<label for="gasRecordMileage">Odometer Reading(@distanceUnit)</label>
|
||||||
<input type="number" id="gasRecordMileage" class="form-control" placeholder="Odometer reading when refueled" value="@(isNew ? "" : Model.GasRecord.Mileage)">
|
<input type="number" id="gasRecordMileage" class="form-control" placeholder="Odometer reading when refueled" value="@(isNew ? "" : Model.GasRecord.Mileage)">
|
||||||
<label for="gasRecordGallons">Fuel Consumption(@(consumptionUnit))</label>
|
<label for="gasRecordGallons">Fuel Consumption(@(consumptionUnit))</label>
|
||||||
<input type="text" id="gasRecordGallons" class="form-control" placeholder="Amount of gas refueled" value="@(isNew ? "" : Model.GasRecord.Gallons)">
|
<input type="text" id="gasRecordGallons" class="form-control" placeholder="Amount of gas refueled" value="@(isNew ? "" : Model.GasRecord.Gallons)">
|
||||||
@@ -44,14 +57,7 @@
|
|||||||
@if (Model.GasRecord.Files.Any())
|
@if (Model.GasRecord.Files.Any())
|
||||||
{
|
{
|
||||||
<div>
|
<div>
|
||||||
<label>Uploaded Documents</label>
|
@await Html.PartialAsync("_UploadedFiles", Model.GasRecord.Files)
|
||||||
@foreach (UploadedFiles filesUploaded in Model.GasRecord.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>
|
<label for="gasRecordFiles">Upload more documents</label>
|
||||||
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="gasRecordFiles">
|
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="gasRecordFiles">
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -30,14 +30,7 @@
|
|||||||
@if (Model.Files.Any())
|
@if (Model.Files.Any())
|
||||||
{
|
{
|
||||||
<div>
|
<div>
|
||||||
<label>Uploaded Documents</label>
|
@await Html.PartialAsync("_UploadedFiles", Model.Files)
|
||||||
@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="deleteServiceRecordFile('@filesUploaded.Location', this)"><i class="bi bi-trash"></i></button>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
<label for="serviceRecordFiles">Upload more documents</label>
|
<label for="serviceRecordFiles">Upload more documents</label>
|
||||||
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="serviceRecordFiles">
|
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="serviceRecordFiles">
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@inject IConfiguration Configuration
|
@inject IConfiguration Configuration
|
||||||
@{
|
@{
|
||||||
var enableCsvImports = bool.Parse(Configuration[nameof(UserConfig.EnableCsvImports)]);
|
var enableCsvImports = bool.Parse(Configuration[nameof(UserConfig.EnableCsvImports)]);
|
||||||
|
var hideZero = bool.Parse(Configuration[nameof(UserConfig.HideZero)]);
|
||||||
}
|
}
|
||||||
@model List<ServiceRecord>
|
@model List<ServiceRecord>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@@ -18,7 +19,7 @@
|
|||||||
<span class="visually-hidden">Toggle Dropdown</span>
|
<span class="visually-hidden">Toggle Dropdown</span>
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li><a class="dropdown-item" href="#" onclick="showBulkImportModal('servicerecord')">Import via CSV</a></li>
|
<li><a class="dropdown-item" href="#" onclick="showBulkImportModal('ServiceRecord')">Import via CSV</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@@ -48,7 +49,7 @@
|
|||||||
<td class="col-1">@serviceRecord.Date.ToShortDateString()</td>
|
<td class="col-1">@serviceRecord.Date.ToShortDateString()</td>
|
||||||
<td class="col-2">@serviceRecord.Mileage</td>
|
<td class="col-2">@serviceRecord.Mileage</td>
|
||||||
<td class="col-4">@serviceRecord.Description</td>
|
<td class="col-4">@serviceRecord.Description</td>
|
||||||
<td class="col-2">@serviceRecord.Cost.ToString("C")</td>
|
<td class="col-2">@((hideZero && serviceRecord.Cost == default) ? "---" : serviceRecord.Cost.ToString("C"))</td>
|
||||||
<td class="col-3 text-truncate">@serviceRecord.Notes</td>
|
<td class="col-3 text-truncate">@serviceRecord.Notes</td>
|
||||||
</tr>
|
</tr>
|
||||||
}
|
}
|
||||||
@@ -58,7 +59,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="modal fade" id="serviceRecordModal" tabindex="-1" role="dialog" aria-hidden="true">
|
<div class="modal fade" data-bs-focus="false" id="serviceRecordModal" tabindex="-1" role="dialog" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-lg" role="document">
|
<div class="modal-dialog modal-lg" role="document">
|
||||||
<div class="modal-content" id="serviceRecordModalContent">
|
<div class="modal-content" id="serviceRecordModalContent">
|
||||||
|
|
||||||
|
|||||||
@@ -28,14 +28,7 @@
|
|||||||
@if (Model.Files.Any())
|
@if (Model.Files.Any())
|
||||||
{
|
{
|
||||||
<div>
|
<div>
|
||||||
<label>Uploaded Documents</label>
|
@await Html.PartialAsync("_UploadedFiles", Model.Files)
|
||||||
@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="deleteTaxRecordFile('@filesUploaded.Location', this)"><i class="bi bi-trash"></i></button>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
<label for="taxRecordFiles">Upload more documents</label>
|
<label for="taxRecordFiles">Upload more documents</label>
|
||||||
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="taxRecordFiles">
|
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="taxRecordFiles">
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@inject IConfiguration Configuration
|
@inject IConfiguration Configuration
|
||||||
@{
|
@{
|
||||||
var enableCsvImports = bool.Parse(Configuration[nameof(UserConfig.EnableCsvImports)]);
|
var enableCsvImports = bool.Parse(Configuration[nameof(UserConfig.EnableCsvImports)]);
|
||||||
|
var hideZero = bool.Parse(Configuration[nameof(UserConfig.HideZero)]);
|
||||||
}
|
}
|
||||||
@model List<TaxRecord>
|
@model List<TaxRecord>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@@ -46,7 +47,7 @@
|
|||||||
<tr class="d-flex" style="cursor:pointer;" onclick="showEditTaxRecordModal(@taxRecord.Id)">
|
<tr class="d-flex" style="cursor:pointer;" onclick="showEditTaxRecordModal(@taxRecord.Id)">
|
||||||
<td class="col-1">@taxRecord.Date.ToShortDateString()</td>
|
<td class="col-1">@taxRecord.Date.ToShortDateString()</td>
|
||||||
<td class="col-6">@taxRecord.Description</td>
|
<td class="col-6">@taxRecord.Description</td>
|
||||||
<td class="col-2">@taxRecord.Cost.ToString("C")</td>
|
<td class="col-2">@((hideZero && taxRecord.Cost == default) ? "---" : taxRecord.Cost.ToString("C"))</td>
|
||||||
<td class="col-3 text-truncate">@taxRecord.Notes</td>
|
<td class="col-3 text-truncate">@taxRecord.Notes</td>
|
||||||
</tr>
|
</tr>
|
||||||
}
|
}
|
||||||
@@ -56,7 +57,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="modal fade" id="taxRecordModal" tabindex="-1" role="dialog" aria-hidden="true">
|
<div class="modal fade" data-bs-focus="false" id="taxRecordModal" tabindex="-1" role="dialog" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-lg" role="document">
|
<div class="modal-dialog modal-lg" role="document">
|
||||||
<div class="modal-content" id="taxRecordModalContent">
|
<div class="modal-content" id="taxRecordModalContent">
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
84
Views/Vehicle/_UpgradeRecordModal.cshtml
Normal file
84
Views/Vehicle/_UpgradeRecordModal.cshtml
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
@model UpgradeRecordInput
|
||||||
|
@{
|
||||||
|
var isNew = Model.Id == 0;
|
||||||
|
}
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">@(isNew ? "Add New Upgrade Record" : "Edit Upgrade Record")</h5>
|
||||||
|
<button type="button" class="btn-close" onclick="hideAddUpgradeRecordModal()" 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="upgradeRecordDate">Date</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text" id="upgradeRecordDate" class="form-control" placeholder="Date upgrade/mods was installed" value="@Model.Date">
|
||||||
|
<span class="input-group-text"><i class="bi bi-calendar-event"></i></span>
|
||||||
|
</div>
|
||||||
|
<label for="upgradeRecordMileage">Odometer</label>
|
||||||
|
<input type="number" id="upgradeRecordMileage" class="form-control" placeholder="Odometer reading when upgraded/modded" value="@(isNew ? "" : Model.Mileage)">
|
||||||
|
<label for="upgradeRecordDescription">Description</label>
|
||||||
|
<input type="text" id="upgradeRecordDescription" class="form-control" placeholder="Description of item(s) upgraded/modded" value="@Model.Description">
|
||||||
|
<label for="upgradeRecordCost">Cost</label>
|
||||||
|
<input type="number" id="upgradeRecordCost" class="form-control" placeholder="Cost of the upgrade/mods" value="@(isNew ? "" : Model.Cost)">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 col-12">
|
||||||
|
<label for="upgradeRecordNotes">Notes(optional)</label>
|
||||||
|
<textarea id="upgradeRecordNotes" class="form-control" rows="5">@Model.Notes</textarea>
|
||||||
|
@if (Model.Files.Any())
|
||||||
|
{
|
||||||
|
<div>
|
||||||
|
@await Html.PartialAsync("_UploadedFiles", Model.Files)
|
||||||
|
<label for="upgradeRecordFiles">Upload more documents</label>
|
||||||
|
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="upgradeRecordFiles">
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
@if (isNew)
|
||||||
|
{
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" value="" id="addReminderCheck">
|
||||||
|
<label class="form-check-label" for="addReminderCheck">
|
||||||
|
Add Reminder
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<label for="upgradeRecordFiles">Upload documents(optional)</label>
|
||||||
|
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="upgradeRecordFiles">
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
@if (!isNew)
|
||||||
|
{
|
||||||
|
<button type="button" class="btn btn-danger" onclick="deleteUpgradeRecord(@Model.Id)" style="margin-right:auto;">Delete</button>
|
||||||
|
}
|
||||||
|
<button type="button" class="btn btn-secondary" onclick="hideAddUpgradeRecordModal()">Cancel</button>
|
||||||
|
@if (isNew)
|
||||||
|
{
|
||||||
|
<button type="button" class="btn btn-primary" onclick="saveUpgradeRecordToVehicle()">Add New Upgrade Record</button>
|
||||||
|
}
|
||||||
|
else if (!isNew)
|
||||||
|
{
|
||||||
|
<button type="button" class="btn btn-primary" onclick="saveUpgradeRecordToVehicle(true)">Edit Upgrade Record</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
var uploadedFiles = [];
|
||||||
|
getUploadedFilesFromModel();
|
||||||
|
function getUploadedFilesFromModel() {
|
||||||
|
@foreach (UploadedFiles filesUploaded in Model.Files)
|
||||||
|
{
|
||||||
|
@:uploadedFiles.push({ name: "@filesUploaded.Name", location: "@filesUploaded.Location" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function getUpgradeRecordModelData() {
|
||||||
|
return { id: @Model.Id}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
66
Views/Vehicle/_UpgradeRecords.cshtml
Normal file
66
Views/Vehicle/_UpgradeRecords.cshtml
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
@inject IConfiguration Configuration
|
||||||
|
@{
|
||||||
|
var enableCsvImports = bool.Parse(Configuration[nameof(UserConfig.EnableCsvImports)]);
|
||||||
|
var hideZero = bool.Parse(Configuration[nameof(UserConfig.HideZero)]);
|
||||||
|
}
|
||||||
|
@model List<UpgradeRecord>
|
||||||
|
<div class="row">
|
||||||
|
<div class="d-flex justify-content-between">
|
||||||
|
<div class="d-flex align-items-center flex-wrap">
|
||||||
|
<span class="ms-2 badge bg-success">@($"# of Upgrade Records: {Model.Count()}")</span>
|
||||||
|
<span class="ms-2 badge bg-primary">@($"Total: {Model.Sum(x => x.Cost).ToString("C")}")</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
@if (enableCsvImports)
|
||||||
|
{
|
||||||
|
<div class="btn-group">
|
||||||
|
<button onclick="showAddUpgradeRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>Add Upgrade Record</button>
|
||||||
|
<button type="button" class="btn btn-md btn-primary btn-md mt-1 mb-1 dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
|
<span class="visually-hidden">Toggle Dropdown</span>
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li><a class="dropdown-item" href="#" onclick="showBulkImportModal('UpgradeRecord')">Import via CSV</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<button onclick="showAddUpgradeRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>Add Upgrade 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-1">Date</th>
|
||||||
|
<th scope="col" class="col-2">Odometer</th>
|
||||||
|
<th scope="col" class="col-4">Description</th>
|
||||||
|
<th scope="col" class="col-2">Cost</th>
|
||||||
|
<th scope="col" class="col-3">Notes</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach (UpgradeRecord upgradeRecord in Model)
|
||||||
|
{
|
||||||
|
<tr class="d-flex" style="cursor:pointer;" onclick="showEditUpgradeRecordModal(@upgradeRecord.Id)">
|
||||||
|
<td class="col-1">@upgradeRecord.Date.ToShortDateString()</td>
|
||||||
|
<td class="col-2">@upgradeRecord.Mileage</td>
|
||||||
|
<td class="col-4">@upgradeRecord.Description</td>
|
||||||
|
<td class="col-2">@((hideZero && upgradeRecord.Cost == default) ? "---" : upgradeRecord.Cost.ToString("C"))</td>
|
||||||
|
<td class="col-3 text-truncate">@upgradeRecord.Notes</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal fade" data-bs-focus="false" id="upgradeRecordModal" tabindex="-1" role="dialog" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-lg" role="document">
|
||||||
|
<div class="modal-content" id="upgradeRecordModalContent">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
16
Views/Vehicle/_UploadedFiles.cshtml
Normal file
16
Views/Vehicle/_UploadedFiles.cshtml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
@model List<UploadedFiles>
|
||||||
|
<label>Uploaded Documents</label>
|
||||||
|
<ul class="list-group">
|
||||||
|
@foreach (UploadedFiles filesUploaded in Model)
|
||||||
|
{
|
||||||
|
<li class="list-group-item">
|
||||||
|
<div class="d-flex justify-content-between">
|
||||||
|
<a type="button" class="btn btn-link" href="@filesUploaded.Location" target="_blank">@filesUploaded.Name</a>
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-secondary me-2" onclick="editFileName('@filesUploaded.Location', this)"><i class="bi bi-pencil"></i></button>
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-danger" onclick="deleteFileFromUploadedFiles('@filesUploaded.Location', this)"><i class="bi bi-trash"></i></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
@@ -11,6 +11,8 @@
|
|||||||
"UseMPG": true,
|
"UseMPG": true,
|
||||||
"UseDescending": false,
|
"UseDescending": false,
|
||||||
"EnableAuth": false,
|
"EnableAuth": false,
|
||||||
|
"HideZero": false,
|
||||||
|
"UseUKMPG": false,
|
||||||
"UserNameHash": "",
|
"UserNameHash": "",
|
||||||
"UserPasswordHash": ""
|
"UserPasswordHash": ""
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
{"UseDarkMode":true,"UsekWh":false,"EnableCsvImports":false,"UseMPG":true,"UseDescending":false,"EnableAuth":false,"UserNameHash":"","UserPasswordHash":""}
|
{"UseDarkMode":true,"EnableCsvImports":false,"UseMPG":true,"UseDescending":false,"EnableAuth":false,"UserNameHash":"","UserPasswordHash":""}
|
||||||
@@ -121,8 +121,4 @@ function getAndValidateCollisionRecordValues() {
|
|||||||
files: uploadedFiles,
|
files: uploadedFiles,
|
||||||
addReminderRecord: addReminderRecord
|
addReminderRecord: addReminderRecord
|
||||||
}
|
}
|
||||||
}
|
|
||||||
function deleteCollisionRecordFile(fileLocation, event) {
|
|
||||||
event.parentElement.remove();
|
|
||||||
uploadedFiles = uploadedFiles.filter(x => x.location != fileLocation);
|
|
||||||
}
|
}
|
||||||
@@ -116,8 +116,4 @@ function getAndValidateGasRecordValues() {
|
|||||||
files: uploadedFiles,
|
files: uploadedFiles,
|
||||||
isFillToFull: gasIsFillToFull
|
isFillToFull: gasIsFillToFull
|
||||||
}
|
}
|
||||||
}
|
|
||||||
function deleteGasRecordFile(fileLocation, event) {
|
|
||||||
event.parentElement.remove();
|
|
||||||
uploadedFiles = uploadedFiles.filter(x => x.location != fileLocation);
|
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,8 @@
|
|||||||
if (data) {
|
if (data) {
|
||||||
$("#reminderRecordModalContent").html(data);
|
$("#reminderRecordModalContent").html(data);
|
||||||
$('#reminderDate').datepicker({
|
$('#reminderDate').datepicker({
|
||||||
startDate: "+0d"
|
startDate: "+0d",
|
||||||
|
format: getShortDatePattern().pattern
|
||||||
});
|
});
|
||||||
$("#reminderRecordModal").modal("show");
|
$("#reminderRecordModal").modal("show");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,8 +121,4 @@ function getAndValidateServiceRecordValues() {
|
|||||||
files: uploadedFiles,
|
files: uploadedFiles,
|
||||||
addReminderRecord: addReminderRecord
|
addReminderRecord: addReminderRecord
|
||||||
}
|
}
|
||||||
}
|
|
||||||
function deleteServiceRecordFile(fileLocation, event) {
|
|
||||||
event.parentElement.remove();
|
|
||||||
uploadedFiles = uploadedFiles.filter(x => x.location != fileLocation);
|
|
||||||
}
|
}
|
||||||
@@ -113,8 +113,4 @@ function getAndValidateTaxRecordValues() {
|
|||||||
files: uploadedFiles,
|
files: uploadedFiles,
|
||||||
addReminderRecord: addReminderRecord
|
addReminderRecord: addReminderRecord
|
||||||
}
|
}
|
||||||
}
|
|
||||||
function deleteTaxRecordFile(fileLocation, event) {
|
|
||||||
event.parentElement.remove();
|
|
||||||
uploadedFiles = uploadedFiles.filter(x => x.location != fileLocation);
|
|
||||||
}
|
}
|
||||||
124
wwwroot/js/upgraderecord.js
Normal file
124
wwwroot/js/upgraderecord.js
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
function showAddUpgradeRecordModal() {
|
||||||
|
$.get('/Vehicle/GetAddUpgradeRecordPartialView', function (data) {
|
||||||
|
if (data) {
|
||||||
|
$("#upgradeRecordModalContent").html(data);
|
||||||
|
//initiate datepicker
|
||||||
|
$('#upgradeRecordDate').datepicker({
|
||||||
|
endDate: "+0d",
|
||||||
|
format: getShortDatePattern().pattern
|
||||||
|
});
|
||||||
|
$('#upgradeRecordModal').modal('show');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function showEditUpgradeRecordModal(upgradeRecordId) {
|
||||||
|
$.get(`/Vehicle/GetUpgradeRecordForEditById?upgradeRecordId=${upgradeRecordId}`, function (data) {
|
||||||
|
if (data) {
|
||||||
|
$("#upgradeRecordModalContent").html(data);
|
||||||
|
//initiate datepicker
|
||||||
|
$('#upgradeRecordDate').datepicker({
|
||||||
|
endDate: "+0d",
|
||||||
|
format: getShortDatePattern().pattern
|
||||||
|
});
|
||||||
|
$('#upgradeRecordModal').modal('show');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function hideAddUpgradeRecordModal() {
|
||||||
|
$('#upgradeRecordModal').modal('hide');
|
||||||
|
}
|
||||||
|
function deleteUpgradeRecord(upgradeRecordId) {
|
||||||
|
$("#workAroundInput").show();
|
||||||
|
Swal.fire({
|
||||||
|
title: "Confirm Deletion?",
|
||||||
|
text: "Deleted Upgrade Records cannot be restored.",
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonText: "Delete",
|
||||||
|
confirmButtonColor: "#dc3545"
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
$.post(`/Vehicle/DeleteUpgradeRecordById?upgradeRecordId=${upgradeRecordId}`, function (data) {
|
||||||
|
if (data) {
|
||||||
|
hideAddUpgradeRecordModal();
|
||||||
|
successToast("Upgrade Record Deleted");
|
||||||
|
var vehicleId = GetVehicleId().vehicleId;
|
||||||
|
getVehicleUpgradeRecords(vehicleId);
|
||||||
|
} else {
|
||||||
|
errorToast("An error has occurred, please try again later.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$("#workAroundInput").hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function saveUpgradeRecordToVehicle(isEdit) {
|
||||||
|
//get values
|
||||||
|
var formValues = getAndValidateUpgradeRecordValues();
|
||||||
|
//validate
|
||||||
|
if (formValues.hasError) {
|
||||||
|
errorToast("Please check the form data");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//save to db.
|
||||||
|
$.post('/Vehicle/SaveUpgradeRecordToVehicleId', { upgradeRecord: formValues }, function (data) {
|
||||||
|
if (data) {
|
||||||
|
successToast(isEdit ? "Upgrade Record Updated" : "Upgrade Record Added.");
|
||||||
|
hideAddUpgradeRecordModal();
|
||||||
|
getVehicleUpgradeRecords(formValues.vehicleId);
|
||||||
|
if (formValues.addReminderRecord) {
|
||||||
|
setTimeout(function () { showAddReminderModal(formValues); }, 500);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
errorToast("An error has occurred, please try again later.");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function getAndValidateUpgradeRecordValues() {
|
||||||
|
var serviceDate = $("#upgradeRecordDate").val();
|
||||||
|
var serviceMileage = $("#upgradeRecordMileage").val();
|
||||||
|
var serviceDescription = $("#upgradeRecordDescription").val();
|
||||||
|
var serviceCost = $("#upgradeRecordCost").val();
|
||||||
|
var serviceNotes = $("#upgradeRecordNotes").val();
|
||||||
|
var vehicleId = GetVehicleId().vehicleId;
|
||||||
|
var upgradeRecordId = getUpgradeRecordModelData().id;
|
||||||
|
var addReminderRecord = $("#addReminderCheck").is(":checked");
|
||||||
|
//validation
|
||||||
|
var hasError = false;
|
||||||
|
if (serviceDate.trim() == '') { //eliminates whitespace.
|
||||||
|
hasError = true;
|
||||||
|
$("#upgradeRecordDate").addClass("is-invalid");
|
||||||
|
} else {
|
||||||
|
$("#upgradeRecordDate").removeClass("is-invalid");
|
||||||
|
}
|
||||||
|
if (serviceMileage.trim() == '' || parseInt(serviceMileage) < 0) {
|
||||||
|
hasError = true;
|
||||||
|
$("#upgradeRecordMileage").addClass("is-invalid");
|
||||||
|
} else {
|
||||||
|
$("#upgradeRecordMileage").removeClass("is-invalid");
|
||||||
|
}
|
||||||
|
if (serviceDescription.trim() == '') {
|
||||||
|
hasError = true;
|
||||||
|
$("#upgradeRecordDescription").addClass("is-invalid");
|
||||||
|
} else {
|
||||||
|
$("#upgradeRecordDescription").removeClass("is-invalid");
|
||||||
|
}
|
||||||
|
if (serviceCost.trim() == '') {
|
||||||
|
hasError = true;
|
||||||
|
$("#upgradeRecordCost").addClass("is-invalid");
|
||||||
|
} else {
|
||||||
|
$("#upgradeRecordCost").removeClass("is-invalid");
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
id: upgradeRecordId,
|
||||||
|
hasError: hasError,
|
||||||
|
vehicleId: vehicleId,
|
||||||
|
date: serviceDate,
|
||||||
|
mileage: serviceMileage,
|
||||||
|
description: serviceDescription,
|
||||||
|
cost: serviceCost,
|
||||||
|
notes: serviceNotes,
|
||||||
|
files: uploadedFiles,
|
||||||
|
addReminderRecord: addReminderRecord
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -37,6 +37,9 @@ $(document).ready(function () {
|
|||||||
case "reminder-tab":
|
case "reminder-tab":
|
||||||
getVehicleReminders(vehicleId);
|
getVehicleReminders(vehicleId);
|
||||||
break;
|
break;
|
||||||
|
case "upgrade-tab":
|
||||||
|
getVehicleUpgradeRecords(vehicleId);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
switch (e.relatedTarget.id) { //clear out previous tabs with grids in them to help with performance
|
switch (e.relatedTarget.id) { //clear out previous tabs with grids in them to help with performance
|
||||||
case "servicerecord-tab":
|
case "servicerecord-tab":
|
||||||
@@ -57,6 +60,9 @@ $(document).ready(function () {
|
|||||||
case "reminder-tab":
|
case "reminder-tab":
|
||||||
$("#reminder-tab-pane").html("");
|
$("#reminder-tab-pane").html("");
|
||||||
break;
|
break;
|
||||||
|
case "upgrade-tab":
|
||||||
|
$("#upgrade-tab-pane").html("");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
getVehicleServiceRecords(vehicleId);
|
getVehicleServiceRecords(vehicleId);
|
||||||
@@ -75,7 +81,15 @@ function getVehicleServiceRecords(vehicleId) {
|
|||||||
$("#servicerecord-tab-pane").html(data);
|
$("#servicerecord-tab-pane").html(data);
|
||||||
getVehicleHaveImportantReminders(vehicleId);
|
getVehicleHaveImportantReminders(vehicleId);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
}
|
||||||
|
function getVehicleUpgradeRecords(vehicleId) {
|
||||||
|
$.get(`/Vehicle/GetUpgradeRecordsByVehicleId?vehicleId=${vehicleId}`, function (data) {
|
||||||
|
if (data) {
|
||||||
|
$("#upgrade-tab-pane").html(data);
|
||||||
|
getVehicleHaveImportantReminders(vehicleId);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
function getVehicleGasRecords(vehicleId) {
|
function getVehicleGasRecords(vehicleId) {
|
||||||
$.get(`/Vehicle/GetGasRecordsByVehicleId?vehicleId=${vehicleId}`, function (data) {
|
$.get(`/Vehicle/GetGasRecordsByVehicleId?vehicleId=${vehicleId}`, function (data) {
|
||||||
@@ -190,7 +204,8 @@ function showAddReminderModal(reminderModalInput) {
|
|||||||
$.post('/Vehicle/GetAddReminderRecordPartialView', function (data) {
|
$.post('/Vehicle/GetAddReminderRecordPartialView', function (data) {
|
||||||
$("#reminderRecordModalContent").html(data);
|
$("#reminderRecordModalContent").html(data);
|
||||||
$('#reminderDate').datepicker({
|
$('#reminderDate').datepicker({
|
||||||
startDate: "+0d"
|
startDate: "+0d",
|
||||||
|
format: getShortDatePattern().pattern
|
||||||
});
|
});
|
||||||
$("#reminderRecordModal").modal("show");
|
$("#reminderRecordModal").modal("show");
|
||||||
});
|
});
|
||||||
@@ -212,4 +227,33 @@ function getVehicleHaveImportantReminders(vehicleId) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, 500);
|
}, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteFileFromUploadedFiles(fileLocation, event) {
|
||||||
|
event.parentElement.parentElement.parentElement.remove();
|
||||||
|
uploadedFiles = uploadedFiles.filter(x => x.location != fileLocation);
|
||||||
|
}
|
||||||
|
function editFileName(fileLocation, event) {
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Rename File',
|
||||||
|
html: `
|
||||||
|
<input type="text" id="newFileName" class="swal2-input" placeholder="New File Name">
|
||||||
|
`,
|
||||||
|
confirmButtonText: 'Rename',
|
||||||
|
focusConfirm: false,
|
||||||
|
preConfirm: () => {
|
||||||
|
const newFileName = $("#newFileName").val();
|
||||||
|
if (!newFileName) {
|
||||||
|
Swal.showValidationMessage(`Please enter a valid file name`)
|
||||||
|
}
|
||||||
|
return { newFileName }
|
||||||
|
},
|
||||||
|
}).then(function (result) {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
var linkDisplayObject = $(event.parentElement.parentElement).find('a')[0];
|
||||||
|
linkDisplayObject.text = result.value.newFileName;
|
||||||
|
var editFileIndex = uploadedFiles.findIndex(x => x.location == fileLocation);
|
||||||
|
uploadedFiles[editFileIndex].name = result.value.newFileName;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user