Merge pull request #125 from hargata/Hargata/to.do
V1.0.7 - Planner(Kanban), Recurring Reminders, Odometer Tab
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using CarCareTracker.External.Interfaces;
|
||||
using CarCareTracker.External.Implementations;
|
||||
using CarCareTracker.External.Interfaces;
|
||||
using CarCareTracker.Filter;
|
||||
using CarCareTracker.Helper;
|
||||
using CarCareTracker.Logic;
|
||||
@@ -20,6 +21,7 @@ namespace CarCareTracker.Controllers
|
||||
private readonly ITaxRecordDataAccess _taxRecordDataAccess;
|
||||
private readonly IReminderRecordDataAccess _reminderRecordDataAccess;
|
||||
private readonly IUpgradeRecordDataAccess _upgradeRecordDataAccess;
|
||||
private readonly IOdometerRecordDataAccess _odometerRecordDataAccess;
|
||||
private readonly IReminderHelper _reminderHelper;
|
||||
private readonly IGasHelper _gasHelper;
|
||||
private readonly IUserLogic _userLogic;
|
||||
@@ -34,6 +36,7 @@ namespace CarCareTracker.Controllers
|
||||
ITaxRecordDataAccess taxRecordDataAccess,
|
||||
IReminderRecordDataAccess reminderRecordDataAccess,
|
||||
IUpgradeRecordDataAccess upgradeRecordDataAccess,
|
||||
IOdometerRecordDataAccess odometerRecordDataAccess,
|
||||
IFileHelper fileHelper,
|
||||
IUserLogic userLogic)
|
||||
{
|
||||
@@ -45,6 +48,7 @@ namespace CarCareTracker.Controllers
|
||||
_taxRecordDataAccess = taxRecordDataAccess;
|
||||
_reminderRecordDataAccess = reminderRecordDataAccess;
|
||||
_upgradeRecordDataAccess = upgradeRecordDataAccess;
|
||||
_odometerRecordDataAccess = odometerRecordDataAccess;
|
||||
_gasHelper = gasHelper;
|
||||
_reminderHelper = reminderHelper;
|
||||
_userLogic = userLogic;
|
||||
@@ -106,6 +110,47 @@ namespace CarCareTracker.Controllers
|
||||
}
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
[HttpGet]
|
||||
[Route("/api/vehicle/odometerrecords")]
|
||||
public IActionResult OdometerRecords(int vehicleId)
|
||||
{
|
||||
var vehicleRecords = _odometerRecordDataAccess.GetOdometerRecordsByVehicleId(vehicleId);
|
||||
var result = vehicleRecords.Select(x => new OdometerRecordExportModel { Date = x.Date.ToShortDateString(), Odometer = x.Mileage.ToString(), Notes = x.Notes });
|
||||
return Json(result);
|
||||
}
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
[HttpPost]
|
||||
[Route("/api/vehicle/odometerrecords/add")]
|
||||
public IActionResult AddOdometerRecord(int vehicleId, OdometerRecordExportModel input)
|
||||
{
|
||||
var response = new OperationResponse();
|
||||
if (vehicleId == default)
|
||||
{
|
||||
response.Success = false;
|
||||
response.Message = "Must provide a valid vehicle id";
|
||||
return Json(response);
|
||||
}
|
||||
try
|
||||
{
|
||||
var odometerRecord = new OdometerRecord()
|
||||
{
|
||||
VehicleId = vehicleId,
|
||||
Date = DateTime.Parse(input.Date),
|
||||
Notes = string.IsNullOrWhiteSpace(input.Notes) ? "" : input.Notes,
|
||||
Mileage = int.Parse(input.Odometer)
|
||||
};
|
||||
_odometerRecordDataAccess.SaveOdometerRecordToVehicle(odometerRecord);
|
||||
response.Success = true;
|
||||
response.Message = "Odometer Record Added";
|
||||
return Json(response);
|
||||
} catch (Exception ex)
|
||||
{
|
||||
response.Success = false;
|
||||
response.Message = StaticHelper.GenericErrorMessage;
|
||||
return Json(response);
|
||||
}
|
||||
}
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
[HttpGet]
|
||||
[Route("/api/vehicle/gasrecords")]
|
||||
public IActionResult GasRecords(int vehicleId, bool useMPG, bool useUKMPG)
|
||||
{
|
||||
@@ -164,6 +209,11 @@ namespace CarCareTracker.Controllers
|
||||
{
|
||||
numbersArray.Add(upgradeRecords.Max(x => x.Mileage));
|
||||
}
|
||||
var odometerRecords = _odometerRecordDataAccess.GetOdometerRecordsByVehicleId(vehicleId);
|
||||
if (odometerRecords.Any())
|
||||
{
|
||||
numbersArray.Add(odometerRecords.Max(x => x.Mileage));
|
||||
}
|
||||
return numbersArray.Any() ? numbersArray.Max() : 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,8 @@ namespace CarCareTracker.Controllers
|
||||
private readonly IReminderRecordDataAccess _reminderRecordDataAccess;
|
||||
private readonly IUpgradeRecordDataAccess _upgradeRecordDataAccess;
|
||||
private readonly ISupplyRecordDataAccess _supplyRecordDataAccess;
|
||||
private readonly IPlanRecordDataAccess _planRecordDataAccess;
|
||||
private readonly IOdometerRecordDataAccess _odometerRecordDataAccess;
|
||||
private readonly IWebHostEnvironment _webEnv;
|
||||
private readonly IConfigHelper _config;
|
||||
private readonly IFileHelper _fileHelper;
|
||||
@@ -48,6 +50,8 @@ namespace CarCareTracker.Controllers
|
||||
IReminderRecordDataAccess reminderRecordDataAccess,
|
||||
IUpgradeRecordDataAccess upgradeRecordDataAccess,
|
||||
ISupplyRecordDataAccess supplyRecordDataAccess,
|
||||
IPlanRecordDataAccess planRecordDataAccess,
|
||||
IOdometerRecordDataAccess odometerRecordDataAccess,
|
||||
IUserLogic userLogic,
|
||||
IWebHostEnvironment webEnv,
|
||||
IConfigHelper config)
|
||||
@@ -66,6 +70,8 @@ namespace CarCareTracker.Controllers
|
||||
_reminderRecordDataAccess = reminderRecordDataAccess;
|
||||
_upgradeRecordDataAccess = upgradeRecordDataAccess;
|
||||
_supplyRecordDataAccess = supplyRecordDataAccess;
|
||||
_planRecordDataAccess = planRecordDataAccess;
|
||||
_odometerRecordDataAccess = odometerRecordDataAccess;
|
||||
_userLogic = userLogic;
|
||||
_webEnv = webEnv;
|
||||
_config = config;
|
||||
@@ -134,12 +140,13 @@ namespace CarCareTracker.Controllers
|
||||
_noteDataAccess.DeleteAllNotesByVehicleId(vehicleId) &&
|
||||
_reminderRecordDataAccess.DeleteAllReminderRecordsByVehicleId(vehicleId) &&
|
||||
_upgradeRecordDataAccess.DeleteAllUpgradeRecordsByVehicleId(vehicleId) &&
|
||||
_planRecordDataAccess.DeleteAllPlanRecordsByVehicleId(vehicleId) &&
|
||||
_supplyRecordDataAccess.DeleteAllSupplyRecordsByVehicleId(vehicleId) &&
|
||||
_userLogic.DeleteAllAccessToVehicle(vehicleId) &&
|
||||
_dataAccess.DeleteVehicle(vehicleId);
|
||||
return Json(result);
|
||||
}
|
||||
#region "Bulk Imports"
|
||||
#region "Bulk Imports and Exports"
|
||||
[HttpGet]
|
||||
public IActionResult GetBulkImportModalPartialView(ImportMode mode)
|
||||
{
|
||||
@@ -211,6 +218,24 @@ namespace CarCareTracker.Controllers
|
||||
return Json($"/{fileNameToExport}");
|
||||
}
|
||||
}
|
||||
else if (mode == ImportMode.OdometerRecord)
|
||||
{
|
||||
var fileNameToExport = $"temp/{Guid.NewGuid()}.csv";
|
||||
var fullExportFilePath = _fileHelper.GetFullFilePath(fileNameToExport, false);
|
||||
var vehicleRecords = _odometerRecordDataAccess.GetOdometerRecordsByVehicleId(vehicleId);
|
||||
if (vehicleRecords.Any())
|
||||
{
|
||||
var exportData = vehicleRecords.Select(x => new OdometerRecordExportModel { Date = x.Date.ToShortDateString(), Notes = x.Notes, Odometer = x.Mileage.ToString() });
|
||||
using (var writer = new StreamWriter(fullExportFilePath))
|
||||
{
|
||||
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
|
||||
{
|
||||
csv.WriteRecords(exportData);
|
||||
}
|
||||
}
|
||||
return Json($"/{fileNameToExport}");
|
||||
}
|
||||
}
|
||||
else if (mode == ImportMode.SupplyRecord)
|
||||
{
|
||||
var fileNameToExport = $"temp/{Guid.NewGuid()}.csv";
|
||||
@@ -218,14 +243,16 @@ namespace CarCareTracker.Controllers
|
||||
var vehicleRecords = _supplyRecordDataAccess.GetSupplyRecordsByVehicleId(vehicleId);
|
||||
if (vehicleRecords.Any())
|
||||
{
|
||||
var exportData = vehicleRecords.Select(x => new SupplyRecordExportModel {
|
||||
Date = x.Date.ToShortDateString(),
|
||||
Description = x.Description,
|
||||
Cost = x.Cost.ToString("C"),
|
||||
var exportData = vehicleRecords.Select(x => new SupplyRecordExportModel
|
||||
{
|
||||
Date = x.Date.ToShortDateString(),
|
||||
Description = x.Description,
|
||||
Cost = x.Cost.ToString("C"),
|
||||
PartNumber = x.PartNumber,
|
||||
PartQuantity = x.Quantity.ToString(),
|
||||
PartSupplier = x.PartSupplier,
|
||||
Notes = x.Notes });
|
||||
Notes = x.Notes
|
||||
});
|
||||
using (var writer = new StreamWriter(fullExportFilePath))
|
||||
{
|
||||
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
|
||||
@@ -254,6 +281,34 @@ namespace CarCareTracker.Controllers
|
||||
return Json($"/{fileNameToExport}");
|
||||
}
|
||||
}
|
||||
else if (mode == ImportMode.PlanRecord)
|
||||
{
|
||||
var fileNameToExport = $"temp/{Guid.NewGuid()}.csv";
|
||||
var fullExportFilePath = _fileHelper.GetFullFilePath(fileNameToExport, false);
|
||||
var vehicleRecords = _planRecordDataAccess.GetPlanRecordsByVehicleId(vehicleId);
|
||||
if (vehicleRecords.Any())
|
||||
{
|
||||
var exportData = vehicleRecords.Select(x => new PlanRecordExportModel
|
||||
{
|
||||
DateCreated = x.DateCreated.ToString("G"),
|
||||
DateModified = x.DateModified.ToString("G"),
|
||||
Description = x.Description,
|
||||
Cost = x.Cost.ToString("C"),
|
||||
Type = x.ImportMode.ToString(),
|
||||
Priority = x.Priority.ToString(),
|
||||
Progress = x.Progress.ToString(),
|
||||
Notes = x.Notes
|
||||
});
|
||||
using (var writer = new StreamWriter(fullExportFilePath))
|
||||
{
|
||||
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
|
||||
{
|
||||
csv.WriteRecords(exportData);
|
||||
}
|
||||
}
|
||||
return Json($"/{fileNameToExport}");
|
||||
}
|
||||
}
|
||||
else if (mode == ImportMode.GasRecord)
|
||||
{
|
||||
var fileNameToExport = $"temp/{Guid.NewGuid()}.csv";
|
||||
@@ -372,6 +427,36 @@ namespace CarCareTracker.Controllers
|
||||
};
|
||||
_serviceRecordDataAccess.SaveServiceRecordToVehicle(convertedRecord);
|
||||
}
|
||||
else if (mode == ImportMode.OdometerRecord)
|
||||
{
|
||||
var convertedRecord = new OdometerRecord()
|
||||
{
|
||||
VehicleId = vehicleId,
|
||||
Date = DateTime.Parse(importModel.Date),
|
||||
Mileage = int.Parse(importModel.Odometer, NumberStyles.Any),
|
||||
Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes
|
||||
};
|
||||
_odometerRecordDataAccess.SaveOdometerRecordToVehicle(convertedRecord);
|
||||
}
|
||||
else if (mode == ImportMode.PlanRecord)
|
||||
{
|
||||
var progressIsEnum = Enum.TryParse(importModel.Progress, out PlanProgress parsedProgress);
|
||||
var typeIsEnum = Enum.TryParse(importModel.Type, out ImportMode parsedType);
|
||||
var priorityIsEnum = Enum.TryParse(importModel.Priority, out PlanPriority parsedPriority);
|
||||
var convertedRecord = new PlanRecord()
|
||||
{
|
||||
VehicleId = vehicleId,
|
||||
DateCreated = DateTime.Parse(importModel.DateCreated),
|
||||
DateModified = DateTime.Parse(importModel.DateModified),
|
||||
Progress = parsedProgress,
|
||||
ImportMode = parsedType,
|
||||
Priority = parsedPriority,
|
||||
Description = string.IsNullOrWhiteSpace(importModel.Description) ? $"Plan Record on {importModel.DateCreated}" : importModel.Description,
|
||||
Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes,
|
||||
Cost = decimal.Parse(importModel.Cost, NumberStyles.Any)
|
||||
};
|
||||
_planRecordDataAccess.SavePlanRecordToVehicle(convertedRecord);
|
||||
}
|
||||
else if (mode == ImportMode.RepairRecord)
|
||||
{
|
||||
var convertedRecord = new CollisionRecord()
|
||||
@@ -959,6 +1044,11 @@ namespace CarCareTracker.Controllers
|
||||
{
|
||||
numbersArray.Add(upgradeRecords.Max(x => x.Mileage));
|
||||
}
|
||||
var odometerRecords = _odometerRecordDataAccess.GetOdometerRecordsByVehicleId(vehicleId);
|
||||
if (odometerRecords.Any())
|
||||
{
|
||||
numbersArray.Add(odometerRecords.Max(x => x.Mileage));
|
||||
}
|
||||
return numbersArray.Any() ? numbersArray.Max() : 0;
|
||||
}
|
||||
private List<ReminderRecordViewModel> GetRemindersAndUrgency(int vehicleId, DateTime dateCompare)
|
||||
@@ -973,7 +1063,37 @@ namespace CarCareTracker.Controllers
|
||||
public IActionResult GetVehicleHaveUrgentOrPastDueReminders(int vehicleId)
|
||||
{
|
||||
var result = GetRemindersAndUrgency(vehicleId, DateTime.Now);
|
||||
if (result.Where(x => x.Urgency == ReminderUrgency.VeryUrgent || x.Urgency == ReminderUrgency.PastDue).Any())
|
||||
//check for past due reminders that are eligible for recurring.
|
||||
var pastDueAndRecurring = result.Where(x => x.Urgency == ReminderUrgency.PastDue && x.IsRecurring);
|
||||
if (pastDueAndRecurring.Any())
|
||||
{
|
||||
foreach (ReminderRecordViewModel reminderRecord in pastDueAndRecurring)
|
||||
{
|
||||
//update based on recurring intervals.
|
||||
//pull reminderRecord based on ID
|
||||
var existingReminder = _reminderRecordDataAccess.GetReminderRecordById(reminderRecord.Id);
|
||||
if (existingReminder.Metric == ReminderMetric.Both)
|
||||
{
|
||||
existingReminder.Date = existingReminder.Date.AddMonths((int)existingReminder.ReminderMonthInterval);
|
||||
existingReminder.Mileage += (int)existingReminder.ReminderMileageInterval;
|
||||
}
|
||||
else if (existingReminder.Metric == ReminderMetric.Odometer)
|
||||
{
|
||||
existingReminder.Mileage += (int)existingReminder.ReminderMileageInterval;
|
||||
}
|
||||
else if (existingReminder.Metric == ReminderMetric.Date)
|
||||
{
|
||||
existingReminder.Date = existingReminder.Date.AddMonths((int)existingReminder.ReminderMonthInterval);
|
||||
}
|
||||
//save to db.
|
||||
_reminderRecordDataAccess.SaveReminderRecordToVehicle(existingReminder);
|
||||
//set urgency to not urgent so it gets excluded in count.
|
||||
reminderRecord.Urgency = ReminderUrgency.NotUrgent;
|
||||
}
|
||||
}
|
||||
//check for very urgent or past due reminders that were not eligible for recurring.
|
||||
var pastDueAndUrgentReminders = result.Where(x => x.Urgency == ReminderUrgency.VeryUrgent || x.Urgency == ReminderUrgency.PastDue);
|
||||
if (pastDueAndUrgentReminders.Any())
|
||||
{
|
||||
return Json(true);
|
||||
}
|
||||
@@ -1018,7 +1138,10 @@ namespace CarCareTracker.Controllers
|
||||
Notes = result.Notes,
|
||||
VehicleId = result.VehicleId,
|
||||
Mileage = result.Mileage,
|
||||
Metric = result.Metric
|
||||
Metric = result.Metric,
|
||||
IsRecurring = result.IsRecurring,
|
||||
ReminderMileageInterval = result.ReminderMileageInterval,
|
||||
ReminderMonthInterval = result.ReminderMonthInterval
|
||||
};
|
||||
return PartialView("_ReminderRecordModal", convertedResult);
|
||||
}
|
||||
@@ -1173,5 +1296,168 @@ namespace CarCareTracker.Controllers
|
||||
return Json(result);
|
||||
}
|
||||
#endregion
|
||||
#region "Plan Records"
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
[HttpGet]
|
||||
public IActionResult GetPlanRecordsByVehicleId(int vehicleId)
|
||||
{
|
||||
var result = _planRecordDataAccess.GetPlanRecordsByVehicleId(vehicleId);
|
||||
return PartialView("_PlanRecords", result);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult SavePlanRecordToVehicleId(PlanRecordInput planRecord)
|
||||
{
|
||||
//populate createdDate
|
||||
if (planRecord.Id == default)
|
||||
{
|
||||
planRecord.DateCreated = DateTime.Now.ToString("G");
|
||||
}
|
||||
planRecord.DateModified = DateTime.Now.ToString("G");
|
||||
//move files from temp.
|
||||
planRecord.Files = planRecord.Files.Select(x => { return new UploadedFiles { Name = x.Name, Location = _fileHelper.MoveFileFromTemp(x.Location, "documents/") }; }).ToList();
|
||||
var result = _planRecordDataAccess.SavePlanRecordToVehicle(planRecord.ToPlanRecord());
|
||||
return Json(result);
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GetAddPlanRecordPartialView()
|
||||
{
|
||||
return PartialView("_PlanRecordModal", new PlanRecordInput());
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult UpdatePlanRecordProgress(int planRecordId, PlanProgress planProgress, int odometer = 0)
|
||||
{
|
||||
var existingRecord = _planRecordDataAccess.GetPlanRecordById(planRecordId);
|
||||
existingRecord.Progress = planProgress;
|
||||
existingRecord.DateModified = DateTime.Now;
|
||||
var result = _planRecordDataAccess.SavePlanRecordToVehicle(existingRecord);
|
||||
if (planProgress == PlanProgress.Done)
|
||||
{
|
||||
//convert plan record to service/upgrade/repair record.
|
||||
if (existingRecord.ImportMode == ImportMode.ServiceRecord)
|
||||
{
|
||||
var newRecord = new ServiceRecord()
|
||||
{
|
||||
VehicleId = existingRecord.VehicleId,
|
||||
Date = DateTime.Now,
|
||||
Mileage = odometer,
|
||||
Description = existingRecord.Description,
|
||||
Cost = existingRecord.Cost,
|
||||
Notes = existingRecord.Notes,
|
||||
Files = existingRecord.Files
|
||||
};
|
||||
_serviceRecordDataAccess.SaveServiceRecordToVehicle(newRecord);
|
||||
}
|
||||
else if (existingRecord.ImportMode == ImportMode.RepairRecord)
|
||||
{
|
||||
var newRecord = new CollisionRecord()
|
||||
{
|
||||
VehicleId = existingRecord.VehicleId,
|
||||
Date = DateTime.Now,
|
||||
Mileage = odometer,
|
||||
Description = existingRecord.Description,
|
||||
Cost = existingRecord.Cost,
|
||||
Notes = existingRecord.Notes,
|
||||
Files = existingRecord.Files
|
||||
};
|
||||
_collisionRecordDataAccess.SaveCollisionRecordToVehicle(newRecord);
|
||||
}
|
||||
else if (existingRecord.ImportMode == ImportMode.UpgradeRecord)
|
||||
{
|
||||
var newRecord = new UpgradeRecord()
|
||||
{
|
||||
VehicleId = existingRecord.VehicleId,
|
||||
Date = DateTime.Now,
|
||||
Mileage = odometer,
|
||||
Description = existingRecord.Description,
|
||||
Cost = existingRecord.Cost,
|
||||
Notes = existingRecord.Notes,
|
||||
Files = existingRecord.Files
|
||||
};
|
||||
_upgradeRecordDataAccess.SaveUpgradeRecordToVehicle(newRecord);
|
||||
}
|
||||
}
|
||||
return Json(result);
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GetPlanRecordForEditById(int planRecordId)
|
||||
{
|
||||
var result = _planRecordDataAccess.GetPlanRecordById(planRecordId);
|
||||
//convert to Input object.
|
||||
var convertedResult = new PlanRecordInput
|
||||
{
|
||||
Id = result.Id,
|
||||
Description = result.Description,
|
||||
DateCreated = result.DateCreated.ToString("G"),
|
||||
DateModified = result.DateModified.ToString("G"),
|
||||
ImportMode = result.ImportMode,
|
||||
Priority = result.Priority,
|
||||
Progress = result.Progress,
|
||||
Cost = result.Cost,
|
||||
Notes = result.Notes,
|
||||
VehicleId = result.VehicleId,
|
||||
Files = result.Files
|
||||
};
|
||||
return PartialView("_PlanRecordModal", convertedResult);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult DeletePlanRecordById(int planRecordId)
|
||||
{
|
||||
var result = _planRecordDataAccess.DeletePlanRecordById(planRecordId);
|
||||
return Json(result);
|
||||
}
|
||||
#endregion
|
||||
#region "Odometer Records"
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
[HttpGet]
|
||||
public IActionResult GetOdometerRecordsByVehicleId(int vehicleId)
|
||||
{
|
||||
var result = _odometerRecordDataAccess.GetOdometerRecordsByVehicleId(vehicleId);
|
||||
bool _useDescending = _config.GetUserConfig(User).UseDescending;
|
||||
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("_OdometerRecords", result);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult SaveOdometerRecordToVehicleId(OdometerRecordInput odometerRecord)
|
||||
{
|
||||
//move files from temp.
|
||||
odometerRecord.Files = odometerRecord.Files.Select(x => { return new UploadedFiles { Name = x.Name, Location = _fileHelper.MoveFileFromTemp(x.Location, "documents/") }; }).ToList();
|
||||
var result = _odometerRecordDataAccess.SaveOdometerRecordToVehicle(odometerRecord.ToOdometerRecord());
|
||||
return Json(result);
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GetAddOdometerRecordPartialView()
|
||||
{
|
||||
return PartialView("_OdometerRecordModal", new OdometerRecordInput());
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GetOdometerRecordForEditById(int odometerRecordId)
|
||||
{
|
||||
var result = _odometerRecordDataAccess.GetOdometerRecordById(odometerRecordId);
|
||||
//convert to Input object.
|
||||
var convertedResult = new OdometerRecordInput
|
||||
{
|
||||
Id = result.Id,
|
||||
Date = result.Date.ToShortDateString(),
|
||||
Mileage = result.Mileage,
|
||||
Notes = result.Notes,
|
||||
VehicleId = result.VehicleId,
|
||||
Files = result.Files
|
||||
};
|
||||
return PartialView("_OdometerRecordModal", convertedResult);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult DeleteOdometerRecordById(int odometerRecordId)
|
||||
{
|
||||
var result = _odometerRecordDataAccess.DeleteOdometerRecordById(odometerRecordId);
|
||||
return Json(result);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
ReminderRecord = 5,
|
||||
NoteRecord = 6,
|
||||
SupplyRecord = 7,
|
||||
Dashboard = 8
|
||||
Dashboard = 8,
|
||||
PlanRecord = 9,
|
||||
OdometerRecord = 10
|
||||
}
|
||||
}
|
||||
|
||||
9
Enum/PlanPriority.cs
Normal file
9
Enum/PlanPriority.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace CarCareTracker.Models
|
||||
{
|
||||
public enum PlanPriority
|
||||
{
|
||||
Critical = 0,
|
||||
Normal = 1,
|
||||
Low = 2
|
||||
}
|
||||
}
|
||||
10
Enum/PlanProgress.cs
Normal file
10
Enum/PlanProgress.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace CarCareTracker.Models
|
||||
{
|
||||
public enum PlanProgress
|
||||
{
|
||||
Backlog = 0,
|
||||
InProgress = 1,
|
||||
Testing = 2,
|
||||
Done = 3
|
||||
}
|
||||
}
|
||||
13
Enum/ReminderMileageInterval.cs
Normal file
13
Enum/ReminderMileageInterval.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace CarCareTracker.Models
|
||||
{
|
||||
public enum ReminderMileageInterval
|
||||
{
|
||||
FiveHundredMiles = 500,
|
||||
OneThousandMiles = 1000,
|
||||
ThreeThousandMiles = 3000,
|
||||
FiveThousandMiles = 5000,
|
||||
SevenThousandFiveHundredMiles = 7500,
|
||||
TenThousandMiles = 10000,
|
||||
FiftyThousandMiles = 50000
|
||||
}
|
||||
}
|
||||
10
Enum/ReminderMonthInterval.cs
Normal file
10
Enum/ReminderMonthInterval.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace CarCareTracker.Models
|
||||
{
|
||||
public enum ReminderMonthInterval
|
||||
{
|
||||
ThreeMonths = 3,
|
||||
SixMonths = 6,
|
||||
OneYear = 12,
|
||||
FiveYears = 60
|
||||
}
|
||||
}
|
||||
57
External/Implementations/OdometerRecordDataAccess.cs
vendored
Normal file
57
External/Implementations/OdometerRecordDataAccess.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 OdometerRecordDataAccess : IOdometerRecordDataAccess
|
||||
{
|
||||
private static string dbName = StaticHelper.DbName;
|
||||
private static string tableName = "odometerrecords";
|
||||
public List<OdometerRecord> GetOdometerRecordsByVehicleId(int vehicleId)
|
||||
{
|
||||
using (var db = new LiteDatabase(dbName))
|
||||
{
|
||||
var table = db.GetCollection<OdometerRecord>(tableName);
|
||||
var odometerRecords = table.Find(Query.EQ(nameof(OdometerRecord.VehicleId), vehicleId));
|
||||
return odometerRecords.ToList() ?? new List<OdometerRecord>();
|
||||
};
|
||||
}
|
||||
public OdometerRecord GetOdometerRecordById(int odometerRecordId)
|
||||
{
|
||||
using (var db = new LiteDatabase(dbName))
|
||||
{
|
||||
var table = db.GetCollection<OdometerRecord>(tableName);
|
||||
return table.FindById(odometerRecordId);
|
||||
};
|
||||
}
|
||||
public bool DeleteOdometerRecordById(int odometerRecordId)
|
||||
{
|
||||
using (var db = new LiteDatabase(dbName))
|
||||
{
|
||||
var table = db.GetCollection<OdometerRecord>(tableName);
|
||||
table.Delete(odometerRecordId);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
public bool SaveOdometerRecordToVehicle(OdometerRecord odometerRecord)
|
||||
{
|
||||
using (var db = new LiteDatabase(dbName))
|
||||
{
|
||||
var table = db.GetCollection<OdometerRecord>(tableName);
|
||||
table.Upsert(odometerRecord);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
public bool DeleteAllOdometerRecordsByVehicleId(int vehicleId)
|
||||
{
|
||||
using (var db = new LiteDatabase(dbName))
|
||||
{
|
||||
var table = db.GetCollection<OdometerRecord>(tableName);
|
||||
var odometerRecords = table.DeleteMany(Query.EQ(nameof(OdometerRecord.VehicleId), vehicleId));
|
||||
return true;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
57
External/Implementations/PlanRecordDataAccess.cs
vendored
Normal file
57
External/Implementations/PlanRecordDataAccess.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 PlanRecordDataAccess : IPlanRecordDataAccess
|
||||
{
|
||||
private static string dbName = StaticHelper.DbName;
|
||||
private static string tableName = "planrecords";
|
||||
public List<PlanRecord> GetPlanRecordsByVehicleId(int vehicleId)
|
||||
{
|
||||
using (var db = new LiteDatabase(dbName))
|
||||
{
|
||||
var table = db.GetCollection<PlanRecord>(tableName);
|
||||
var planRecords = table.Find(Query.EQ(nameof(PlanRecord.VehicleId), vehicleId));
|
||||
return planRecords.ToList() ?? new List<PlanRecord>();
|
||||
};
|
||||
}
|
||||
public PlanRecord GetPlanRecordById(int planRecordId)
|
||||
{
|
||||
using (var db = new LiteDatabase(dbName))
|
||||
{
|
||||
var table = db.GetCollection<PlanRecord>(tableName);
|
||||
return table.FindById(planRecordId);
|
||||
};
|
||||
}
|
||||
public bool DeletePlanRecordById(int planRecordId)
|
||||
{
|
||||
using (var db = new LiteDatabase(dbName))
|
||||
{
|
||||
var table = db.GetCollection<PlanRecord>(tableName);
|
||||
table.Delete(planRecordId);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
public bool SavePlanRecordToVehicle(PlanRecord planRecord)
|
||||
{
|
||||
using (var db = new LiteDatabase(dbName))
|
||||
{
|
||||
var table = db.GetCollection<PlanRecord>(tableName);
|
||||
table.Upsert(planRecord);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
public bool DeleteAllPlanRecordsByVehicleId(int vehicleId)
|
||||
{
|
||||
using (var db = new LiteDatabase(dbName))
|
||||
{
|
||||
var table = db.GetCollection<PlanRecord>(tableName);
|
||||
var planRecords = table.DeleteMany(Query.EQ(nameof(PlanRecord.VehicleId), vehicleId));
|
||||
return true;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
13
External/Interfaces/IOdometerRecordDataAccess.cs
vendored
Normal file
13
External/Interfaces/IOdometerRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
using CarCareTracker.Models;
|
||||
|
||||
namespace CarCareTracker.External.Interfaces
|
||||
{
|
||||
public interface IOdometerRecordDataAccess
|
||||
{
|
||||
public List<OdometerRecord> GetOdometerRecordsByVehicleId(int vehicleId);
|
||||
public OdometerRecord GetOdometerRecordById(int odometerRecordId);
|
||||
public bool DeleteOdometerRecordById(int odometerRecordId);
|
||||
public bool SaveOdometerRecordToVehicle(OdometerRecord odometerRecord);
|
||||
public bool DeleteAllOdometerRecordsByVehicleId(int vehicleId);
|
||||
}
|
||||
}
|
||||
13
External/Interfaces/IPlanRecordDataAccess.cs
vendored
Normal file
13
External/Interfaces/IPlanRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
using CarCareTracker.Models;
|
||||
|
||||
namespace CarCareTracker.External.Interfaces
|
||||
{
|
||||
public interface IPlanRecordDataAccess
|
||||
{
|
||||
public List<PlanRecord> GetPlanRecordsByVehicleId(int vehicleId);
|
||||
public PlanRecord GetPlanRecordById(int planRecordId);
|
||||
public bool DeletePlanRecordById(int planRecordId);
|
||||
public bool SavePlanRecordToVehicle(PlanRecord planRecord);
|
||||
public bool DeleteAllPlanRecordsByVehicleId(int vehicleId);
|
||||
}
|
||||
}
|
||||
@@ -68,7 +68,7 @@ namespace CarCareTracker.Helper
|
||||
var filesToUpload = Directory.GetFiles(imagePath);
|
||||
foreach(string file in filesToUpload)
|
||||
{
|
||||
File.Copy(file, $"{existingPath}/{Path.GetFileName(file)}");
|
||||
File.Copy(file, $"{existingPath}/{Path.GetFileName(file)}", true);
|
||||
}
|
||||
}
|
||||
if (Directory.Exists(documentPath))
|
||||
@@ -82,7 +82,7 @@ namespace CarCareTracker.Helper
|
||||
var filesToUpload = Directory.GetFiles(documentPath);
|
||||
foreach (string file in filesToUpload)
|
||||
{
|
||||
File.Copy(file, $"{existingPath}/{Path.GetFileName(file)}");
|
||||
File.Copy(file, $"{existingPath}/{Path.GetFileName(file)}", true);
|
||||
}
|
||||
}
|
||||
if (File.Exists(dataPath))
|
||||
|
||||
@@ -21,7 +21,8 @@ namespace CarCareTracker.Helper
|
||||
Mileage = reminder.Mileage,
|
||||
Description = reminder.Description,
|
||||
Notes = reminder.Notes,
|
||||
Metric = reminder.Metric
|
||||
Metric = reminder.Metric,
|
||||
IsRecurring = reminder.IsRecurring
|
||||
};
|
||||
if (reminder.Metric == ReminderMetric.Both)
|
||||
{
|
||||
|
||||
@@ -8,6 +8,8 @@ namespace CarCareTracker.MapProfile
|
||||
public ImportMapper()
|
||||
{
|
||||
Map(m => m.Date).Name(["date", "fuelup_date"]);
|
||||
Map(m => m.DateCreated).Name(["datecreated"]);
|
||||
Map(m => m.DateModified).Name(["datemodified"]);
|
||||
Map(m => m.Odometer).Name(["odometer"]);
|
||||
Map(m => m.FuelConsumed).Name(["gallons", "liters", "litres", "consumption", "quantity", "fuelconsumed"]);
|
||||
Map(m => m.Cost).Name(["cost", "total cost", "totalcost", "total price"]);
|
||||
@@ -20,6 +22,9 @@ namespace CarCareTracker.MapProfile
|
||||
Map(m => m.PartSupplier).Name(["partsupplier"]);
|
||||
Map(m => m.PartQuantity).Name(["partquantity"]);
|
||||
Map(m => m.PartNumber).Name(["partnumber"]);
|
||||
Map(m => m.Progress).Name(["progress"]);
|
||||
Map(m => m.Type).Name(["type"]);
|
||||
Map(m => m.Priority).Name(["priority"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,11 @@
|
||||
public class ImportModel
|
||||
{
|
||||
public string Date { get; set; }
|
||||
public string DateCreated { get; set; }
|
||||
public string DateModified { get; set; }
|
||||
public string Type { get; set; }
|
||||
public string Priority { get; set; }
|
||||
public string Progress { get; set; }
|
||||
public string Odometer { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string Notes { get; set; }
|
||||
@@ -39,6 +44,12 @@
|
||||
public string Notes { get; set; }
|
||||
public string Cost { get; set; }
|
||||
}
|
||||
public class OdometerRecordExportModel
|
||||
{
|
||||
public string Date { get; set; }
|
||||
public string Odometer { get; set; }
|
||||
public string Notes { get; set; }
|
||||
}
|
||||
public class TaxRecordExportModel
|
||||
{
|
||||
public string Date { get; set; }
|
||||
@@ -65,4 +76,16 @@
|
||||
public string Metric { get; set; }
|
||||
public string Notes { get; set; }
|
||||
}
|
||||
public class PlanRecordExportModel
|
||||
{
|
||||
public string DateCreated { get; set; }
|
||||
public string DateModified { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string Notes { get; set; }
|
||||
public string Type { get; set; }
|
||||
public string Priority { get; set; }
|
||||
public string Progress { get; set; }
|
||||
public string Cost { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
12
Models/OdometerRecord/OdometerRecord.cs
Normal file
12
Models/OdometerRecord/OdometerRecord.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace CarCareTracker.Models
|
||||
{
|
||||
public class OdometerRecord
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public int VehicleId { get; set; }
|
||||
public DateTime Date { get; set; }
|
||||
public int Mileage { get; set; }
|
||||
public string Notes { get; set; }
|
||||
public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>();
|
||||
}
|
||||
}
|
||||
13
Models/OdometerRecord/OdometerRecordInput.cs
Normal file
13
Models/OdometerRecord/OdometerRecordInput.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace CarCareTracker.Models
|
||||
{
|
||||
public class OdometerRecordInput
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public int VehicleId { get; set; }
|
||||
public string Date { get; set; } = DateTime.Now.ToShortDateString();
|
||||
public int Mileage { get; set; }
|
||||
public string Notes { get; set; }
|
||||
public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>();
|
||||
public OdometerRecord ToOdometerRecord() { return new OdometerRecord { Id = Id, VehicleId = VehicleId, Date = DateTime.Parse(Date), Mileage = Mileage, Notes = Notes, Files = Files }; }
|
||||
}
|
||||
}
|
||||
8
Models/PlanRecord/PlanCostItem.cs
Normal file
8
Models/PlanRecord/PlanCostItem.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace CarCareTracker.Models
|
||||
{
|
||||
public class PlanCostItem
|
||||
{
|
||||
public string CostName { get; set; }
|
||||
public decimal CostAmount { get; set; }
|
||||
}
|
||||
}
|
||||
17
Models/PlanRecord/PlanRecord.cs
Normal file
17
Models/PlanRecord/PlanRecord.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace CarCareTracker.Models
|
||||
{
|
||||
public class PlanRecord
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public int VehicleId { get; set; }
|
||||
public DateTime DateCreated { get; set; }
|
||||
public DateTime DateModified { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string Notes { get; set; }
|
||||
public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>();
|
||||
public ImportMode ImportMode { get; set; }
|
||||
public PlanPriority Priority { get; set; }
|
||||
public PlanProgress Progress { get; set; }
|
||||
public decimal Cost { get; set; }
|
||||
}
|
||||
}
|
||||
30
Models/PlanRecord/PlanRecordInput.cs
Normal file
30
Models/PlanRecord/PlanRecordInput.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
namespace CarCareTracker.Models
|
||||
{
|
||||
public class PlanRecordInput
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public int VehicleId { get; set; }
|
||||
public string DateCreated { get; set; } = DateTime.Now.ToShortDateString();
|
||||
public string DateModified { get; set; } = DateTime.Now.ToShortDateString();
|
||||
public string Description { get; set; }
|
||||
public string Notes { get; set; }
|
||||
public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>();
|
||||
public ImportMode ImportMode { get; set; }
|
||||
public PlanPriority Priority { get; set; }
|
||||
public PlanProgress Progress { get; set; }
|
||||
public decimal Cost { get; set; }
|
||||
public PlanRecord ToPlanRecord() { return new PlanRecord {
|
||||
Id = Id,
|
||||
VehicleId = VehicleId,
|
||||
DateCreated = DateTime.Parse(DateCreated),
|
||||
DateModified = DateTime.Parse(DateModified),
|
||||
Description = Description,
|
||||
Notes = Notes,
|
||||
Files = Files,
|
||||
ImportMode = ImportMode,
|
||||
Cost = Cost,
|
||||
Priority = Priority,
|
||||
Progress = Progress
|
||||
}; }
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,9 @@
|
||||
public int Mileage { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string Notes { get; set; }
|
||||
public bool IsRecurring { get; set; } = false;
|
||||
public ReminderMileageInterval ReminderMileageInterval { get; set; } = ReminderMileageInterval.FiveThousandMiles;
|
||||
public ReminderMonthInterval ReminderMonthInterval { get; set; } = ReminderMonthInterval.OneYear;
|
||||
public ReminderMetric Metric { get; set; } = ReminderMetric.Date;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
public int Mileage { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string Notes { get; set; }
|
||||
public bool IsRecurring { get; set; } = false;
|
||||
public ReminderMileageInterval ReminderMileageInterval { get; set; } = ReminderMileageInterval.FiveThousandMiles;
|
||||
public ReminderMonthInterval ReminderMonthInterval { get; set; } = ReminderMonthInterval.OneYear;
|
||||
public ReminderMetric Metric { get; set; } = ReminderMetric.Date;
|
||||
public ReminderRecord ToReminderRecord() { return new ReminderRecord {
|
||||
Id = Id,
|
||||
@@ -16,6 +19,9 @@
|
||||
Mileage = Mileage,
|
||||
Description = Description,
|
||||
Metric = Metric,
|
||||
IsRecurring = IsRecurring,
|
||||
ReminderMileageInterval = ReminderMileageInterval,
|
||||
ReminderMonthInterval = ReminderMonthInterval,
|
||||
Notes = Notes }; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,5 +13,9 @@
|
||||
/// </summary>
|
||||
public ReminderMetric Metric { get; set; } = ReminderMetric.Date;
|
||||
public ReminderUrgency Urgency { get; set; } = ReminderUrgency.NotUrgent;
|
||||
/// <summary>
|
||||
/// Recurring Reminders
|
||||
/// </summary>
|
||||
public bool IsRecurring { get; set; } = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ builder.Services.AddSingleton<ITokenRecordDataAccess, TokenRecordDataAccess>();
|
||||
builder.Services.AddSingleton<IUserAccessDataAccess, UserAccessDataAccess>();
|
||||
builder.Services.AddSingleton<IUserConfigDataAccess, UserConfigDataAccess>();
|
||||
builder.Services.AddSingleton<ISupplyRecordDataAccess, SupplyRecordDataAccess>();
|
||||
builder.Services.AddSingleton<IPlanRecordDataAccess, PlanRecordDataAccess>();
|
||||
builder.Services.AddSingleton<IOdometerRecordDataAccess, OdometerRecordDataAccess>();
|
||||
|
||||
//configure helpers
|
||||
builder.Services.AddSingleton<IFileHelper, FileHelper>();
|
||||
|
||||
@@ -141,4 +141,38 @@
|
||||
No Params(must be root user)
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
<div class="row">
|
||||
<div class="col-1">
|
||||
GET
|
||||
</div>
|
||||
<div class="col-5">
|
||||
<code>/api/vehicle/odometerrecords</code>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
Returns a list of odometer records for the vehicle
|
||||
</div>
|
||||
<div class="col-3">
|
||||
vehicleId - Id of Vehicle
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-1">
|
||||
POST
|
||||
</div>
|
||||
<div class="col-5">
|
||||
<code>/api/vehicle/odometerrecords/add</code>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
Returns a list of odometer records for the vehicle
|
||||
</div>
|
||||
<div class="col-3">
|
||||
vehicleId - Id of Vehicle
|
||||
<br />
|
||||
Body(form-data): {<br />
|
||||
date - Date to be entered<br />
|
||||
odometer - Odometer reading<br />
|
||||
notes - notes(optional)<br />
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
@@ -70,6 +70,10 @@
|
||||
<input onChange="updateSettings()" class="form-check-input me-1" type="checkbox" value="GasRecord" id="gasRecordTab" @(Model.VisibleTabs.Contains(ImportMode.GasRecord) ? "checked" : "")>
|
||||
<label class="form-check-label stretched-link" for="gasRecordTab">Fuel</label>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<input onChange="updateSettings()" class="form-check-input me-1" type="checkbox" value="OdometerRecord" id="odometerRecordTab" @(Model.VisibleTabs.Contains(ImportMode.OdometerRecord) ? "checked" : "")>
|
||||
<label class="form-check-label stretched-link" for="odometerRecordTab">Odometer</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
@@ -90,6 +94,10 @@
|
||||
<input onChange="updateSettings()" class="form-check-input me-1" type="checkbox" value="SupplyRecord" id="supplyRecordTab" @(Model.VisibleTabs.Contains(ImportMode.SupplyRecord) ? "checked" : "")>
|
||||
<label class="form-check-label stretched-link" for="supplyRecordTab">Supplies</label>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<input onChange="updateSettings()" class="form-check-input me-1" type="checkbox" value="PlanRecord" id="planRecordTab" @(Model.VisibleTabs.Contains(ImportMode.PlanRecord) ? "checked" : "")>
|
||||
<label class="form-check-label stretched-link" for="planRecordTab">Planner</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -106,6 +114,8 @@
|
||||
<!option @(StaticHelper.DefaultTabSelected(Model, ImportMode.NoteRecord)) value="NoteRecord">Notes</!option>
|
||||
<!option @(StaticHelper.DefaultTabSelected(Model, ImportMode.ReminderRecord)) value="ReminderRecord">Reminders</!option>
|
||||
<!option @(StaticHelper.DefaultTabSelected(Model, ImportMode.SupplyRecord)) value="SupplyRecord">Supplies</!option>
|
||||
<!option @(StaticHelper.DefaultTabSelected(Model, ImportMode.PlanRecord)) value="PlanRecord">Planner</!option>
|
||||
<!option @(StaticHelper.DefaultTabSelected(Model, ImportMode.OdometerRecord)) value="OdometerRecord">Odometer</!option>
|
||||
</select>
|
||||
</div>
|
||||
@if (User.IsInRole(nameof(UserData.IsRootUser)))
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
<script src="~/js/note.js" asp-append-version="true"></script>
|
||||
<script src="~/js/reports.js" asp-append-version="true"></script>
|
||||
<script src="~/js/supplyrecord.js" asp-append-version="true"></script>
|
||||
<script src="~/js/planrecord.js" asp-append-version="true"></script>
|
||||
<script src="~/js/odometerrecord.js" asp-append-version="true"></script>
|
||||
<script src="~/lib/chart-js/chart.umd.js"></script>
|
||||
}
|
||||
<div class="lubelogger-mobile-nav" onclick="hideMobileNav()">
|
||||
@@ -31,6 +33,12 @@
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.Dashboard)" 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>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.PlanRecord)" id="plan-tab" data-bs-toggle="tab" data-bs-target="#plan-tab-pane" type="button" role="tab" aria-selected="false"><span class="display-3 ms-2"><i class="bi bi-bar-chart-steps me-2"></i>Planner</span></button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.OdometerRecord)" id="odometer-tab" data-bs-toggle="tab" data-bs-target="#odometer-tab-pane" type="button" role="tab" aria-selected="false"><span class="display-3 ms-2"><i class="bi bi-speedometer me-2"></i>Odometer</span></button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.ServiceRecord)" id="servicerecord-tab" data-bs-toggle="tab" data-bs-target="#servicerecord-tab-pane" type="button" role="tab" aria-selected="true"><span class="display-3 ms-2"><i class="bi bi-card-checklist me-2"></i>Service Records</span></button>
|
||||
</li>
|
||||
@@ -76,6 +84,12 @@
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.Dashboard)" id="report-tab" data-bs-toggle="tab" data-bs-target="#report-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-file-bar-graph me-2"></i>Dash</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.PlanRecord)" id="plan-tab" data-bs-toggle="tab" data-bs-target="#plan-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-bar-chart-steps me-2"></i>Planner</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.OdometerRecord)" id="odometer-tab" data-bs-toggle="tab" data-bs-target="#odometer-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-speedometer me-2"></i>Odometer</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.ServiceRecord)" id="servicerecord-tab" data-bs-toggle="tab" data-bs-target="#servicerecord-tab-pane" type="button" role="tab" aria-selected="true"><i class="bi bi-card-checklist me-2"></i>Service Records</button>
|
||||
</li>
|
||||
@@ -117,6 +131,8 @@
|
||||
<div class="tab-pane fade @StaticHelper.DefaultActiveTabContent(userConfig, ImportMode.Dashboard)" id="report-tab-pane" role="tabpanel" tabindex="0"></div>
|
||||
<div class="tab-pane fade @StaticHelper.DefaultActiveTabContent(userConfig, ImportMode.UpgradeRecord)" id="upgrade-tab-pane" role="tabpanel" tabindex="0"></div>
|
||||
<div class="tab-pane fade @StaticHelper.DefaultActiveTabContent(userConfig, ImportMode.SupplyRecord)" id="supply-tab-pane" role="tabpanel" tabindex="0"></div>
|
||||
<div class="tab-pane fade @StaticHelper.DefaultActiveTabContent(userConfig, ImportMode.PlanRecord)" id="plan-tab-pane" role="tabpanel" tabindex="0"></div>
|
||||
<div class="tab-pane fade @StaticHelper.DefaultActiveTabContent(userConfig, ImportMode.OdometerRecord)" id="odometer-tab-pane" role="tabpanel" tabindex="0"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal fade" id="editVehicleModal" tabindex="-1" role="dialog">
|
||||
|
||||
@@ -28,6 +28,12 @@
|
||||
} else if (Model == ImportMode.SupplyRecord)
|
||||
{
|
||||
<a class="btn btn-link" href="/defaults/supplysample.csv" target="_blank">Download Sample</a>
|
||||
} else if (Model == ImportMode.PlanRecord)
|
||||
{
|
||||
<a class="btn btn-link" href="/defaults/plansample.csv" target="_blank">Download Sample</a>
|
||||
} else if (Model == ImportMode.OdometerRecord)
|
||||
{
|
||||
<a class="btn btn-link" href="/defaults/odometersample.csv" target="_blank">Download Sample</a>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
@@ -67,6 +73,10 @@
|
||||
getVehicleUpgradeRecords(vehicleId);
|
||||
} else if (mode == "SupplyRecord") {
|
||||
getVehicleSupplyRecords(vehicleId);
|
||||
} else if (mode == "PlanRecord"){
|
||||
getVehiclePlanRecords(vehicleId);
|
||||
} else if (mode == "OdometerRecord") {
|
||||
getVehicleOdometerRecords(vehicleId);
|
||||
}
|
||||
} else {
|
||||
errorToast("An error has occurred, please double check the data and try again.");
|
||||
|
||||
71
Views/Vehicle/_OdometerRecordModal.cshtml
Normal file
71
Views/Vehicle/_OdometerRecordModal.cshtml
Normal file
@@ -0,0 +1,71 @@
|
||||
@model OdometerRecordInput
|
||||
@{
|
||||
var isNew = Model.Id == 0;
|
||||
}
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">@(isNew ? "Add New Odometer Record" : "Edit Odometer Record")</h5>
|
||||
<button type="button" class="btn-close" onclick="hideAddOdometerRecordModal()" 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="odometerRecordDate">Date</label>
|
||||
<div class="input-group">
|
||||
<input type="text" id="odometerRecordDate" class="form-control" placeholder="Date recorded" value="@Model.Date">
|
||||
<span class="input-group-text"><i class="bi bi-calendar-event"></i></span>
|
||||
</div>
|
||||
<label for="odometerRecordMileage">Odometer</label>
|
||||
<input type="number" id="odometerRecordMileage" class="form-control" placeholder="Odometer reading" value="@(isNew ? "" : Model.Mileage)">
|
||||
</div>
|
||||
<div class="col-md-6 col-12">
|
||||
<label for="odometerRecordNotes">Notes(optional)</label>
|
||||
<textarea id="odometerRecordNotes" class="form-control" rows="5">@Model.Notes</textarea>
|
||||
@if (Model.Files.Any())
|
||||
{
|
||||
<div>
|
||||
@await Html.PartialAsync("_UploadedFiles", Model.Files)
|
||||
<label for="odometerRecordFiles">Upload more documents</label>
|
||||
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="odometerRecordFiles">
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<label for="odometerRecordFiles">Upload documents(optional)</label>
|
||||
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="odometerRecordFiles">
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
@if (!isNew)
|
||||
{
|
||||
<button type="button" class="btn btn-danger" onclick="deleteOdometerRecord(@Model.Id)" style="margin-right:auto;">Delete</button>
|
||||
}
|
||||
<button type="button" class="btn btn-secondary" onclick="hideAddOdometerRecordModal()">Cancel</button>
|
||||
@if (isNew)
|
||||
{
|
||||
<button type="button" class="btn btn-primary" onclick="saveOdometerRecordToVehicle()">Add New Odometer Record</button>
|
||||
}
|
||||
else if (!isNew)
|
||||
{
|
||||
<button type="button" class="btn btn-primary" onclick="saveOdometerRecordToVehicle(true)">Edit Odometer Record</button>
|
||||
}
|
||||
</div>
|
||||
<script>
|
||||
var uploadedFiles = [];
|
||||
getUploadedFilesFromModel();
|
||||
function getUploadedFilesFromModel() {
|
||||
@foreach (UploadedFiles filesUploaded in Model.Files)
|
||||
{
|
||||
@:uploadedFiles.push({ name: "@filesUploaded.Name", location: "@filesUploaded.Location" });
|
||||
}
|
||||
}
|
||||
function getOdometerRecordModelData() {
|
||||
return { id: @Model.Id}
|
||||
}
|
||||
</script>
|
||||
69
Views/Vehicle/_OdometerRecords.cshtml
Normal file
69
Views/Vehicle/_OdometerRecords.cshtml
Normal file
@@ -0,0 +1,69 @@
|
||||
@using CarCareTracker.Helper
|
||||
@inject IConfigHelper config
|
||||
@{
|
||||
var enableCsvImports = config.GetUserConfig(User).EnableCsvImports;
|
||||
var hideZero = config.GetUserConfig(User).HideZero;
|
||||
}
|
||||
@model List<OdometerRecord>
|
||||
<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 Odometer Records: {Model.Count()}")</span>
|
||||
</div>
|
||||
<div>
|
||||
@if (enableCsvImports)
|
||||
{
|
||||
<div class="btn-group">
|
||||
<button onclick="showAddOdometerRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>Add Odometer 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('OdometerRecord')">Import via CSV</a></li>
|
||||
<li><a class="dropdown-item" href="#" onclick="exportVehicleData('OdometerRecord')">Export to CSV</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button onclick="showAddOdometerRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>Add Odometer Record</button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row vehicleDetailTabContainer">
|
||||
<div class="col-12">
|
||||
<div class="row mt-2 showOnPrint">
|
||||
<div class="d-flex">
|
||||
<img src="/defaults/lubelogger_logo.png" />
|
||||
</div>
|
||||
</div>
|
||||
<table class="table table-hover">
|
||||
<thead class="sticky-top">
|
||||
<tr class="d-flex">
|
||||
<th scope="col" class="col-2 col-xl-1">Date</th>
|
||||
<th scope="col" class="col-3">Odometer</th>
|
||||
<th scope="col" class="col-7 col-xl-8">Notes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (OdometerRecord odometerRecord in Model)
|
||||
{
|
||||
<tr class="d-flex" style="cursor:pointer;" onclick="showEditOdometerRecordModal(@odometerRecord.Id)">
|
||||
<td class="col-2 col-xl-1">@odometerRecord.Date.ToShortDateString()</td>
|
||||
<td class="col-3">@odometerRecord.Mileage</td>
|
||||
<td class="col-7 col-xl-8 text-truncate">@CarCareTracker.Helper.StaticHelper.TruncateStrings(odometerRecord.Notes)</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="modal fade" data-bs-focus="false" id="odometerRecordModal" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content" id="odometerRecordModalContent">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
49
Views/Vehicle/_PlanRecordItem.cshtml
Normal file
49
Views/Vehicle/_PlanRecordItem.cshtml
Normal file
@@ -0,0 +1,49 @@
|
||||
@model PlanRecord
|
||||
<div class="taskCard @(Model.Progress == PlanProgress.Done ? "nodrag" : "") text-dark user-select-none mb-2" draggable="@(Model.Progress == PlanProgress.Done ? "false" : "true")" ondragstart="dragStart(event, @Model.Id)" onclick="@(Model.Progress == PlanProgress.Done ? $"deletePlanRecord({Model.Id})" : $"showEditPlanRecordModal({Model.Id})")">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-12 col-lg-8 text-truncate">
|
||||
@if (Model.Progress == PlanProgress.Done)
|
||||
{
|
||||
<span class="taskCard-title text-truncate"><s>@Model.Description</s></span>
|
||||
} else
|
||||
{
|
||||
<span class="taskCard-title text-truncate">@Model.Description</span>
|
||||
}
|
||||
</div>
|
||||
<div class="col-12 col-lg-4 d-flex align-items-center">
|
||||
<span class="text-truncate">@Model.Cost.ToString("C2")</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-6 col-md-1">
|
||||
@if (Model.ImportMode == ImportMode.ServiceRecord)
|
||||
{
|
||||
<i class="bi bi-card-checklist"></i>
|
||||
}
|
||||
else if (Model.ImportMode == ImportMode.UpgradeRecord)
|
||||
{
|
||||
<i class="bi bi-wrench-adjustable"></i>
|
||||
}
|
||||
else if (Model.ImportMode == ImportMode.RepairRecord)
|
||||
{
|
||||
<i class="bi bi-exclamation-octagon"></i>
|
||||
}
|
||||
</div>
|
||||
<div class="col-6 col-md-1">
|
||||
@if (Model.Priority == PlanPriority.Critical)
|
||||
{
|
||||
<i class="bi bi-fire"></i>
|
||||
}
|
||||
else if (Model.Priority == PlanPriority.Normal)
|
||||
{
|
||||
<i class="bi bi-water"></i>
|
||||
}
|
||||
else if (Model.Priority == PlanPriority.Low)
|
||||
{
|
||||
<i class="bi bi-snow"></i>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
94
Views/Vehicle/_PlanRecordModal.cshtml
Normal file
94
Views/Vehicle/_PlanRecordModal.cshtml
Normal file
@@ -0,0 +1,94 @@
|
||||
@model PlanRecordInput
|
||||
@{
|
||||
var isNew = Model.Id == 0;
|
||||
}
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">@(isNew ? "Add New Plan Record" : "Edit Plan Record")</h5>
|
||||
<button type="button" class="btn-close" onclick="hideAddPlanRecordModal()" 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="planRecordDescription">Description</label>
|
||||
<input type="text" id="planRecordDescription" class="form-control" placeholder="Describe the Plan" value="@Model.Description">
|
||||
<label for="planRecordCost">Cost</label>
|
||||
<input type="text" id="planRecordCost" class="form-control" placeholder="Cost of the Plan" value="@Model.Cost">
|
||||
<label for="planRecordType">Type</label>
|
||||
<select class="form-select" id="planRecordType">
|
||||
<!option value="ServiceRecord" @(Model.ImportMode == ImportMode.ServiceRecord || isNew ? "selected" : "")>Service</!option>
|
||||
<!option value="RepairRecord" @(Model.ImportMode == ImportMode.RepairRecord ? "selected" : "")>Repair</!option>
|
||||
<!option value="UpgradeRecord" @(Model.ImportMode == ImportMode.UpgradeRecord ? "selected" : "")>Upgrade</!option>
|
||||
</select>
|
||||
<label for="planRecordPriority">Priority</label>
|
||||
<select class="form-select" id="planRecordPriority">
|
||||
<!option value="Critical" @(Model.Priority == PlanPriority.Critical ? "selected" : "")>Critical</!option>
|
||||
<!option value="Normal" @(Model.Priority == PlanPriority.Normal || isNew ? "selected" : "")>Normal</!option>
|
||||
<!option value="Low" @(Model.Priority == PlanPriority.Low ? "selected" : "")>Low</!option>
|
||||
</select>
|
||||
<label for="planRecordProgress">Current Stage</label>
|
||||
<select class="form-select" id="planRecordProgress">
|
||||
<!option value="Backlog" @(Model.Progress == PlanProgress.Backlog ||isNew ? "selected" : "")>Planned</!option>
|
||||
<!option value="InProgress" @(Model.Progress == PlanProgress.InProgress ? "selected" : "")>Doing</!option>
|
||||
<!option value="Testing" @(Model.Progress == PlanProgress.Testing ? "selected" : "")>Testing</!option>
|
||||
</select>
|
||||
@if (!isNew)
|
||||
{
|
||||
<label>Date Created: @Model.DateCreated</label>
|
||||
<label>Last Modified: @Model.DateModified</label>
|
||||
}
|
||||
</div>
|
||||
<div class="col-md-6 col-12">
|
||||
<label for="planRecordNotes">Notes(optional)</label>
|
||||
<textarea id="planRecordNotes" class="form-control" rows="5">@Model.Notes</textarea>
|
||||
@if (Model.Files.Any())
|
||||
{
|
||||
<div>
|
||||
@await Html.PartialAsync("_UploadedFiles", Model.Files)
|
||||
<label for="planRecordFiles">Upload more documents</label>
|
||||
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="planRecordFiles">
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<label for="planRecordFiles">Upload documents(optional)</label>
|
||||
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="planRecordFiles">
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
@if (!isNew)
|
||||
{
|
||||
<button type="button" class="btn btn-danger" onclick="deletePlanRecord(@Model.Id)" style="margin-right:auto;">Delete</button>
|
||||
}
|
||||
<button type="button" class="btn btn-secondary" onclick="hideAddPlanRecordModal()">Cancel</button>
|
||||
@if (isNew)
|
||||
{
|
||||
<button type="button" class="btn btn-primary" onclick="savePlanRecordToVehicle()">Add New Plan Record</button>
|
||||
}
|
||||
else if (!isNew)
|
||||
{
|
||||
<button type="button" class="btn btn-primary" onclick="savePlanRecordToVehicle(true)">Edit Plan Record</button>
|
||||
}
|
||||
</div>
|
||||
<script>
|
||||
var uploadedFiles = [];
|
||||
getUploadedFilesFromModel();
|
||||
function getUploadedFilesFromModel() {
|
||||
@foreach (UploadedFiles filesUploaded in Model.Files)
|
||||
{
|
||||
@:uploadedFiles.push({ name: "@filesUploaded.Name", location: "@filesUploaded.Location" });
|
||||
}
|
||||
}
|
||||
function getPlanRecordModelData() {
|
||||
return {
|
||||
id: @Model.Id,
|
||||
dateCreated: "@Model.DateCreated"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
100
Views/Vehicle/_PlanRecords.cshtml
Normal file
100
Views/Vehicle/_PlanRecords.cshtml
Normal file
@@ -0,0 +1,100 @@
|
||||
@using CarCareTracker.Helper
|
||||
@inject IConfigHelper config
|
||||
@{
|
||||
var enableCsvImports = config.GetUserConfig(User).EnableCsvImports;
|
||||
var hideZero = config.GetUserConfig(User).HideZero;
|
||||
var backLogItems = Model.Where(x => x.Progress == PlanProgress.Backlog).OrderBy(x=>x.Priority);
|
||||
var inProgressItems = Model.Where(x => x.Progress == PlanProgress.InProgress).OrderBy(x => x.Priority);
|
||||
var testingItems = Model.Where(x => x.Progress == PlanProgress.Testing).OrderBy(x => x.Priority);
|
||||
var doneItems = Model.Where(x => x.Progress == PlanProgress.Done).OrderBy(x => x.Priority);
|
||||
}
|
||||
@model List<PlanRecord>
|
||||
<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 Plan Records: {Model.Count()}")</span>
|
||||
</div>
|
||||
<div>
|
||||
@if (enableCsvImports)
|
||||
{
|
||||
<div class="btn-group">
|
||||
<button onclick="showAddPlanRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>Add Plan 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('PlanRecord')">Import via CSV</a></li>
|
||||
<li><a class="dropdown-item" href="#" onclick="exportVehicleData('PlanRecord')">Export to CSV</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button onclick="showAddPlanRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>Add Plan Record</button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row vehicleDetailTabContainer fixed">
|
||||
<div class="col-12">
|
||||
<div class="row mt-2 showOnPrint">
|
||||
<div class="d-flex">
|
||||
<img src="/defaults/lubelogger_logo.png" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row swimlane">
|
||||
<div class="col-3 d-flex flex-column swimlane mid" ondragover="dragOver(event)" ondrop="dropBox(event, 'Backlog')">
|
||||
<div class="row">
|
||||
<div class="col-12 d-flex justify-content-center" style="height:5vh;">
|
||||
<span class="display-7">Planned</span>
|
||||
</div>
|
||||
</div>
|
||||
@foreach (PlanRecord planRecord in backLogItems)
|
||||
{
|
||||
@await Html.PartialAsync("_PlanRecordItem", planRecord)
|
||||
}
|
||||
</div>
|
||||
<div class="col-3 d-flex flex-column swimlane mid" ondragover="dragOver(event)" ondrop="dropBox(event, 'InProgress')">
|
||||
<div class="row">
|
||||
<div class="col-12 d-flex justify-content-center" style="height:5vh;">
|
||||
<span class="display-7">Doing</span>
|
||||
</div>
|
||||
</div>
|
||||
@foreach (PlanRecord planRecord in inProgressItems)
|
||||
{
|
||||
@await Html.PartialAsync("_PlanRecordItem", planRecord)
|
||||
}
|
||||
</div>
|
||||
<div class="col-3 d-flex flex-column swimlane" ondragover="dragOver(event)" ondrop="dropBox(event, 'Testing')">
|
||||
<div class="row">
|
||||
<div class="col-12 d-flex justify-content-center" style="height:5vh;">
|
||||
<span class="display-7">Testing</span>
|
||||
</div>
|
||||
</div>
|
||||
@foreach (PlanRecord planRecord in testingItems)
|
||||
{
|
||||
@await Html.PartialAsync("_PlanRecordItem", planRecord)
|
||||
}
|
||||
</div>
|
||||
<div class="col-3 d-flex flex-column swimlane end" ondragover="dragOver(event)" ondrop="dropBox(event, 'Done')">
|
||||
<div class="row">
|
||||
<div class="col-12 d-flex justify-content-center" style="height:5vh;">
|
||||
<span class="display-7">Done</span>
|
||||
</div>
|
||||
</div>
|
||||
@foreach (PlanRecord planRecord in doneItems)
|
||||
{
|
||||
@await Html.PartialAsync("_PlanRecordItem", planRecord)
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="modal fade" data-bs-focus="false" id="planRecordModal" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content" id="planRecordModalContent">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -41,6 +41,27 @@
|
||||
<div class="col-md-6 col-12">
|
||||
<label for="reminderNotes">Notes(optional)</label>
|
||||
<textarea id="reminderNotes" class="form-control" rows="5">@Model.Notes</textarea>
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" onChange="enableRecurring()" role="switch" id="reminderIsRecurring" checked="@Model.IsRecurring">
|
||||
<label class="form-check-label" for="reminderIsRecurring">Is Recurring</label>
|
||||
</div>
|
||||
<label for="reminderRecurringMileage">Odometer</label>
|
||||
<select class="form-select" id="reminderRecurringMileage" @(Model.IsRecurring ? "" : "disabled")>
|
||||
<!option value="FiveHundredMiles" @(Model.ReminderMileageInterval == ReminderMileageInterval.FiveHundredMiles || isNew ? "selected" : "")>500 mi. / Km</!option>
|
||||
<!option value="OneThousandMiles" @(Model.ReminderMileageInterval == ReminderMileageInterval.OneThousandMiles ? "selected" : "")>1000 mi. / Km</!option>
|
||||
<!option value="ThreeThousandMiles" @(Model.ReminderMileageInterval == ReminderMileageInterval.ThreeThousandMiles ? "selected" : "")>3000 mi. / Km</!option>
|
||||
<!option value="FiveThousandMiles" @(Model.ReminderMileageInterval == ReminderMileageInterval.FiveThousandMiles || isNew ? "selected" : "")>5000 mi. / Km</!option>
|
||||
<!option value="SevenThousandFiveHundredMiles" @(Model.ReminderMileageInterval == ReminderMileageInterval.SevenThousandFiveHundredMiles ? "selected" : "")>7500 mi. / Km</!option>
|
||||
<!option value="TenThousandMiles" @(Model.ReminderMileageInterval == ReminderMileageInterval.TenThousandMiles ? "selected" : "")>10000 mi. / Km</!option>
|
||||
<!option value="FiftyThousandMiles" @(Model.ReminderMileageInterval == ReminderMileageInterval.FiftyThousandMiles ? "selected" : "")>50000 mi. / Km</!option>
|
||||
</select>
|
||||
<label for="reminderRecurringMonth">Month</label>
|
||||
<select class="form-select" id="reminderRecurringMonth" @(Model.IsRecurring ? "" : "disabled")>
|
||||
<!option value="ThreeMonths" @(Model.ReminderMonthInterval == ReminderMonthInterval.ThreeMonths || isNew ? "selected" : "")>3 Months</!option>
|
||||
<!option value="SixMonths" @(Model.ReminderMonthInterval == ReminderMonthInterval.SixMonths ? "selected" : "")>6 Months</!option>
|
||||
<!option value="OneYear" @(Model.ReminderMonthInterval == ReminderMonthInterval.OneYear ? "selected" : "")>1 Year</!option>
|
||||
<!option value="FiveYears" @(Model.ReminderMonthInterval == ReminderMonthInterval.FiveYears ? "selected" : "")>5 Years</!option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
@model ReportViewModel
|
||||
<div class="container reportTabContainer">
|
||||
<div class="row hideOnPrint">
|
||||
<div class="col-md-3 col-12 mt-2">
|
||||
<div class="row">
|
||||
@@ -20,7 +21,8 @@
|
||||
</div>
|
||||
<div class="col-md-6 col-12 mt-2">
|
||||
<div class="row">
|
||||
<div class="col-12 d-flex justify-content-center reportsCheckBoxContainer">
|
||||
<div class="col-md-1 d-sm-none d-md-block"></div>
|
||||
<div class="col-12 col-md-10 reportsCheckBoxContainer">
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" onChange="updateCheck(this)" type="checkbox" id="serviceExpenseCheck" value="1" checked>
|
||||
<label class="form-check-label" for="serviceExpenseCheck">Service</label>
|
||||
@@ -42,6 +44,7 @@
|
||||
<label class="form-check-label" for="taxExpenseCheck">Tax</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-1 d-sm-none d-md-block"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="d-flex justify-content-center align-items-center col-12 chartContainer" id="gasCostByMonthReportContent">
|
||||
@@ -83,4 +86,5 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="vehicleHistoryReport" class="showOnPrint"></div>
|
||||
@@ -35,18 +35,39 @@ html {
|
||||
overflow-y: auto;
|
||||
overflow-x: auto;
|
||||
}
|
||||
.reportTabContainer {
|
||||
max-height: 85vh;
|
||||
overflow-y: auto;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.vehicleDetailTabContainer.fixed {
|
||||
height: 65vh;
|
||||
}
|
||||
|
||||
.swimlane{
|
||||
height:100%;
|
||||
}
|
||||
.swimlane.mid {
|
||||
border-right-style: solid;
|
||||
}
|
||||
.swimlane.end {
|
||||
border-left-style: solid;
|
||||
}
|
||||
|
||||
.showOnPrint {
|
||||
display:none;
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media print {
|
||||
.hideOnPrint {
|
||||
display:none;
|
||||
display: none;
|
||||
}
|
||||
.showOnPrint{
|
||||
display:block !important;
|
||||
|
||||
.showOnPrint {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.vehicleDetailTabContainer {
|
||||
background-color: #fff !important;
|
||||
height: 100%;
|
||||
@@ -60,18 +81,22 @@ html {
|
||||
color: #000 !important;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
table {
|
||||
background-color: #fff !important;
|
||||
}
|
||||
|
||||
ul {
|
||||
border: 0px !important;
|
||||
background-color: #fff !important;
|
||||
}
|
||||
|
||||
li {
|
||||
color: #000 !important;
|
||||
border: 0px !important;
|
||||
background-color: #fff !important;
|
||||
}
|
||||
|
||||
td {
|
||||
color: #000 !important;
|
||||
border: hidden;
|
||||
@@ -81,7 +106,8 @@ html {
|
||||
td.col-1 {
|
||||
width: 10%;
|
||||
}
|
||||
td.col-4.text-wrap{
|
||||
|
||||
td.col-4.text-wrap {
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
@@ -94,7 +120,7 @@ html {
|
||||
background-color: #fff !important;
|
||||
}
|
||||
|
||||
tr{
|
||||
tr {
|
||||
border: hidden;
|
||||
}
|
||||
}
|
||||
@@ -183,10 +209,10 @@ html {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.lubelogger-navbar-button > button {
|
||||
padding: 0;
|
||||
font-size: 2rem;
|
||||
}
|
||||
.lubelogger-navbar-button > button {
|
||||
padding: 0;
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.lubelogger-menu-icon {
|
||||
display: inline-block;
|
||||
@@ -196,7 +222,7 @@ html {
|
||||
|
||||
.lubelogger-mobile-nav {
|
||||
background-color: var(--bs-body-bg);
|
||||
height: 100vh;
|
||||
height: max(100vh, 100%);
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@@ -209,6 +235,7 @@ html {
|
||||
.lubelogger-mobile-nav-show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.lubelogger-mobile-nav > ul > li > .nav-link.active {
|
||||
color: #6ea8fe;
|
||||
}
|
||||
@@ -232,14 +259,38 @@ html {
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-menu.show{
|
||||
.dropdown-menu.show {
|
||||
z-index: 1030;
|
||||
}
|
||||
|
||||
input[type="file"] {
|
||||
max-width:100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.uploadedFileName {
|
||||
max-width:75%;
|
||||
max-width: 75%;
|
||||
}
|
||||
|
||||
.taskCard {
|
||||
max-height: 20vh;
|
||||
padding:0.5rem;
|
||||
overflow:hidden;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 6px 10px rgba(0,0,0,.08), 0 0 6px rgba(0,0,0,.05);
|
||||
transition: .3s transform cubic-bezier(.155,1.105,.295,1.12),.3s box-shadow,.3s -webkit-transform cubic-bezier(.155,1.105,.295,1.12);
|
||||
cursor: pointer;
|
||||
}
|
||||
.taskCard.nodrag{
|
||||
cursor:not-allowed;
|
||||
}
|
||||
.taskCard-title{
|
||||
font-size:1.5rem;
|
||||
font-weight:300;
|
||||
max-height:10vh;
|
||||
}
|
||||
[data-bs-theme=dark] .taskCard {
|
||||
background-color: rgba(255,255,255,0.5);
|
||||
}
|
||||
[data-bs-theme=light] .taskCard {
|
||||
background-color: rgba(80,80,80,0.25);
|
||||
}
|
||||
2
wwwroot/defaults/odometersample.csv
Normal file
2
wwwroot/defaults/odometersample.csv
Normal file
@@ -0,0 +1,2 @@
|
||||
Date,Odometer,Notes
|
||||
1/1/2024,260001,test test
|
||||
|
2
wwwroot/defaults/plansample.csv
Normal file
2
wwwroot/defaults/plansample.csv
Normal file
@@ -0,0 +1,2 @@
|
||||
DateCreated,DateModified,Description,Notes,Type,Priority,Progress,Cost
|
||||
1/19/2024 6:01:02 PM,1/19/2024 7:32:58 PM,Repair Exhaust,,RepairRecord,Normal,Testing,$50.00
|
||||
|
101
wwwroot/js/odometerrecord.js
Normal file
101
wwwroot/js/odometerrecord.js
Normal file
@@ -0,0 +1,101 @@
|
||||
function showAddOdometerRecordModal() {
|
||||
$.get('/Vehicle/GetAddOdometerRecordPartialView', function (data) {
|
||||
if (data) {
|
||||
$("#odometerRecordModalContent").html(data);
|
||||
//initiate datepicker
|
||||
initDatePicker($('#odometerRecordDate'));
|
||||
$('#odometerRecordModal').modal('show');
|
||||
}
|
||||
});
|
||||
}
|
||||
function showEditOdometerRecordModal(odometerRecordId) {
|
||||
$.get(`/Vehicle/GetOdometerRecordForEditById?odometerRecordId=${odometerRecordId}`, function (data) {
|
||||
if (data) {
|
||||
$("#odometerRecordModalContent").html(data);
|
||||
//initiate datepicker
|
||||
initDatePicker($('#odometerRecordDate'));
|
||||
$('#odometerRecordModal').modal('show');
|
||||
}
|
||||
});
|
||||
}
|
||||
function hideAddOdometerRecordModal() {
|
||||
$('#odometerRecordModal').modal('hide');
|
||||
}
|
||||
function deleteOdometerRecord(odometerRecordId) {
|
||||
$("#workAroundInput").show();
|
||||
Swal.fire({
|
||||
title: "Confirm Deletion?",
|
||||
text: "Deleted Odometer Records cannot be restored.",
|
||||
showCancelButton: true,
|
||||
confirmButtonText: "Delete",
|
||||
confirmButtonColor: "#dc3545"
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
$.post(`/Vehicle/DeleteOdometerRecordById?odometerRecordId=${odometerRecordId}`, function (data) {
|
||||
if (data) {
|
||||
hideAddOdometerRecordModal();
|
||||
successToast("Odometer Record Deleted");
|
||||
var vehicleId = GetVehicleId().vehicleId;
|
||||
getVehicleOdometerRecords(vehicleId);
|
||||
} else {
|
||||
errorToast("An error has occurred, please try again later.");
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$("#workAroundInput").hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
function saveOdometerRecordToVehicle(isEdit) {
|
||||
//get values
|
||||
var formValues = getAndValidateOdometerRecordValues();
|
||||
//validate
|
||||
if (formValues.hasError) {
|
||||
errorToast("Please check the form data");
|
||||
return;
|
||||
}
|
||||
//save to db.
|
||||
$.post('/Vehicle/SaveOdometerRecordToVehicleId', { odometerRecord: formValues }, function (data) {
|
||||
if (data) {
|
||||
successToast(isEdit ? "Odometer Record Updated" : "Odometer Record Added.");
|
||||
hideAddOdometerRecordModal();
|
||||
saveScrollPosition();
|
||||
getVehicleOdometerRecords(formValues.vehicleId);
|
||||
if (formValues.addReminderRecord) {
|
||||
setTimeout(function () { showAddReminderModal(formValues); }, 500);
|
||||
}
|
||||
} else {
|
||||
errorToast("An error has occurred, please try again later.");
|
||||
}
|
||||
})
|
||||
}
|
||||
function getAndValidateOdometerRecordValues() {
|
||||
var serviceDate = $("#odometerRecordDate").val();
|
||||
var serviceMileage = $("#odometerRecordMileage").val();
|
||||
var serviceNotes = $("#odometerRecordNotes").val();
|
||||
var vehicleId = GetVehicleId().vehicleId;
|
||||
var odometerRecordId = getOdometerRecordModelData().id;
|
||||
//validation
|
||||
var hasError = false;
|
||||
if (serviceDate.trim() == '') { //eliminates whitespace.
|
||||
hasError = true;
|
||||
$("#odometerRecordDate").addClass("is-invalid");
|
||||
} else {
|
||||
$("#odometerRecordDate").removeClass("is-invalid");
|
||||
}
|
||||
if (serviceMileage.trim() == '' || parseInt(serviceMileage) < 0) {
|
||||
hasError = true;
|
||||
$("#odometerRecordMileage").addClass("is-invalid");
|
||||
} else {
|
||||
$("#odometerRecordMileage").removeClass("is-invalid");
|
||||
}
|
||||
return {
|
||||
id: odometerRecordId,
|
||||
hasError: hasError,
|
||||
vehicleId: vehicleId,
|
||||
date: serviceDate,
|
||||
mileage: serviceMileage,
|
||||
notes: serviceNotes,
|
||||
files: uploadedFiles
|
||||
}
|
||||
}
|
||||
179
wwwroot/js/planrecord.js
Normal file
179
wwwroot/js/planrecord.js
Normal file
@@ -0,0 +1,179 @@
|
||||
function showAddPlanRecordModal() {
|
||||
$.get('/Vehicle/GetAddPlanRecordPartialView', function (data) {
|
||||
if (data) {
|
||||
$("#planRecordModalContent").html(data);
|
||||
//initiate datepicker
|
||||
initDatePicker($('#planRecordDate'));
|
||||
$('#planRecordModal').modal('show');
|
||||
}
|
||||
});
|
||||
}
|
||||
function showEditPlanRecordModal(planRecordId) {
|
||||
$.get(`/Vehicle/GetPlanRecordForEditById?planRecordId=${planRecordId}`, function (data) {
|
||||
if (data) {
|
||||
$("#planRecordModalContent").html(data);
|
||||
//initiate datepicker
|
||||
initDatePicker($('#planRecordDate'));
|
||||
$('#planRecordModal').modal('show');
|
||||
}
|
||||
});
|
||||
}
|
||||
function hideAddPlanRecordModal() {
|
||||
$('#planRecordModal').modal('hide');
|
||||
}
|
||||
function deletePlanRecord(planRecordId) {
|
||||
$("#workAroundInput").show();
|
||||
Swal.fire({
|
||||
title: "Confirm Deletion?",
|
||||
text: "Deleted Plan Records cannot be restored.",
|
||||
showCancelButton: true,
|
||||
confirmButtonText: "Delete",
|
||||
confirmButtonColor: "#dc3545"
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
$.post(`/Vehicle/DeletePlanRecordById?planRecordId=${planRecordId}`, function (data) {
|
||||
if (data) {
|
||||
hideAddPlanRecordModal();
|
||||
successToast("Plan Record Deleted");
|
||||
var vehicleId = GetVehicleId().vehicleId;
|
||||
getVehiclePlanRecords(vehicleId);
|
||||
} else {
|
||||
errorToast("An error has occurred, please try again later.");
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$("#workAroundInput").hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
function savePlanRecordToVehicle(isEdit) {
|
||||
//get values
|
||||
var formValues = getAndValidatePlanRecordValues();
|
||||
//validate
|
||||
if (formValues.hasError) {
|
||||
errorToast("Please check the form data");
|
||||
return;
|
||||
}
|
||||
//save to db.
|
||||
$.post('/Vehicle/SavePlanRecordToVehicleId', { planRecord: formValues }, function (data) {
|
||||
if (data) {
|
||||
successToast(isEdit ? "Plan Record Updated" : "Plan Record Added.");
|
||||
hideAddPlanRecordModal();
|
||||
saveScrollPosition();
|
||||
getVehiclePlanRecords(formValues.vehicleId);
|
||||
if (formValues.addReminderRecord) {
|
||||
setTimeout(function () { showAddReminderModal(formValues); }, 500);
|
||||
}
|
||||
} else {
|
||||
errorToast("An error has occurred, please try again later.");
|
||||
}
|
||||
})
|
||||
}
|
||||
function getAndValidatePlanRecordValues() {
|
||||
var planDescription = $("#planRecordDescription").val();
|
||||
var planCost = $("#planRecordCost").val();
|
||||
var planNotes = $("#planRecordNotes").val();
|
||||
var planType = $("#planRecordType").val();
|
||||
var planPriority = $("#planRecordPriority").val();
|
||||
var planProgress = $("#planRecordProgress").val();
|
||||
var planDateCreated = getPlanRecordModelData().dateCreated;
|
||||
var vehicleId = GetVehicleId().vehicleId;
|
||||
var planRecordId = getPlanRecordModelData().id;
|
||||
//validation
|
||||
var hasError = false;
|
||||
if (planDescription.trim() == '') {
|
||||
hasError = true;
|
||||
$("#planRecordDescription").addClass("is-invalid");
|
||||
} else {
|
||||
$("#planRecordDescription").removeClass("is-invalid");
|
||||
}
|
||||
if (planCost.trim() == '' || !isValidMoney(planCost)) {
|
||||
hasError = true;
|
||||
$("#planRecordCost").addClass("is-invalid");
|
||||
} else {
|
||||
$("#planRecordCost").removeClass("is-invalid");
|
||||
}
|
||||
return {
|
||||
id: planRecordId,
|
||||
hasError: hasError,
|
||||
vehicleId: vehicleId,
|
||||
dateCreated: planDateCreated,
|
||||
description: planDescription,
|
||||
cost: planCost,
|
||||
notes: planNotes,
|
||||
files: uploadedFiles,
|
||||
priority: planPriority,
|
||||
progress: planProgress,
|
||||
importMode: planType
|
||||
}
|
||||
}
|
||||
//drag and drop stuff.
|
||||
|
||||
let dragged = null;
|
||||
let draggedId = 0;
|
||||
function dragEnter(event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
function dragStart(event, planRecordId) {
|
||||
dragged = event.target;
|
||||
draggedId = planRecordId;
|
||||
event.dataTransfer.setData('text/plain', draggedId);
|
||||
}
|
||||
function dragOver(event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
function dropBox(event, newProgress) {
|
||||
if ($(event.target).hasClass("swimlane")) {
|
||||
if (dragged.parentElement != event.target && event.target != dragged) {
|
||||
updatePlanRecordProgress(newProgress);
|
||||
}
|
||||
}
|
||||
event.preventDefault();
|
||||
}
|
||||
function updatePlanRecordProgress(newProgress) {
|
||||
if (draggedId > 0) {
|
||||
if (newProgress == 'Done') {
|
||||
//if user is marking the task as done, we will want them to enter the mileage so that we can auto-convert it.
|
||||
Swal.fire({
|
||||
title: 'Mark Task as Done?',
|
||||
html: `<p>To confirm, please enter the current odometer reading on your vehicle, as we also need the current odometer to auto convert the task into the relevant record.</p>
|
||||
<input type="text" id="inputOdometer" class="swal2-input" placeholder="Odometer Reading">
|
||||
`,
|
||||
confirmButtonText: 'Confirm',
|
||||
showCancelButton: true,
|
||||
focusConfirm: false,
|
||||
preConfirm: () => {
|
||||
const odometer = $("#inputOdometer").val();
|
||||
if (!odometer || isNaN(odometer)) {
|
||||
Swal.showValidationMessage(`Please enter an odometer reading`)
|
||||
}
|
||||
return { odometer }
|
||||
},
|
||||
}).then(function (result) {
|
||||
if (result.isConfirmed) {
|
||||
$.post('/Vehicle/UpdatePlanRecordProgress', { planRecordId: draggedId, planProgress: newProgress, odometer: result.value.odometer }, function (data) {
|
||||
if (data) {
|
||||
successToast("Plan Progress Updated");
|
||||
var vehicleId = GetVehicleId().vehicleId;
|
||||
getVehiclePlanRecords(vehicleId);
|
||||
} else {
|
||||
errorToast("An error has occurred, please try again later.");
|
||||
}
|
||||
});
|
||||
}
|
||||
draggedId = 0;
|
||||
});
|
||||
} else {
|
||||
$.post('/Vehicle/UpdatePlanRecordProgress', { planRecordId: draggedId, planProgress: newProgress }, function (data) {
|
||||
if (data) {
|
||||
successToast("Plan Progress Updated");
|
||||
var vehicleId = GetVehicleId().vehicleId;
|
||||
getVehiclePlanRecords(vehicleId);
|
||||
} else {
|
||||
errorToast("An error has occurred, please try again later.");
|
||||
}
|
||||
});
|
||||
draggedId = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,12 +69,27 @@ function appendMileageToOdometer(increment) {
|
||||
reminderMileage += increment;
|
||||
$("#reminderMileage").val(reminderMileage);
|
||||
}
|
||||
|
||||
function enableRecurring() {
|
||||
var reminderIsRecurring = $("#reminderIsRecurring").is(":checked");
|
||||
if (reminderIsRecurring) {
|
||||
$("#reminderRecurringMileage").attr('disabled', false);
|
||||
$("#reminderRecurringMonth").attr('disabled', false);
|
||||
} else {
|
||||
$("#reminderRecurringMileage").attr('disabled', true);
|
||||
$("#reminderRecurringMonth").attr('disabled', true);
|
||||
}
|
||||
}
|
||||
|
||||
function getAndValidateReminderRecordValues() {
|
||||
var reminderDate = $("#reminderDate").val();
|
||||
var reminderMileage = $("#reminderMileage").val();
|
||||
var reminderDescription = $("#reminderDescription").val();
|
||||
var reminderNotes = $("#reminderNotes").val();
|
||||
var reminderOption = $('#reminderOptions input:radio:checked').val();
|
||||
var reminderIsRecurring = $("#reminderIsRecurring").is(":checked");
|
||||
var reminderRecurringMonth = $("#reminderRecurringMonth").val();
|
||||
var reminderRecurringMileage = $("#reminderRecurringMileage").val();
|
||||
var vehicleId = GetVehicleId().vehicleId;
|
||||
var reminderId = getReminderRecordModelData().id;
|
||||
//validation
|
||||
@@ -118,6 +133,9 @@ function getAndValidateReminderRecordValues() {
|
||||
mileage: reminderMileage,
|
||||
description: reminderDescription,
|
||||
notes: reminderNotes,
|
||||
metric: reminderOption
|
||||
metric: reminderOption,
|
||||
isRecurring: reminderIsRecurring,
|
||||
reminderMileageInterval: reminderRecurringMileage,
|
||||
reminderMonthInterval: reminderRecurringMonth
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,12 @@ $(document).ready(function () {
|
||||
case "supply-tab":
|
||||
getVehicleSupplyRecords(vehicleId);
|
||||
break;
|
||||
case "plan-tab":
|
||||
getVehiclePlanRecords(vehicleId);
|
||||
break;
|
||||
case "odometer-tab":
|
||||
getVehicleOdometerRecords(vehicleId);
|
||||
break;
|
||||
}
|
||||
switch (e.relatedTarget.id) { //clear out previous tabs with grids in them to help with performance
|
||||
case "servicerecord-tab":
|
||||
@@ -62,6 +68,12 @@ $(document).ready(function () {
|
||||
case "supply-tab":
|
||||
$("#supply-tab-pane").html("");
|
||||
break;
|
||||
case "plan-tab":
|
||||
$("#plan-tab-pane").html("");
|
||||
break;
|
||||
case "odometer-tab":
|
||||
$("odometer-tab-pane").html("");
|
||||
break;
|
||||
}
|
||||
});
|
||||
var defaultTab = GetDefaultTab().tab;
|
||||
@@ -93,6 +105,12 @@ $(document).ready(function () {
|
||||
case "SupplyRecord":
|
||||
getVehicleSupplyRecords(vehicleId);
|
||||
break;
|
||||
case "PlanRecord":
|
||||
getVehiclePlanRecords(vehicleId);
|
||||
break;
|
||||
case "OdometerRecord":
|
||||
getVehicleOdometerRecords(vehicleId);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -113,6 +131,24 @@ function getVehicleServiceRecords(vehicleId) {
|
||||
}
|
||||
});
|
||||
}
|
||||
function getVehiclePlanRecords(vehicleId) {
|
||||
$.get(`/Vehicle/GetPlanRecordsByVehicleId?vehicleId=${vehicleId}`, function (data) {
|
||||
if (data) {
|
||||
$("#plan-tab-pane").html(data);
|
||||
restoreScrollPosition();
|
||||
getVehicleHaveImportantReminders(vehicleId);
|
||||
}
|
||||
});
|
||||
}
|
||||
function getVehicleOdometerRecords(vehicleId) {
|
||||
$.get(`/Vehicle/GetOdometerRecordsByVehicleId?vehicleId=${vehicleId}`, function (data) {
|
||||
if (data) {
|
||||
$("#odometer-tab-pane").html(data);
|
||||
restoreScrollPosition();
|
||||
getVehicleHaveImportantReminders(vehicleId);
|
||||
}
|
||||
});
|
||||
}
|
||||
function getVehicleSupplyRecords(vehicleId) {
|
||||
$.get(`/Vehicle/GetSupplyRecordsByVehicleId?vehicleId=${vehicleId}`, function (data) {
|
||||
if (data) {
|
||||
|
||||
Reference in New Issue
Block a user