Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9262131936 | ||
|
|
02c5302653 | ||
|
|
fa73b61e3f | ||
|
|
96ade10289 | ||
|
|
acf16a6c28 | ||
|
|
dedf8fc2f7 | ||
|
|
7099652083 | ||
|
|
d0f9795e63 | ||
|
|
0ffc469ac8 | ||
|
|
b5ea3c63a1 | ||
|
|
5901531ddf | ||
|
|
814aa8d22b | ||
|
|
d3aa55f987 | ||
|
|
8b7fb7ef0f | ||
|
|
0fab57d19c | ||
|
|
0d8822c496 | ||
|
|
7235931f38 | ||
|
|
410f45c6c2 | ||
|
|
9a44d80be4 | ||
|
|
2f52ed64ba | ||
|
|
dd68dec05c | ||
|
|
a8bc9f90e1 | ||
|
|
8759216dd6 | ||
|
|
0851e0a222 | ||
|
|
40f1f1380e | ||
|
|
2a5ff7a911 | ||
|
|
0590f991d2 | ||
|
|
c6a96df3e9 | ||
|
|
0088c74b20 | ||
|
|
6af0d8b88e | ||
|
|
5204a71b00 | ||
|
|
8b2866b89b | ||
|
|
65f638f336 | ||
|
|
f92e95e01c | ||
|
|
2aeae70060 |
@@ -3,8 +3,6 @@ using CarCareTracker.Logic;
|
|||||||
using CarCareTracker.Models;
|
using CarCareTracker.Models;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using System.Net;
|
|
||||||
using System.Net.Mail;
|
|
||||||
|
|
||||||
namespace CarCareTracker.Controllers
|
namespace CarCareTracker.Controllers
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,12 +1,5 @@
|
|||||||
using CarCareTracker.External.Interfaces;
|
|
||||||
using CarCareTracker.Models;
|
using CarCareTracker.Models;
|
||||||
using LiteDB;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using System.Diagnostics;
|
|
||||||
using static System.Net.Mime.MediaTypeNames;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Linq.Expressions;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using CarCareTracker.Helper;
|
using CarCareTracker.Helper;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,7 @@ using CarCareTracker.Models;
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.DataProtection;
|
using Microsoft.AspNetCore.DataProtection;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.IdentityModel.Tokens;
|
|
||||||
using System.IdentityModel.Tokens.Jwt;
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
using System.Net;
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace CarCareTracker.Controllers
|
namespace CarCareTracker.Controllers
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
using CarCareTracker.External.Implementations;
|
using CarCareTracker.Helper;
|
||||||
using CarCareTracker.Helper;
|
|
||||||
using CarCareTracker.Models;
|
using CarCareTracker.Models;
|
||||||
using LiteDB;
|
using LiteDB;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Npgsql;
|
using Npgsql;
|
||||||
using System.Data.Common;
|
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Xml.Linq;
|
|
||||||
|
|
||||||
namespace CarCareTracker.Controllers
|
namespace CarCareTracker.Controllers
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -165,18 +165,21 @@ namespace CarCareTracker.Controllers
|
|||||||
var sourceCollaborators = _userLogic.GetCollaboratorsForVehicle(sourceVehicleId).Select(x => x.UserVehicle.UserId).ToList();
|
var sourceCollaborators = _userLogic.GetCollaboratorsForVehicle(sourceVehicleId).Select(x => x.UserVehicle.UserId).ToList();
|
||||||
var destCollaborators = _userLogic.GetCollaboratorsForVehicle(destVehicleId).Select(x => x.UserVehicle.UserId).ToList();
|
var destCollaborators = _userLogic.GetCollaboratorsForVehicle(destVehicleId).Select(x => x.UserVehicle.UserId).ToList();
|
||||||
sourceCollaborators.RemoveAll(x => destCollaborators.Contains(x));
|
sourceCollaborators.RemoveAll(x => destCollaborators.Contains(x));
|
||||||
if (sourceCollaborators.Any()) {
|
if (sourceCollaborators.Any())
|
||||||
|
{
|
||||||
foreach (int collaboratorId in sourceCollaborators)
|
foreach (int collaboratorId in sourceCollaborators)
|
||||||
{
|
{
|
||||||
_userLogic.AddUserAccessToVehicle(collaboratorId, destVehicleId);
|
_userLogic.AddUserAccessToVehicle(collaboratorId, destVehicleId);
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
return Json(new OperationResponse { Success = false, Message = "Both vehicles already have identical collaborators" });
|
return Json(new OperationResponse { Success = false, Message = "Both vehicles already have identical collaborators" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Json(new OperationResponse { Success = true, Message = "Collaborators Copied"});
|
return Json(new OperationResponse { Success = true, Message = "Collaborators Copied" });
|
||||||
} catch (Exception ex)
|
}
|
||||||
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex.Message);
|
_logger.LogError(ex.Message);
|
||||||
return Json(new OperationResponse { Success = false, Message = StaticHelper.GenericErrorMessage });
|
return Json(new OperationResponse { Success = false, Message = StaticHelper.GenericErrorMessage });
|
||||||
@@ -454,6 +457,16 @@ namespace CarCareTracker.Controllers
|
|||||||
if (convertedRecord.Gallons > 0)
|
if (convertedRecord.Gallons > 0)
|
||||||
{
|
{
|
||||||
_gasRecordDataAccess.SaveGasRecordToVehicle(convertedRecord);
|
_gasRecordDataAccess.SaveGasRecordToVehicle(convertedRecord);
|
||||||
|
if (_config.GetUserConfig(User).EnableAutoOdometerInsert)
|
||||||
|
{
|
||||||
|
_odometerRecordDataAccess.SaveOdometerRecordToVehicle(new OdometerRecord
|
||||||
|
{
|
||||||
|
Date = convertedRecord.Date,
|
||||||
|
VehicleId = convertedRecord.VehicleId,
|
||||||
|
Mileage = convertedRecord.Mileage,
|
||||||
|
Notes = $"Auto Insert From Gas Record via CSV Import. {convertedRecord.Notes}"
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (mode == ImportMode.ServiceRecord)
|
else if (mode == ImportMode.ServiceRecord)
|
||||||
@@ -469,6 +482,16 @@ namespace CarCareTracker.Controllers
|
|||||||
Tags = string.IsNullOrWhiteSpace(importModel.Tags) ? [] : importModel.Tags.Split(" ").ToList()
|
Tags = string.IsNullOrWhiteSpace(importModel.Tags) ? [] : importModel.Tags.Split(" ").ToList()
|
||||||
};
|
};
|
||||||
_serviceRecordDataAccess.SaveServiceRecordToVehicle(convertedRecord);
|
_serviceRecordDataAccess.SaveServiceRecordToVehicle(convertedRecord);
|
||||||
|
if (_config.GetUserConfig(User).EnableAutoOdometerInsert)
|
||||||
|
{
|
||||||
|
_odometerRecordDataAccess.SaveOdometerRecordToVehicle(new OdometerRecord
|
||||||
|
{
|
||||||
|
Date = convertedRecord.Date,
|
||||||
|
VehicleId = convertedRecord.VehicleId,
|
||||||
|
Mileage = convertedRecord.Mileage,
|
||||||
|
Notes = $"Auto Insert From Service Record via CSV Import. {convertedRecord.Notes}"
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (mode == ImportMode.OdometerRecord)
|
else if (mode == ImportMode.OdometerRecord)
|
||||||
{
|
{
|
||||||
@@ -514,6 +537,16 @@ namespace CarCareTracker.Controllers
|
|||||||
Tags = string.IsNullOrWhiteSpace(importModel.Tags) ? [] : importModel.Tags.Split(" ").ToList()
|
Tags = string.IsNullOrWhiteSpace(importModel.Tags) ? [] : importModel.Tags.Split(" ").ToList()
|
||||||
};
|
};
|
||||||
_collisionRecordDataAccess.SaveCollisionRecordToVehicle(convertedRecord);
|
_collisionRecordDataAccess.SaveCollisionRecordToVehicle(convertedRecord);
|
||||||
|
if (_config.GetUserConfig(User).EnableAutoOdometerInsert)
|
||||||
|
{
|
||||||
|
_odometerRecordDataAccess.SaveOdometerRecordToVehicle(new OdometerRecord
|
||||||
|
{
|
||||||
|
Date = convertedRecord.Date,
|
||||||
|
VehicleId = convertedRecord.VehicleId,
|
||||||
|
Mileage = convertedRecord.Mileage,
|
||||||
|
Notes = $"Auto Insert From Repair Record via CSV Import. {convertedRecord.Notes}"
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (mode == ImportMode.UpgradeRecord)
|
else if (mode == ImportMode.UpgradeRecord)
|
||||||
{
|
{
|
||||||
@@ -528,6 +561,16 @@ namespace CarCareTracker.Controllers
|
|||||||
Tags = string.IsNullOrWhiteSpace(importModel.Tags) ? [] : importModel.Tags.Split(" ").ToList()
|
Tags = string.IsNullOrWhiteSpace(importModel.Tags) ? [] : importModel.Tags.Split(" ").ToList()
|
||||||
};
|
};
|
||||||
_upgradeRecordDataAccess.SaveUpgradeRecordToVehicle(convertedRecord);
|
_upgradeRecordDataAccess.SaveUpgradeRecordToVehicle(convertedRecord);
|
||||||
|
if (_config.GetUserConfig(User).EnableAutoOdometerInsert)
|
||||||
|
{
|
||||||
|
_odometerRecordDataAccess.SaveOdometerRecordToVehicle(new OdometerRecord
|
||||||
|
{
|
||||||
|
Date = convertedRecord.Date,
|
||||||
|
VehicleId = convertedRecord.VehicleId,
|
||||||
|
Mileage = convertedRecord.Mileage,
|
||||||
|
Notes = $"Auto Insert From Upgrade Record via CSV Import. {convertedRecord.Notes}"
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (mode == ImportMode.SupplyRecord)
|
else if (mode == ImportMode.SupplyRecord)
|
||||||
{
|
{
|
||||||
@@ -704,6 +747,11 @@ namespace CarCareTracker.Controllers
|
|||||||
{
|
{
|
||||||
serviceRecord.RequisitionHistory = RequisitionSupplyRecordsByUsage(serviceRecord.Supplies, DateTime.Parse(serviceRecord.Date), serviceRecord.Description);
|
serviceRecord.RequisitionHistory = RequisitionSupplyRecordsByUsage(serviceRecord.Supplies, DateTime.Parse(serviceRecord.Date), serviceRecord.Description);
|
||||||
}
|
}
|
||||||
|
//push back any reminders
|
||||||
|
if (serviceRecord.ReminderRecordId != default)
|
||||||
|
{
|
||||||
|
PushbackRecurringReminderRecordWithChecks(serviceRecord.ReminderRecordId);
|
||||||
|
}
|
||||||
var result = _serviceRecordDataAccess.SaveServiceRecordToVehicle(serviceRecord.ToServiceRecord());
|
var result = _serviceRecordDataAccess.SaveServiceRecordToVehicle(serviceRecord.ToServiceRecord());
|
||||||
return Json(result);
|
return Json(result);
|
||||||
}
|
}
|
||||||
@@ -776,7 +824,12 @@ namespace CarCareTracker.Controllers
|
|||||||
{
|
{
|
||||||
collisionRecord.RequisitionHistory = RequisitionSupplyRecordsByUsage(collisionRecord.Supplies, DateTime.Parse(collisionRecord.Date), collisionRecord.Description);
|
collisionRecord.RequisitionHistory = RequisitionSupplyRecordsByUsage(collisionRecord.Supplies, DateTime.Parse(collisionRecord.Date), collisionRecord.Description);
|
||||||
}
|
}
|
||||||
var result = _collisionRecordDataAccess.SaveCollisionRecordToVehicle(collisionRecord.ToCollisionRecord());
|
//push back any reminders
|
||||||
|
if (collisionRecord.ReminderRecordId != default)
|
||||||
|
{
|
||||||
|
PushbackRecurringReminderRecordWithChecks(collisionRecord.ReminderRecordId);
|
||||||
|
}
|
||||||
|
var result = _collisionRecordDataAccess.SaveCollisionRecordToVehicle(collisionRecord.ToCollisionRecord());
|
||||||
return Json(result);
|
return Json(result);
|
||||||
}
|
}
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
@@ -835,17 +888,19 @@ namespace CarCareTracker.Controllers
|
|||||||
var recurringFees = result.Where(x => x.IsRecurring);
|
var recurringFees = result.Where(x => x.IsRecurring);
|
||||||
if (recurringFees.Any())
|
if (recurringFees.Any())
|
||||||
{
|
{
|
||||||
foreach(TaxRecord recurringFee in recurringFees)
|
foreach (TaxRecord recurringFee in recurringFees)
|
||||||
{
|
{
|
||||||
var newDate = new DateTime();
|
var newDate = new DateTime();
|
||||||
if (recurringFee.RecurringInterval != ReminderMonthInterval.Other)
|
if (recurringFee.RecurringInterval != ReminderMonthInterval.Other)
|
||||||
{
|
{
|
||||||
newDate = recurringFee.Date.AddMonths((int)recurringFee.RecurringInterval);
|
newDate = recurringFee.Date.AddMonths((int)recurringFee.RecurringInterval);
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
newDate = recurringFee.Date.AddMonths(recurringFee.CustomMonthInterval);
|
newDate = recurringFee.Date.AddMonths(recurringFee.CustomMonthInterval);
|
||||||
}
|
}
|
||||||
if (DateTime.Now > newDate){
|
if (DateTime.Now > newDate)
|
||||||
|
{
|
||||||
recurringFee.IsRecurring = false;
|
recurringFee.IsRecurring = false;
|
||||||
var newRecurringFee = new TaxRecord()
|
var newRecurringFee = new TaxRecord()
|
||||||
{
|
{
|
||||||
@@ -872,6 +927,11 @@ namespace CarCareTracker.Controllers
|
|||||||
{
|
{
|
||||||
//move files from temp.
|
//move files from temp.
|
||||||
taxRecord.Files = taxRecord.Files.Select(x => { return new UploadedFiles { Name = x.Name, Location = _fileHelper.MoveFileFromTemp(x.Location, "documents/") }; }).ToList();
|
taxRecord.Files = taxRecord.Files.Select(x => { return new UploadedFiles { Name = x.Name, Location = _fileHelper.MoveFileFromTemp(x.Location, "documents/") }; }).ToList();
|
||||||
|
//push back any reminders
|
||||||
|
if (taxRecord.ReminderRecordId != default)
|
||||||
|
{
|
||||||
|
PushbackRecurringReminderRecordWithChecks(taxRecord.ReminderRecordId);
|
||||||
|
}
|
||||||
var result = _taxRecordDataAccess.SaveTaxRecordToVehicle(taxRecord.ToTaxRecord());
|
var result = _taxRecordDataAccess.SaveTaxRecordToVehicle(taxRecord.ToTaxRecord());
|
||||||
return Json(result);
|
return Json(result);
|
||||||
}
|
}
|
||||||
@@ -943,7 +1003,7 @@ namespace CarCareTracker.Controllers
|
|||||||
{
|
{
|
||||||
MonthName = x.Key.MonthName,
|
MonthName = x.Key.MonthName,
|
||||||
Cost = x.Sum(y => y.Cost),
|
Cost = x.Sum(y => y.Cost),
|
||||||
DistanceTraveled = x.Any(y=>y.MinMileage != default) ? x.Max(y=>y.MaxMileage) - x.Where(y=>y.MinMileage != default).Min(y=>y.MinMileage) : 0
|
DistanceTraveled = x.Any(y => y.MinMileage != default) ? x.Max(y => y.MaxMileage) - x.Where(y => y.MinMileage != default).Min(y => y.MinMileage) : 0
|
||||||
}).ToList();
|
}).ToList();
|
||||||
//get reminders
|
//get reminders
|
||||||
var reminders = GetRemindersAndUrgency(vehicleId, DateTime.Now);
|
var reminders = GetRemindersAndUrgency(vehicleId, DateTime.Now);
|
||||||
@@ -995,7 +1055,7 @@ namespace CarCareTracker.Controllers
|
|||||||
{
|
{
|
||||||
MonthId = x.Key,
|
MonthId = x.Key,
|
||||||
MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(x.Key),
|
MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(x.Key),
|
||||||
Cost = x.Sum(y=>y.Cost)
|
Cost = x.Sum(y => y.Cost)
|
||||||
}).ToList();
|
}).ToList();
|
||||||
viewModel.FuelMileageForVehicleByMonth = monthlyMileageData;
|
viewModel.FuelMileageForVehicleByMonth = monthlyMileageData;
|
||||||
return PartialView("_Report", viewModel);
|
return PartialView("_Report", viewModel);
|
||||||
@@ -1066,8 +1126,9 @@ namespace CarCareTracker.Controllers
|
|||||||
public IActionResult GetVehicleAttachments(int vehicleId, List<ImportMode> exportTabs)
|
public IActionResult GetVehicleAttachments(int vehicleId, List<ImportMode> exportTabs)
|
||||||
{
|
{
|
||||||
List<GenericReportModel> attachmentData = new List<GenericReportModel>();
|
List<GenericReportModel> attachmentData = new List<GenericReportModel>();
|
||||||
if (exportTabs.Contains(ImportMode.ServiceRecord)){
|
if (exportTabs.Contains(ImportMode.ServiceRecord))
|
||||||
var records = _serviceRecordDataAccess.GetServiceRecordsByVehicleId(vehicleId).Where(x=>x.Files.Any());
|
{
|
||||||
|
var records = _serviceRecordDataAccess.GetServiceRecordsByVehicleId(vehicleId).Where(x => x.Files.Any());
|
||||||
attachmentData.AddRange(records.Select(x => new GenericReportModel
|
attachmentData.AddRange(records.Select(x => new GenericReportModel
|
||||||
{
|
{
|
||||||
Date = x.Date,
|
Date = x.Date,
|
||||||
@@ -1134,7 +1195,8 @@ namespace CarCareTracker.Controllers
|
|||||||
return Json(new OperationResponse { Success = false, Message = StaticHelper.GenericErrorMessage });
|
return Json(new OperationResponse { Success = false, Message = StaticHelper.GenericErrorMessage });
|
||||||
}
|
}
|
||||||
return Json(new OperationResponse { Success = true, Message = result });
|
return Json(new OperationResponse { Success = true, Message = result });
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
return Json(new OperationResponse { Success = false, Message = "No Attachments Found" });
|
return Json(new OperationResponse { Success = false, Message = "No Attachments Found" });
|
||||||
}
|
}
|
||||||
@@ -1366,15 +1428,48 @@ namespace CarCareTracker.Controllers
|
|||||||
result = result.OrderByDescending(x => x.Urgency).ToList();
|
result = result.OrderByDescending(x => x.Urgency).ToList();
|
||||||
return PartialView("_ReminderRecords", result);
|
return PartialView("_ReminderRecords", result);
|
||||||
}
|
}
|
||||||
|
[HttpGet]
|
||||||
|
public IActionResult GetRecurringReminderRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
var result = _reminderRecordDataAccess.GetReminderRecordsByVehicleId(vehicleId);
|
||||||
|
result.RemoveAll(x => !x.IsRecurring);
|
||||||
|
return PartialView("_RecurringReminderSelector", result);
|
||||||
|
}
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public IActionResult PushbackRecurringReminderRecord(int reminderRecordId)
|
public IActionResult PushbackRecurringReminderRecord(int reminderRecordId)
|
||||||
{
|
{
|
||||||
var existingReminder = _reminderRecordDataAccess.GetReminderRecordById(reminderRecordId);
|
var result = PushbackRecurringReminderRecordWithChecks(reminderRecordId);
|
||||||
existingReminder = _reminderHelper.GetUpdatedRecurringReminderRecord(existingReminder);
|
|
||||||
//save to db.
|
|
||||||
var result = _reminderRecordDataAccess.SaveReminderRecordToVehicle(existingReminder);
|
|
||||||
return Json(result);
|
return Json(result);
|
||||||
}
|
}
|
||||||
|
private bool PushbackRecurringReminderRecordWithChecks(int reminderRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var existingReminder = _reminderRecordDataAccess.GetReminderRecordById(reminderRecordId);
|
||||||
|
if (existingReminder is not null && existingReminder.Id != default && existingReminder.IsRecurring)
|
||||||
|
{
|
||||||
|
existingReminder = _reminderHelper.GetUpdatedRecurringReminderRecord(existingReminder);
|
||||||
|
//save to db.
|
||||||
|
var reminderUpdateResult = _reminderRecordDataAccess.SaveReminderRecordToVehicle(existingReminder);
|
||||||
|
if (!reminderUpdateResult)
|
||||||
|
{
|
||||||
|
_logger.LogError("Unable to update reminder either because the reminder no longer exists or is no longer recurring");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogError("Unable to update reminder because it no longer exists.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public IActionResult SaveReminderRecordToVehicleId(ReminderRecordInput reminderRecord)
|
public IActionResult SaveReminderRecordToVehicleId(ReminderRecordInput reminderRecord)
|
||||||
{
|
{
|
||||||
@@ -1458,6 +1553,11 @@ namespace CarCareTracker.Controllers
|
|||||||
{
|
{
|
||||||
upgradeRecord.RequisitionHistory = RequisitionSupplyRecordsByUsage(upgradeRecord.Supplies, DateTime.Parse(upgradeRecord.Date), upgradeRecord.Description);
|
upgradeRecord.RequisitionHistory = RequisitionSupplyRecordsByUsage(upgradeRecord.Supplies, DateTime.Parse(upgradeRecord.Date), upgradeRecord.Description);
|
||||||
}
|
}
|
||||||
|
//push back any reminders
|
||||||
|
if (upgradeRecord.ReminderRecordId != default)
|
||||||
|
{
|
||||||
|
PushbackRecurringReminderRecordWithChecks(upgradeRecord.ReminderRecordId);
|
||||||
|
}
|
||||||
var result = _upgradeRecordDataAccess.SaveUpgradeRecordToVehicle(upgradeRecord.ToUpgradeRecord());
|
var result = _upgradeRecordDataAccess.SaveUpgradeRecordToVehicle(upgradeRecord.ToUpgradeRecord());
|
||||||
return Json(result);
|
return Json(result);
|
||||||
}
|
}
|
||||||
@@ -1508,7 +1608,7 @@ namespace CarCareTracker.Controllers
|
|||||||
public IActionResult GetPinnedNotesByVehicleId(int vehicleId)
|
public IActionResult GetPinnedNotesByVehicleId(int vehicleId)
|
||||||
{
|
{
|
||||||
var result = _noteDataAccess.GetNotesByVehicleId(vehicleId);
|
var result = _noteDataAccess.GetNotesByVehicleId(vehicleId);
|
||||||
result = result.Where(x=>x.Pinned).ToList();
|
result = result.Where(x => x.Pinned).ToList();
|
||||||
return Json(result);
|
return Json(result);
|
||||||
}
|
}
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
@@ -1534,6 +1634,24 @@ namespace CarCareTracker.Controllers
|
|||||||
var result = _noteDataAccess.DeleteNoteById(noteId);
|
var result = _noteDataAccess.DeleteNoteById(noteId);
|
||||||
return Json(result);
|
return Json(result);
|
||||||
}
|
}
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult PinNotes(List<int> noteIds, bool isToggle = false, bool pinStatus = false)
|
||||||
|
{
|
||||||
|
var result = false;
|
||||||
|
foreach(int noteId in noteIds)
|
||||||
|
{
|
||||||
|
var existingNote = _noteDataAccess.GetNoteById(noteId);
|
||||||
|
if (isToggle)
|
||||||
|
{
|
||||||
|
existingNote.Pinned = !existingNote.Pinned;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
existingNote.Pinned = pinStatus;
|
||||||
|
}
|
||||||
|
result = _noteDataAccess.SaveNoteToVehicle(existingNote);
|
||||||
|
}
|
||||||
|
return Json(result);
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
#region "Supply Records"
|
#region "Supply Records"
|
||||||
private List<string> CheckSupplyRecordsAvailability(List<SupplyUsage> supplyUsage)
|
private List<string> CheckSupplyRecordsAvailability(List<SupplyUsage> supplyUsage)
|
||||||
@@ -1558,11 +1676,11 @@ namespace CarCareTracker.Controllers
|
|||||||
private List<SupplyUsageHistory> RequisitionSupplyRecordsByUsage(List<SupplyUsage> supplyUsage, DateTime dateRequisitioned, string usageDescription)
|
private List<SupplyUsageHistory> RequisitionSupplyRecordsByUsage(List<SupplyUsage> supplyUsage, DateTime dateRequisitioned, string usageDescription)
|
||||||
{
|
{
|
||||||
List<SupplyUsageHistory> results = new List<SupplyUsageHistory>();
|
List<SupplyUsageHistory> results = new List<SupplyUsageHistory>();
|
||||||
foreach(SupplyUsage supply in supplyUsage)
|
foreach (SupplyUsage supply in supplyUsage)
|
||||||
{
|
{
|
||||||
//get supply record.
|
//get supply record.
|
||||||
var result = _supplyRecordDataAccess.GetSupplyRecordById(supply.SupplyId);
|
var result = _supplyRecordDataAccess.GetSupplyRecordById(supply.SupplyId);
|
||||||
var unitCost = (result.Quantity != 0 ) ? result.Cost / result.Quantity : 0;
|
var unitCost = (result.Quantity != 0) ? result.Cost / result.Quantity : 0;
|
||||||
//deduct quantity used.
|
//deduct quantity used.
|
||||||
result.Quantity -= supply.Quantity;
|
result.Quantity -= supply.Quantity;
|
||||||
//deduct cost.
|
//deduct cost.
|
||||||
@@ -1701,10 +1819,10 @@ namespace CarCareTracker.Controllers
|
|||||||
public IActionResult SavePlanRecordTemplateToVehicleId(PlanRecordInput planRecord)
|
public IActionResult SavePlanRecordTemplateToVehicleId(PlanRecordInput planRecord)
|
||||||
{
|
{
|
||||||
//check if template name already taken.
|
//check if template name already taken.
|
||||||
var existingRecord = _planRecordTemplateDataAccess.GetPlanRecordTemplatesByVehicleId(planRecord.VehicleId).Where(x=>x.Description == planRecord.Description).Any();
|
var existingRecord = _planRecordTemplateDataAccess.GetPlanRecordTemplatesByVehicleId(planRecord.VehicleId).Where(x => x.Description == planRecord.Description).Any();
|
||||||
if (existingRecord)
|
if (existingRecord)
|
||||||
{
|
{
|
||||||
return Json(new OperationResponse { Success = false, Message = "A template with that description already exists for this vehicle"});
|
return Json(new OperationResponse { Success = false, Message = "A template with that description already exists for this vehicle" });
|
||||||
}
|
}
|
||||||
planRecord.Files = planRecord.Files.Select(x => { return new UploadedFiles { Name = x.Name, Location = _fileHelper.MoveFileFromTemp(x.Location, "documents/") }; }).ToList();
|
planRecord.Files = planRecord.Files.Select(x => { return new UploadedFiles { Name = x.Name, Location = _fileHelper.MoveFileFromTemp(x.Location, "documents/") }; }).ToList();
|
||||||
var result = _planRecordTemplateDataAccess.SavePlanRecordTemplateToVehicle(planRecord);
|
var result = _planRecordTemplateDataAccess.SavePlanRecordTemplateToVehicle(planRecord);
|
||||||
@@ -1757,7 +1875,7 @@ namespace CarCareTracker.Controllers
|
|||||||
{
|
{
|
||||||
existingRecord.RequisitionHistory = RequisitionSupplyRecordsByUsage(existingRecord.Supplies, DateTime.Parse(existingRecord.DateCreated), existingRecord.Description);
|
existingRecord.RequisitionHistory = RequisitionSupplyRecordsByUsage(existingRecord.Supplies, DateTime.Parse(existingRecord.DateCreated), existingRecord.Description);
|
||||||
}
|
}
|
||||||
var result = _planRecordDataAccess.SavePlanRecordToVehicle(existingRecord.ToPlanRecord());
|
var result = _planRecordDataAccess.SavePlanRecordToVehicle(existingRecord.ToPlanRecord());
|
||||||
return Json(new OperationResponse { Success = result, Message = result ? "Plan Record Added" : StaticHelper.GenericErrorMessage });
|
return Json(new OperationResponse { Success = result, Message = result ? "Plan Record Added" : StaticHelper.GenericErrorMessage });
|
||||||
}
|
}
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
@@ -1847,20 +1965,7 @@ namespace CarCareTracker.Controllers
|
|||||||
//push back any reminders
|
//push back any reminders
|
||||||
if (existingRecord.ReminderRecordId != default)
|
if (existingRecord.ReminderRecordId != default)
|
||||||
{
|
{
|
||||||
var existingReminder = _reminderRecordDataAccess.GetReminderRecordById(existingRecord.ReminderRecordId);
|
PushbackRecurringReminderRecordWithChecks(existingRecord.ReminderRecordId);
|
||||||
if (existingReminder is not null && existingReminder.Id != default && existingReminder.IsRecurring)
|
|
||||||
{
|
|
||||||
existingReminder = _reminderHelper.GetUpdatedRecurringReminderRecord(existingReminder);
|
|
||||||
//save to db.
|
|
||||||
var reminderUpdateResult = _reminderRecordDataAccess.SaveReminderRecordToVehicle(existingReminder);
|
|
||||||
if (!reminderUpdateResult)
|
|
||||||
{
|
|
||||||
_logger.LogError("Unable to update reminder either because the reminder no longer exists or is no longer recurring");
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
_logger.LogError("Unable to update reminder because it no longer exists.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Json(result);
|
return Json(result);
|
||||||
@@ -2000,6 +2105,291 @@ namespace CarCareTracker.Controllers
|
|||||||
}
|
}
|
||||||
return Json(result);
|
return Json(result);
|
||||||
}
|
}
|
||||||
|
public IActionResult MoveRecords(List<int> recordIds, ImportMode source, ImportMode destination)
|
||||||
|
{
|
||||||
|
var genericRecord = new GenericRecord();
|
||||||
|
bool result = false;
|
||||||
|
foreach (int recordId in recordIds)
|
||||||
|
{
|
||||||
|
//get
|
||||||
|
switch (source)
|
||||||
|
{
|
||||||
|
case ImportMode.ServiceRecord:
|
||||||
|
genericRecord = _serviceRecordDataAccess.GetServiceRecordById(recordId);
|
||||||
|
break;
|
||||||
|
case ImportMode.RepairRecord:
|
||||||
|
genericRecord = _collisionRecordDataAccess.GetCollisionRecordById(recordId);
|
||||||
|
break;
|
||||||
|
case ImportMode.UpgradeRecord:
|
||||||
|
genericRecord = _upgradeRecordDataAccess.GetUpgradeRecordById(recordId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//save
|
||||||
|
switch (destination)
|
||||||
|
{
|
||||||
|
case ImportMode.ServiceRecord:
|
||||||
|
result = _serviceRecordDataAccess.SaveServiceRecordToVehicle(StaticHelper.GenericToServiceRecord(genericRecord));
|
||||||
|
break;
|
||||||
|
case ImportMode.RepairRecord:
|
||||||
|
result = _collisionRecordDataAccess.SaveCollisionRecordToVehicle(StaticHelper.GenericToRepairRecord(genericRecord));
|
||||||
|
break;
|
||||||
|
case ImportMode.UpgradeRecord:
|
||||||
|
result = _upgradeRecordDataAccess.SaveUpgradeRecordToVehicle(StaticHelper.GenericToUpgradeRecord(genericRecord));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//delete
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
switch (source)
|
||||||
|
{
|
||||||
|
case ImportMode.ServiceRecord:
|
||||||
|
_serviceRecordDataAccess.DeleteServiceRecordById(recordId);
|
||||||
|
break;
|
||||||
|
case ImportMode.RepairRecord:
|
||||||
|
_collisionRecordDataAccess.DeleteCollisionRecordById(recordId);
|
||||||
|
break;
|
||||||
|
case ImportMode.UpgradeRecord:
|
||||||
|
_upgradeRecordDataAccess.DeleteUpgradeRecordById(recordId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Json(result);
|
||||||
|
}
|
||||||
|
public IActionResult DeleteRecords(List<int> recordIds, ImportMode importMode)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
foreach (int recordId in recordIds)
|
||||||
|
{
|
||||||
|
switch (importMode)
|
||||||
|
{
|
||||||
|
case ImportMode.ServiceRecord:
|
||||||
|
result = _serviceRecordDataAccess.DeleteServiceRecordById(recordId);
|
||||||
|
break;
|
||||||
|
case ImportMode.RepairRecord:
|
||||||
|
result = _collisionRecordDataAccess.DeleteCollisionRecordById(recordId);
|
||||||
|
break;
|
||||||
|
case ImportMode.UpgradeRecord:
|
||||||
|
result = _upgradeRecordDataAccess.DeleteUpgradeRecordById(recordId);
|
||||||
|
break;
|
||||||
|
case ImportMode.GasRecord:
|
||||||
|
result = _gasRecordDataAccess.DeleteGasRecordById(recordId);
|
||||||
|
break;
|
||||||
|
case ImportMode.TaxRecord:
|
||||||
|
result = _taxRecordDataAccess.DeleteTaxRecordById(recordId);
|
||||||
|
break;
|
||||||
|
case ImportMode.SupplyRecord:
|
||||||
|
result = _supplyRecordDataAccess.DeleteSupplyRecordById(recordId);
|
||||||
|
break;
|
||||||
|
case ImportMode.NoteRecord:
|
||||||
|
result = _noteDataAccess.DeleteNoteById(recordId);
|
||||||
|
break;
|
||||||
|
case ImportMode.OdometerRecord:
|
||||||
|
result = _odometerRecordDataAccess.DeleteOdometerRecordById(recordId);
|
||||||
|
break;
|
||||||
|
case ImportMode.ReminderRecord:
|
||||||
|
result = _reminderRecordDataAccess.DeleteReminderRecordById(recordId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Json(result);
|
||||||
|
}
|
||||||
|
public IActionResult DuplicateRecords(List<int> recordIds, ImportMode importMode)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
foreach (int recordId in recordIds)
|
||||||
|
{
|
||||||
|
switch (importMode)
|
||||||
|
{
|
||||||
|
case ImportMode.ServiceRecord:
|
||||||
|
{
|
||||||
|
var existingRecord = _serviceRecordDataAccess.GetServiceRecordById(recordId);
|
||||||
|
existingRecord.Id = default;
|
||||||
|
result = _serviceRecordDataAccess.SaveServiceRecordToVehicle(existingRecord);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ImportMode.RepairRecord:
|
||||||
|
{
|
||||||
|
var existingRecord = _collisionRecordDataAccess.GetCollisionRecordById(recordId);
|
||||||
|
existingRecord.Id = default;
|
||||||
|
result = _collisionRecordDataAccess.SaveCollisionRecordToVehicle(existingRecord);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ImportMode.UpgradeRecord:
|
||||||
|
{
|
||||||
|
var existingRecord = _upgradeRecordDataAccess.GetUpgradeRecordById(recordId);
|
||||||
|
existingRecord.Id = default;
|
||||||
|
result = _upgradeRecordDataAccess.SaveUpgradeRecordToVehicle(existingRecord);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ImportMode.GasRecord:
|
||||||
|
{
|
||||||
|
var existingRecord = _gasRecordDataAccess.GetGasRecordById(recordId);
|
||||||
|
existingRecord.Id = default;
|
||||||
|
result = _gasRecordDataAccess.SaveGasRecordToVehicle(existingRecord);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ImportMode.TaxRecord:
|
||||||
|
{
|
||||||
|
var existingRecord = _taxRecordDataAccess.GetTaxRecordById(recordId);
|
||||||
|
existingRecord.Id = default;
|
||||||
|
result = _taxRecordDataAccess.SaveTaxRecordToVehicle(existingRecord);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ImportMode.SupplyRecord:
|
||||||
|
{
|
||||||
|
var existingRecord = _supplyRecordDataAccess.GetSupplyRecordById(recordId);
|
||||||
|
existingRecord.Id = default;
|
||||||
|
result = _supplyRecordDataAccess.SaveSupplyRecordToVehicle(existingRecord);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ImportMode.NoteRecord:
|
||||||
|
{
|
||||||
|
var existingRecord = _noteDataAccess.GetNoteById(recordId);
|
||||||
|
existingRecord.Id = default;
|
||||||
|
result = _noteDataAccess.SaveNoteToVehicle(existingRecord);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ImportMode.OdometerRecord:
|
||||||
|
{
|
||||||
|
var existingRecord = _odometerRecordDataAccess.GetOdometerRecordById(recordId);
|
||||||
|
existingRecord.Id = default;
|
||||||
|
result = _odometerRecordDataAccess.SaveOdometerRecordToVehicle(existingRecord);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ImportMode.ReminderRecord:
|
||||||
|
{
|
||||||
|
var existingRecord = _reminderRecordDataAccess.GetReminderRecordById(recordId);
|
||||||
|
existingRecord.Id = default;
|
||||||
|
result = _reminderRecordDataAccess.SaveReminderRecordToVehicle(existingRecord);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Json(result);
|
||||||
|
}
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult GetGenericRecordModal(List<int> recordIds, ImportMode dataType)
|
||||||
|
{
|
||||||
|
return PartialView("_GenericRecordModal", new GenericRecordEditModel() { DataType = dataType, RecordIds = recordIds });
|
||||||
|
}
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult EditMultipleRecords(GenericRecordEditModel genericRecordEditModel)
|
||||||
|
{
|
||||||
|
var dateIsEdited = genericRecordEditModel.EditRecord.Date != default;
|
||||||
|
var descriptionIsEdited = !string.IsNullOrWhiteSpace(genericRecordEditModel.EditRecord.Description);
|
||||||
|
var mileageIsEdited = genericRecordEditModel.EditRecord.Mileage != default;
|
||||||
|
var costIsEdited = genericRecordEditModel.EditRecord.Cost != default;
|
||||||
|
var noteIsEdited = !string.IsNullOrWhiteSpace(genericRecordEditModel.EditRecord.Notes);
|
||||||
|
var tagsIsEdited = genericRecordEditModel.EditRecord.Tags.Any();
|
||||||
|
//handle clear overrides
|
||||||
|
if (tagsIsEdited && genericRecordEditModel.EditRecord.Tags.Contains("---"))
|
||||||
|
{
|
||||||
|
genericRecordEditModel.EditRecord.Tags = new List<string>();
|
||||||
|
}
|
||||||
|
if (noteIsEdited && genericRecordEditModel.EditRecord.Notes == "---")
|
||||||
|
{
|
||||||
|
genericRecordEditModel.EditRecord.Notes = "";
|
||||||
|
}
|
||||||
|
bool result = false;
|
||||||
|
foreach (int recordId in genericRecordEditModel.RecordIds)
|
||||||
|
{
|
||||||
|
switch (genericRecordEditModel.DataType)
|
||||||
|
{
|
||||||
|
case ImportMode.ServiceRecord:
|
||||||
|
{
|
||||||
|
var existingRecord = _serviceRecordDataAccess.GetServiceRecordById(recordId);
|
||||||
|
if (dateIsEdited)
|
||||||
|
{
|
||||||
|
existingRecord.Date = genericRecordEditModel.EditRecord.Date;
|
||||||
|
}
|
||||||
|
if (descriptionIsEdited)
|
||||||
|
{
|
||||||
|
existingRecord.Description = genericRecordEditModel.EditRecord.Description;
|
||||||
|
}
|
||||||
|
if (mileageIsEdited)
|
||||||
|
{
|
||||||
|
existingRecord.Mileage = genericRecordEditModel.EditRecord.Mileage;
|
||||||
|
}
|
||||||
|
if (costIsEdited)
|
||||||
|
{
|
||||||
|
existingRecord.Cost = genericRecordEditModel.EditRecord.Cost;
|
||||||
|
}
|
||||||
|
if (noteIsEdited)
|
||||||
|
{
|
||||||
|
existingRecord.Notes = genericRecordEditModel.EditRecord.Notes;
|
||||||
|
}
|
||||||
|
if (tagsIsEdited)
|
||||||
|
{
|
||||||
|
existingRecord.Tags = genericRecordEditModel.EditRecord.Tags;
|
||||||
|
}
|
||||||
|
result = _serviceRecordDataAccess.SaveServiceRecordToVehicle(existingRecord);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ImportMode.RepairRecord:
|
||||||
|
{
|
||||||
|
var existingRecord = _collisionRecordDataAccess.GetCollisionRecordById(recordId);
|
||||||
|
if (dateIsEdited)
|
||||||
|
{
|
||||||
|
existingRecord.Date = genericRecordEditModel.EditRecord.Date;
|
||||||
|
}
|
||||||
|
if (descriptionIsEdited)
|
||||||
|
{
|
||||||
|
existingRecord.Description = genericRecordEditModel.EditRecord.Description;
|
||||||
|
}
|
||||||
|
if (mileageIsEdited)
|
||||||
|
{
|
||||||
|
existingRecord.Mileage = genericRecordEditModel.EditRecord.Mileage;
|
||||||
|
}
|
||||||
|
if (costIsEdited)
|
||||||
|
{
|
||||||
|
existingRecord.Cost = genericRecordEditModel.EditRecord.Cost;
|
||||||
|
}
|
||||||
|
if (noteIsEdited)
|
||||||
|
{
|
||||||
|
existingRecord.Notes = genericRecordEditModel.EditRecord.Notes;
|
||||||
|
}
|
||||||
|
if (tagsIsEdited)
|
||||||
|
{
|
||||||
|
existingRecord.Tags = genericRecordEditModel.EditRecord.Tags;
|
||||||
|
}
|
||||||
|
result = _collisionRecordDataAccess.SaveCollisionRecordToVehicle(existingRecord);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ImportMode.UpgradeRecord:
|
||||||
|
{
|
||||||
|
var existingRecord = _upgradeRecordDataAccess.GetUpgradeRecordById(recordId);
|
||||||
|
if (dateIsEdited)
|
||||||
|
{
|
||||||
|
existingRecord.Date = genericRecordEditModel.EditRecord.Date;
|
||||||
|
}
|
||||||
|
if (descriptionIsEdited)
|
||||||
|
{
|
||||||
|
existingRecord.Description = genericRecordEditModel.EditRecord.Description;
|
||||||
|
}
|
||||||
|
if (mileageIsEdited)
|
||||||
|
{
|
||||||
|
existingRecord.Mileage = genericRecordEditModel.EditRecord.Mileage;
|
||||||
|
}
|
||||||
|
if (costIsEdited)
|
||||||
|
{
|
||||||
|
existingRecord.Cost = genericRecordEditModel.EditRecord.Cost;
|
||||||
|
}
|
||||||
|
if (noteIsEdited)
|
||||||
|
{
|
||||||
|
existingRecord.Notes = genericRecordEditModel.EditRecord.Notes;
|
||||||
|
}
|
||||||
|
if (tagsIsEdited)
|
||||||
|
{
|
||||||
|
existingRecord.Tags = genericRecordEditModel.EditRecord.Tags;
|
||||||
|
}
|
||||||
|
result = _upgradeRecordDataAccess.SaveUpgradeRecordToVehicle(existingRecord);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Json(result);
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using CarCareTracker.Models;
|
using CarCareTracker.Models;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace CarCareTracker.Helper
|
namespace CarCareTracker.Helper
|
||||||
{
|
{
|
||||||
@@ -130,7 +129,8 @@ namespace CarCareTracker.Helper
|
|||||||
Files = input.Files,
|
Files = input.Files,
|
||||||
Notes = input.Notes,
|
Notes = input.Notes,
|
||||||
Tags = input.Tags,
|
Tags = input.Tags,
|
||||||
ExtraFields = input.ExtraFields
|
ExtraFields = input.ExtraFields,
|
||||||
|
RequisitionHistory = input.RequisitionHistory
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
public static CollisionRecord GenericToRepairRecord(GenericRecord input)
|
public static CollisionRecord GenericToRepairRecord(GenericRecord input)
|
||||||
@@ -145,7 +145,8 @@ namespace CarCareTracker.Helper
|
|||||||
Files = input.Files,
|
Files = input.Files,
|
||||||
Notes = input.Notes,
|
Notes = input.Notes,
|
||||||
Tags = input.Tags,
|
Tags = input.Tags,
|
||||||
ExtraFields = input.ExtraFields
|
ExtraFields = input.ExtraFields,
|
||||||
|
RequisitionHistory = input.RequisitionHistory
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
public static UpgradeRecord GenericToUpgradeRecord(GenericRecord input)
|
public static UpgradeRecord GenericToUpgradeRecord(GenericRecord input)
|
||||||
@@ -160,7 +161,8 @@ namespace CarCareTracker.Helper
|
|||||||
Files = input.Files,
|
Files = input.Files,
|
||||||
Notes = input.Notes,
|
Notes = input.Notes,
|
||||||
Tags = input.Tags,
|
Tags = input.Tags,
|
||||||
ExtraFields = input.ExtraFields
|
ExtraFields = input.ExtraFields,
|
||||||
|
RequisitionHistory = input.RequisitionHistory
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using CarCareTracker.Models;
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using Microsoft.Extensions.Caching.Memory;
|
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace CarCareTracker.Helper
|
namespace CarCareTracker.Helper
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
using CarCareTracker.Helper;
|
using CarCareTracker.Helper;
|
||||||
using CarCareTracker.Models;
|
using CarCareTracker.Models;
|
||||||
using Microsoft.Extensions.Caching.Memory;
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using System.Net;
|
|
||||||
using System.Net.Mail;
|
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using CarCareTracker.External.Interfaces;
|
using CarCareTracker.External.Interfaces;
|
||||||
using CarCareTracker.Helper;
|
using CarCareTracker.Helper;
|
||||||
using CarCareTracker.Models;
|
using CarCareTracker.Models;
|
||||||
using Microsoft.AspNetCore.Mvc.Formatters;
|
|
||||||
|
|
||||||
namespace CarCareTracker.Logic
|
namespace CarCareTracker.Logic
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
using CarCareTracker.Logic;
|
using CarCareTracker.Logic;
|
||||||
using CarCareTracker.Models;
|
using CarCareTracker.Models;
|
||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.AspNetCore.Authentication;
|
||||||
using Microsoft.AspNetCore.Components.Web;
|
|
||||||
using Microsoft.AspNetCore.DataProtection;
|
using Microsoft.AspNetCore.DataProtection;
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using System.Text.Encodings.Web;
|
using System.Text.Encodings.Web;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
{
|
{
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public int VehicleId { get; set; }
|
public int VehicleId { get; set; }
|
||||||
|
public int ReminderRecordId { get; set; }
|
||||||
public string Date { get; set; } = DateTime.Now.ToShortDateString();
|
public string Date { get; set; } = DateTime.Now.ToShortDateString();
|
||||||
public int Mileage { get; set; }
|
public int Mileage { get; set; }
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
|
|||||||
9
Models/GenericRecordEditModel.cs
Normal file
9
Models/GenericRecordEditModel.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace CarCareTracker.Models
|
||||||
|
{
|
||||||
|
public class GenericRecordEditModel
|
||||||
|
{
|
||||||
|
public ImportMode DataType { get; set; }
|
||||||
|
public List<int> RecordIds { get; set; } = new List<int>();
|
||||||
|
public GenericRecord EditRecord { get; set; } = new GenericRecord();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
{
|
{
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public int VehicleId { get; set; }
|
public int VehicleId { get; set; }
|
||||||
|
public int ReminderRecordId { get; set; }
|
||||||
public string Date { get; set; } = DateTime.Now.ToShortDateString();
|
public string Date { get; set; } = DateTime.Now.ToShortDateString();
|
||||||
public int Mileage { get; set; }
|
public int Mileage { get; set; }
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
{
|
{
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public int VehicleId { get; set; }
|
public int VehicleId { get; set; }
|
||||||
|
public int ReminderRecordId { get; set; }
|
||||||
public string Date { get; set; } = DateTime.Now.ToShortDateString();
|
public string Date { get; set; } = DateTime.Now.ToShortDateString();
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
public decimal Cost { get; set; }
|
public decimal Cost { get; set; }
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
{
|
{
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public int VehicleId { get; set; }
|
public int VehicleId { get; set; }
|
||||||
|
public int ReminderRecordId { get; set; }
|
||||||
public string Date { get; set; } = DateTime.Now.ToShortDateString();
|
public string Date { get; set; } = DateTime.Now.ToShortDateString();
|
||||||
public int Mileage { get; set; }
|
public int Mileage { get; set; }
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
|
|||||||
79
README.md
79
README.md
@@ -1,39 +1,32 @@
|
|||||||

|

|
||||||
|
|
||||||
A self-hosted, open-source vehicle service records and maintainence tracker.
|
A self-hosted, open-source vehicle service records and maintenance tracker.
|
||||||
|
|
||||||
Visit our website: https://lubelogger.com
|
Visit our website: https://lubelogger.com
|
||||||
|
|
||||||
Support this project by [Subscribing on Patreon](https://patreon.com/LubeLogger) or [Making a Donation](https://buy.stripe.com/aEU9Egc8DdMc9bO144)
|
Support this project by [Subscribing on Patreon](https://patreon.com/LubeLogger) or [Making a Donation](https://buy.stripe.com/aEU9Egc8DdMc9bO144)
|
||||||
|
|
||||||
## Why
|
Note: Commercial users are required to maintain an active Patreon subscripton to be compliant with our licensing model.
|
||||||
Because nobody should have to deal with a homemade spreadsheet or a shoebox full of receipts when it comes to vehicle maintainence.
|
|
||||||
|
|
||||||
## Screenshots
|
## Why
|
||||||
<a href="/docs/screenshots.md">Screenshots</a>
|
Because nobody should have to deal with a homemade spreadsheet or a shoebox full of receipts when it comes to vehicle maintenance.
|
||||||
|
|
||||||
|
## Showcase
|
||||||
|
[Promotional Brochure](https://lubelogger.com/brochure.pdf)
|
||||||
|
|
||||||
|
[Screenshots](/docs/screenshots.md)
|
||||||
|
|
||||||
## Demo
|
## Demo
|
||||||
Try it out before you download it! The live demo resets every 20 minutes.
|
Try it out before you download it! The live demo resets every 20 minutes.
|
||||||
|
|
||||||
[Live Demo](https://demo.lubelogger.com) Login using username "test" and password "1234"
|
[Live Demo - Latest Stable](https://demo.lubelogger.com) Login using username "test" and password "1234"
|
||||||
|
|
||||||
## Dependencies
|
## Download
|
||||||
- Bootstrap
|
LubeLogger is distributed both as a Docker image or a Windows Standalone Executable.
|
||||||
- LiteDB
|
|
||||||
- Bootstrap-DatePicker
|
|
||||||
- SweetAlert2
|
|
||||||
- CsvHelper
|
|
||||||
- Chart.js
|
|
||||||
- Drawdown
|
|
||||||
|
|
||||||
## Docker Setup (GHCR)
|
Read this [Getting Started Guide](https://docs.lubelogger.com/Getting%20Started) on how to download either of them
|
||||||
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. You can also setup SMTP Config here.
|
|
||||||
4. If using traefik, use docker-compose.traefik.yml
|
|
||||||
5. Run `docker-compose up`
|
|
||||||
|
|
||||||
## Docker Setup (Manual Build)
|
### Docker Setup (Manual Build)
|
||||||
1. Install Docker
|
1. Install Docker
|
||||||
2. Clone this repo
|
2. Clone this repo
|
||||||
3. CHECK culture in .env file, default is en_US, also setup SMTP for user management if you want that.
|
3. CHECK culture in .env file, default is en_US, also setup SMTP for user management if you want that.
|
||||||
@@ -42,38 +35,12 @@ Try it out before you download it! The live demo resets every 20 minutes.
|
|||||||
6. If using traefik, use docker-compose.traefik.yml
|
6. If using traefik, use docker-compose.traefik.yml
|
||||||
7. Run `docker-compose up`
|
7. Run `docker-compose up`
|
||||||
|
|
||||||
## Additional Docker Instructions
|
## Dependencies
|
||||||
|
- Bootstrap
|
||||||
### manual
|
- LiteDB
|
||||||
|
- Npgsql
|
||||||
- build
|
- Bootstrap-DatePicker
|
||||||
|
- SweetAlert2
|
||||||
```
|
- CsvHelper
|
||||||
docker build -t hargata/lubelog:latest .
|
- Chart.js
|
||||||
```
|
- Drawdown
|
||||||
|
|
||||||
- run
|
|
||||||
|
|
||||||
```
|
|
||||||
docker run -d hargata/lubelog:latest
|
|
||||||
```
|
|
||||||
|
|
||||||
add `-v` for persistent volumes as needed. Have a look at the docker-compose.yml for examples.
|
|
||||||
|
|
||||||
## docker-compose
|
|
||||||
|
|
||||||
- build image
|
|
||||||
|
|
||||||
```
|
|
||||||
docker compose build
|
|
||||||
```
|
|
||||||
|
|
||||||
- run
|
|
||||||
|
|
||||||
```
|
|
||||||
docker compose up
|
|
||||||
|
|
||||||
# or variant with traefik labels:
|
|
||||||
|
|
||||||
docker compose -f docker-compose.traefik.yml up
|
|
||||||
```
|
|
||||||
|
|||||||
@@ -24,11 +24,11 @@
|
|||||||
@if(config.GetServerEnableShopSupplies())
|
@if(config.GetServerEnableShopSupplies())
|
||||||
{
|
{
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<button class="nav-link" id="supply-tab" data-bs-toggle="tab" data-bs-target="#supply-tab-pane" type="button" role="tab"><span class="ms-2 display-3"><i class="bi bi-shop me-2"></i>@translator.Translate(userLanguage, "Supplies")</button>
|
<button class="nav-link" id="supply-tab" data-bs-toggle="tab" data-bs-target="#supply-tab-pane" type="button" role="tab"><span class="ms-2 display-3"><i class="bi bi-shop me-2"></i>@translator.Translate(userLanguage, "Supplies")</span></button>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<button class="nav-link" id="calendar-tab" data-bs-toggle="tab" data-bs-target="#calendar-tab-pane" type="button" role="tab"><span class="ms-2 display-3"><i class="bi bi-calendar-week me-2"></i>@translator.Translate(userLanguage, "Calendar")</button>
|
<button class="nav-link" id="calendar-tab" data-bs-toggle="tab" data-bs-target="#calendar-tab-pane" type="button" role="tab"><span class="ms-2 display-3"><i class="bi bi-calendar-week me-2"></i>@translator.Translate(userLanguage, "Calendar")</span></button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<button class="nav-link @(Model == "settings" ? "active" : "")" id="settings-tab" data-bs-toggle="tab" data-bs-target="#settings-tab-pane" type="button" role="tab"><span class="ms-2 display-3"><i class="bi bi-gear me-2"></i>@translator.Translate(userLanguage,"Settings")</span></button>
|
<button class="nav-link @(Model == "settings" ? "active" : "")" id="settings-tab" data-bs-toggle="tab" data-bs-target="#settings-tab-pane" type="button" role="tab"><span class="ms-2 display-3"><i class="bi bi-gear me-2"></i>@translator.Translate(userLanguage,"Settings")</span></button>
|
||||||
|
|||||||
@@ -201,7 +201,7 @@
|
|||||||
<img src="/defaults/lubelogger_logo.png" />
|
<img src="/defaults/lubelogger_logo.png" />
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex justify-content-center">
|
<div class="d-flex justify-content-center">
|
||||||
<small class="text-body-secondary">Version 1.2.1</small>
|
<small class="text-body-secondary">Version 1.2.2</small>
|
||||||
</div>
|
</div>
|
||||||
<p class="lead">
|
<p class="lead">
|
||||||
Proudly developed in the rural town of Price, Utah by Hargata Softworks.
|
Proudly developed in the rural town of Price, Utah by Hargata Softworks.
|
||||||
|
|||||||
@@ -156,6 +156,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="modal fade" data-bs-focus="false" id="genericRecordEditModal" tabindex="-1" role="dialog" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-lg" role="document">
|
||||||
|
<div class="modal-content" id="genericRecordEditModalContent">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="modal fade" data-bs-focus="false" id="inputSuppliesModal" tabindex="-1" role="dialog" aria-hidden="true" data-bs-backdrop="static" data-bs-keyboard="false">
|
<div class="modal fade" data-bs-focus="false" id="inputSuppliesModal" tabindex="-1" role="dialog" aria-hidden="true" data-bs-backdrop="static" data-bs-keyboard="false">
|
||||||
<div class="modal-dialog modal-lg" role="document">
|
<div class="modal-dialog modal-lg" role="document">
|
||||||
<div class="modal-content" id="inputSuppliesModalContent"></div>
|
<div class="modal-content" id="inputSuppliesModalContent"></div>
|
||||||
|
|||||||
@@ -26,6 +26,14 @@
|
|||||||
<input type="number" inputmode="numeric" id="collisionRecordMileage" class="form-control" placeholder="@translator.Translate(userLanguage,"Odometer reading when repaired")" value="@(isNew ? "" : Model.Mileage)">
|
<input type="number" inputmode="numeric" id="collisionRecordMileage" class="form-control" placeholder="@translator.Translate(userLanguage,"Odometer reading when repaired")" value="@(isNew ? "" : Model.Mileage)">
|
||||||
<label for="collisionRecordDescription">@translator.Translate(userLanguage,"Description")</label>
|
<label for="collisionRecordDescription">@translator.Translate(userLanguage,"Description")</label>
|
||||||
<input type="text" id="collisionRecordDescription" class="form-control" placeholder="@translator.Translate(userLanguage,"Description of item(s) repaired(i.e. Alternator)")" value="@Model.Description">
|
<input type="text" id="collisionRecordDescription" class="form-control" placeholder="@translator.Translate(userLanguage,"Description of item(s) repaired(i.e. Alternator)")" value="@Model.Description">
|
||||||
|
@if (isNew)
|
||||||
|
{
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<a onclick="showRecurringReminderSelector('collisionRecordDescription')" class="btn btn-link">@translator.Translate(userLanguage, "Select Reminder")</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
<label for="collisionRecordCost">@translator.Translate(userLanguage,"Cost")</label>
|
<label for="collisionRecordCost">@translator.Translate(userLanguage,"Cost")</label>
|
||||||
<input type="text" inputmode="decimal" id="collisionRecordCost" class="form-control" placeholder="@translator.Translate(userLanguage,"Cost of the repair")" value="@(isNew ? "" : Model.Cost)">
|
<input type="text" inputmode="decimal" id="collisionRecordCost" class="form-control" placeholder="@translator.Translate(userLanguage,"Cost of the repair")" value="@(isNew ? "" : Model.Cost)">
|
||||||
@if (isNew)
|
@if (isNew)
|
||||||
@@ -113,6 +121,7 @@
|
|||||||
<script>
|
<script>
|
||||||
var uploadedFiles = [];
|
var uploadedFiles = [];
|
||||||
var selectedSupplies = [];
|
var selectedSupplies = [];
|
||||||
|
var recurringReminderRecordId = 0;
|
||||||
getUploadedFilesFromModel();
|
getUploadedFilesFromModel();
|
||||||
function getUploadedFilesFromModel() {
|
function getUploadedFilesFromModel() {
|
||||||
@foreach (UploadedFiles filesUploaded in Model.Files)
|
@foreach (UploadedFiles filesUploaded in Model.Files)
|
||||||
|
|||||||
@@ -68,7 +68,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
@foreach (CollisionRecord collisionRecord in Model)
|
@foreach (CollisionRecord collisionRecord in Model)
|
||||||
{
|
{
|
||||||
<tr class="d-flex" style="cursor:pointer;" onclick="showEditCollisionRecordModal(@collisionRecord.Id)" data-tags='@string.Join(" ", collisionRecord.Tags)'>
|
<tr class="d-flex user-select-none" style="cursor:pointer;" ontouchstart="detectRowLongTouch(this)" ontouchend="detectRowTouchEndPremature(this)" data-rowId="@collisionRecord.Id" oncontextmenu="showTableContextMenu(this)" onmousemove="rangeMouseMove(this)" onclick="handleTableRowClick(this, showEditCollisionRecordModal,@collisionRecord.Id)" data-tags='@string.Join(" ", collisionRecord.Tags)'>
|
||||||
<td class="col-2 col-xl-1">@collisionRecord.Date.ToShortDateString()</td>
|
<td class="col-2 col-xl-1">@collisionRecord.Date.ToShortDateString()</td>
|
||||||
<td class="col-2">@collisionRecord.Mileage</td>
|
<td class="col-2">@collisionRecord.Mileage</td>
|
||||||
<td class="col-3 col-xl-4">@collisionRecord.Description</td>
|
<td class="col-3 col-xl-4">@collisionRecord.Description</td>
|
||||||
@@ -87,4 +87,17 @@
|
|||||||
<div class="modal-content" id="collisionRecordModalContent">
|
<div class="modal-content" id="collisionRecordModalContent">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<ul class="table-context-menu dropdown-menu" style="display:none;">
|
||||||
|
<li><a class="context-menu-multiple context-menu-select-all dropdown-item" href="#" onclick="selectAllRows()">@translator.Translate(userLanguage, "Select All")</a></li>
|
||||||
|
<li><a class="context-menu-multiple context-menu-deselect-all dropdown-item" href="#" onclick="clearSelectedRows()">@translator.Translate(userLanguage, "Deselect All")</a></li>
|
||||||
|
<li><a class="context-menu-active-multiple dropdown-item" href="#" onclick="editMultipleRecords(selectedRow, 'RepairRecord')">@translator.Translate(userLanguage, "Edit Multiple")</a></li>
|
||||||
|
<li><hr class="context-menu-multiple dropdown-divider"></li>
|
||||||
|
<li><h6 class="dropdown-header">@translator.Translate(userLanguage, "Move To")</h6></li>
|
||||||
|
<li><a class="dropdown-item" href="#" onclick="moveRecords(selectedRow, 'RepairRecord', 'ServiceRecord')">@translator.Translate(userLanguage, "Service Records")</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#" onclick="moveRecords(selectedRow, 'RepairRecord', 'UpgradeRecord')">@translator.Translate(userLanguage, "Upgrades")</a></li>
|
||||||
|
<li><hr class="dropdown-divider"></li>
|
||||||
|
<li><a class="dropdown-item" href="#" onclick="duplicateRecords(selectedRow, 'RepairRecord')">@translator.Translate(userLanguage, "Duplicate")</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#" onclick="deleteRecords(selectedRow, 'RepairRecord')">@translator.Translate(userLanguage, "Delete")</a></li>
|
||||||
|
</ul>
|
||||||
@@ -112,7 +112,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
@foreach (GasRecordViewModel gasRecord in Model.GasRecords)
|
@foreach (GasRecordViewModel gasRecord in Model.GasRecords)
|
||||||
{
|
{
|
||||||
<tr class="d-flex" style="cursor:pointer;" onclick="showEditGasRecordModal(@gasRecord.Id)" data-tags='@string.Join(" ", gasRecord.Tags)'>
|
<tr class="d-flex user-select-none" style="cursor:pointer;" ontouchstart="detectRowLongTouch(this)" ontouchend="detectRowTouchEndPremature(this)" data-rowId="@gasRecord.Id" oncontextmenu="showTableContextMenu(this)" onmousemove="rangeMouseMove(this)" onclick="handleTableRowClick(this, showEditGasRecordModal,@gasRecord.Id)" data-tags='@string.Join(" ", gasRecord.Tags)'>
|
||||||
<td class="col-2">@gasRecord.Date</td>
|
<td class="col-2">@gasRecord.Date</td>
|
||||||
<td class="col-2" data-gas-type="mileage" data-gas-aggregate="@gasRecord.DeltaMileage" data-gas-original="@gasRecord.Mileage">@gasRecord.Mileage</td>
|
<td class="col-2" data-gas-type="mileage" data-gas-aggregate="@gasRecord.DeltaMileage" data-gas-original="@gasRecord.Mileage">@gasRecord.Mileage</td>
|
||||||
<td class="col-1">@(gasRecord.DeltaMileage == default ? "---" : gasRecord.DeltaMileage)</td>
|
<td class="col-1">@(gasRecord.DeltaMileage == default ? "---" : gasRecord.DeltaMileage)</td>
|
||||||
@@ -136,6 +136,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<ul class="table-context-menu dropdown-menu" style="display:none;">
|
||||||
|
<li><a class="context-menu-multiple context-menu-select-all dropdown-item" href="#" onclick="selectAllRows()">@translator.Translate(userLanguage, "Select All")</a></li>
|
||||||
|
<li><a class="context-menu-multiple context-menu-deselect-all dropdown-item" href="#" onclick="clearSelectedRows()">@translator.Translate(userLanguage, "Deselect All")</a></li>
|
||||||
|
<li><hr class="context-menu-multiple dropdown-divider"></li>
|
||||||
|
<li><a class="dropdown-item" href="#" onclick="duplicateRecords(selectedRow, 'GasRecord')">@translator.Translate(userLanguage, "Duplicate")</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#" onclick="deleteRecords(selectedRow, 'GasRecord')">@translator.Translate(userLanguage, "Delete")</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@if (!string.IsNullOrWhiteSpace(preferredFuelEconomyUnit))
|
@if (!string.IsNullOrWhiteSpace(preferredFuelEconomyUnit))
|
||||||
{
|
{
|
||||||
|
|||||||
55
Views/Vehicle/_GenericRecordModal.cshtml
Normal file
55
Views/Vehicle/_GenericRecordModal.cshtml
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
@using CarCareTracker.Helper
|
||||||
|
@inject IConfigHelper config
|
||||||
|
@inject ITranslationHelper translator
|
||||||
|
@model GenericRecordEditModel
|
||||||
|
@{
|
||||||
|
var userConfig = config.GetUserConfig(User);
|
||||||
|
var userLanguage = userConfig.UserLanguage;
|
||||||
|
}
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">@translator.Translate(userLanguage,"Edit Multiple Records")</h5>
|
||||||
|
<button type="button" class="btn-close" onclick="hideGenericRecordModal()" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<form>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6 col-12">
|
||||||
|
<label for="genericRecordDate">@translator.Translate(userLanguage,"Date")</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text" id="genericRecordDate" class="form-control" placeholder="@translator.Translate(userLanguage,"(multiple)")">
|
||||||
|
<span class="input-group-text"><i class="bi bi-calendar-event"></i></span>
|
||||||
|
</div>
|
||||||
|
<label for="genericRecordMileage">@translator.Translate(userLanguage,"Odometer")</label>
|
||||||
|
<input type="number" inputmode="numeric" id="genericRecordMileage" class="form-control" placeholder="@translator.Translate(userLanguage,"(multiple)")">
|
||||||
|
<label for="genericRecordDescription">@translator.Translate(userLanguage, "Description")</label>
|
||||||
|
<input type="text" id="genericRecordDescription" class="form-control" placeholder="@translator.Translate(userLanguage,"(multiple)")">
|
||||||
|
<label for="genericRecordCost">@translator.Translate(userLanguage, "Cost")</label>
|
||||||
|
<input type="text" inputmode="decimal" id="genericRecordCost" class="form-control" placeholder="@translator.Translate(userLanguage,"(multiple)")">
|
||||||
|
<label for="genericRecordTag">@translator.Translate(userLanguage, "Tags(use --- to clear all existing tags)")</label>
|
||||||
|
<select multiple class="form-select" id="genericRecordTag"></select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 col-12">
|
||||||
|
<label for="genericRecordNotes">@translator.Translate(userLanguage, "Notes(use --- to clear all existing notes)")<a class="link-underline link-underline-opacity-0" onclick="showLinks(this)"><i class="bi bi-markdown ms-2"></i></a></label>
|
||||||
|
<textarea id="genericRecordNotes" class="form-control" rows="5"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" onclick="hideGenericRecordModal()">@translator.Translate(userLanguage, "Cancel")</button>
|
||||||
|
<button type="button" class="btn btn-primary" onclick="saveGenericRecord()">@translator.Translate(userLanguage,"Edit")</button>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
var recordsToEdit = [];
|
||||||
|
@foreach(int recordId in Model.RecordIds)
|
||||||
|
{
|
||||||
|
@:recordsToEdit.push(@recordId);
|
||||||
|
}
|
||||||
|
function getGenericRecordEditModelData(){
|
||||||
|
return {
|
||||||
|
dataType: decodeHTMLEntities('@Model.DataType.ToString()')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
@foreach (Note note in Model)
|
@foreach (Note note in Model)
|
||||||
{
|
{
|
||||||
<tr class="d-flex" style="cursor:pointer;" onclick="showEditNoteModal(@note.Id)" data-tags='@string.Join(" ", note.Tags)'>
|
<tr class="d-flex user-select-none" style="cursor:pointer;" ontouchstart="detectRowLongTouch(this)" ontouchend="detectRowTouchEndPremature(this)" data-rowId="@note.Id" oncontextmenu="showTableContextMenu(this)" onmousemove="rangeMouseMove(this)" onclick="handleTableRowClick(this, showEditNoteModal,@note.Id)" data-tags='@string.Join(" ", note.Tags)'>
|
||||||
@if (note.Pinned)
|
@if (note.Pinned)
|
||||||
{
|
{
|
||||||
<td class="col-3"><i class='bi bi-pin-fill me-2'></i>@note.Description</td>
|
<td class="col-3"><i class='bi bi-pin-fill me-2'></i>@note.Description</td>
|
||||||
@@ -66,4 +66,16 @@
|
|||||||
<div class="modal-content" id="noteModalContent">
|
<div class="modal-content" id="noteModalContent">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<ul class="table-context-menu dropdown-menu" style="display:none;">
|
||||||
|
<li><a class="context-menu-multiple context-menu-select-all dropdown-item" href="#" onclick="selectAllRows()">@translator.Translate(userLanguage, "Select All")</a></li>
|
||||||
|
<li><a class="context-menu-multiple context-menu-deselect-all dropdown-item" href="#" onclick="clearSelectedRows()">@translator.Translate(userLanguage, "Deselect All")</a></li>
|
||||||
|
<li><hr class="context-menu-multiple dropdown-divider"></li>
|
||||||
|
<li><a class="dropdown-item" href="#" onclick="pinNotes(selectedRow, true)">@translator.Translate(userLanguage, "Toggle Pin")</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#" onclick="pinNotes(selectedRow, false, true)">@translator.Translate(userLanguage, "Pin")</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#" onclick="pinNotes(selectedRow, false, false)">@translator.Translate(userLanguage, "Unpin")</a></li>
|
||||||
|
<li><hr class="dropdown-divider"></li>
|
||||||
|
<li><a class="dropdown-item" href="#" onclick="duplicateRecords(selectedRow, 'NoteRecord')">@translator.Translate(userLanguage, "Duplicate")</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#" onclick="deleteRecords(selectedRow, 'NoteRecord')">@translator.Translate(userLanguage, "Delete")</a></li>
|
||||||
|
</ul>
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="d-flex justify-content-between">
|
<div class="d-flex justify-content-between">
|
||||||
<div class="d-flex align-items-center flex-wrap">
|
<div class="d-flex align-items-center flex-wrap">
|
||||||
<span class="ms-2 badge bg-success" data-aggregate-type="count">@($"{translator.Translate(userLanguage,"# of Odometer Records")}: {Model.Count()}")</span>
|
<span class="ms-2 badge bg-success" data-aggregate-type="count">@($"{translator.Translate(userLanguage, "# of Odometer Records")}: {Model.Count()}")</span>
|
||||||
@foreach (string recordTag in recordTags)
|
@foreach (string recordTag in recordTags)
|
||||||
{
|
{
|
||||||
<span onclick="filterTable('odometer-tab-pane', this)" class="user-select-none ms-2 rounded-pill badge bg-secondary tagfilter" style="cursor:pointer;">@recordTag</span>
|
<span onclick="filterTable('odometer-tab-pane', this)" class="user-select-none ms-2 rounded-pill badge bg-secondary tagfilter" style="cursor:pointer;">@recordTag</span>
|
||||||
@@ -28,21 +28,21 @@
|
|||||||
@if (enableCsvImports)
|
@if (enableCsvImports)
|
||||||
{
|
{
|
||||||
<div class="btn-group">
|
<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>@translator.Translate(userLanguage,"Add Odometer Record")</button>
|
<button onclick="showAddOdometerRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>@translator.Translate(userLanguage, "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">
|
<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>
|
<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('OdometerRecord')">@translator.Translate(userLanguage,"Import via CSV")</a></li>
|
<li><a class="dropdown-item" href="#" onclick="showBulkImportModal('OdometerRecord')">@translator.Translate(userLanguage, "Import via CSV")</a></li>
|
||||||
<li><a class="dropdown-item" href="#" onclick="exportVehicleData('OdometerRecord')">@translator.Translate(userLanguage,"Export to CSV")</a></li>
|
<li><a class="dropdown-item" href="#" onclick="exportVehicleData('OdometerRecord')">@translator.Translate(userLanguage, "Export to CSV")</a></li>
|
||||||
<li><hr class="dropdown-divider"></li>
|
<li><hr class="dropdown-divider"></li>
|
||||||
<li><a class="dropdown-item" href="#" onclick="printTab()">@translator.Translate(userLanguage,"Print")</a></li>
|
<li><a class="dropdown-item" href="#" onclick="printTab()">@translator.Translate(userLanguage, "Print")</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<button onclick="showAddOdometerRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>@translator.Translate(userLanguage,"Add Odometer Record")</button>
|
<button onclick="showAddOdometerRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>@translator.Translate(userLanguage, "Add Odometer Record")</button>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -57,15 +57,15 @@
|
|||||||
<table class="table table-hover">
|
<table class="table table-hover">
|
||||||
<thead class="sticky-top">
|
<thead class="sticky-top">
|
||||||
<tr class="d-flex">
|
<tr class="d-flex">
|
||||||
<th scope="col" class="col-2 col-xl-1">@translator.Translate(userLanguage,"Date")</th>
|
<th scope="col" class="col-2 col-xl-1">@translator.Translate(userLanguage, "Date")</th>
|
||||||
<th scope="col" class="col-3">@translator.Translate(userLanguage,"Odometer")</th>
|
<th scope="col" class="col-3">@translator.Translate(userLanguage, "Odometer")</th>
|
||||||
<th scope="col" class="col-7 col-xl-8">@translator.Translate(userLanguage,"Notes")</th>
|
<th scope="col" class="col-7 col-xl-8">@translator.Translate(userLanguage, "Notes")</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@foreach (OdometerRecord odometerRecord in Model)
|
@foreach (OdometerRecord odometerRecord in Model)
|
||||||
{
|
{
|
||||||
<tr class="d-flex" style="cursor:pointer;" onclick="showEditOdometerRecordModal(@odometerRecord.Id)" data-tags='@string.Join(" ", odometerRecord.Tags)'>
|
<tr class="d-flex user-select-none" style="cursor:pointer;" ontouchstart="detectRowLongTouch(this)" ontouchend="detectRowTouchEndPremature(this)" data-rowId="@odometerRecord.Id" oncontextmenu="showTableContextMenu(this)" onmousemove="rangeMouseMove(this)" onclick="handleTableRowClick(this, showEditOdometerRecordModal,@odometerRecord.Id)" data-tags='@string.Join(" ", odometerRecord.Tags)'>
|
||||||
<td class="col-2 col-xl-1">@odometerRecord.Date.ToShortDateString()</td>
|
<td class="col-2 col-xl-1">@odometerRecord.Date.ToShortDateString()</td>
|
||||||
<td class="col-3" data-record-type="cost">@odometerRecord.Mileage</td>
|
<td class="col-3" data-record-type="cost">@odometerRecord.Mileage</td>
|
||||||
<td class="col-7 col-xl-8 text-truncate">@CarCareTracker.Helper.StaticHelper.TruncateStrings(odometerRecord.Notes, 75)</td>
|
<td class="col-7 col-xl-8 text-truncate">@CarCareTracker.Helper.StaticHelper.TruncateStrings(odometerRecord.Notes, 75)</td>
|
||||||
@@ -82,4 +82,12 @@
|
|||||||
<div class="modal-content" id="odometerRecordModalContent">
|
<div class="modal-content" id="odometerRecordModalContent">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<ul class="table-context-menu dropdown-menu" style="display:none;">
|
||||||
|
<li><a class="context-menu-multiple context-menu-select-all dropdown-item" href="#" onclick="selectAllRows()">@translator.Translate(userLanguage, "Select All")</a></li>
|
||||||
|
<li><a class="context-menu-multiple context-menu-deselect-all dropdown-item" href="#" onclick="clearSelectedRows()">@translator.Translate(userLanguage, "Deselect All")</a></li>
|
||||||
|
<li><hr class="context-menu-multiple dropdown-divider"></li>
|
||||||
|
<li><a class="dropdown-item" href="#" onclick="duplicateRecords(selectedRow, 'OdometerRecord')">@translator.Translate(userLanguage, "Duplicate")</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#" onclick="deleteRecords(selectedRow, 'OdometerRecord')">@translator.Translate(userLanguage, "Delete")</a></li>
|
||||||
|
</ul>
|
||||||
13
Views/Vehicle/_RecurringReminderSelector.cshtml
Normal file
13
Views/Vehicle/_RecurringReminderSelector.cshtml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
@model List<ReminderRecord>
|
||||||
|
<select class="form-select" id="recurringReminderInput">
|
||||||
|
@if (Model.Any())
|
||||||
|
{
|
||||||
|
@foreach (ReminderRecord reminderRecord in Model)
|
||||||
|
{
|
||||||
|
<!option value="@reminderRecord.Id">@reminderRecord.Description</!option>
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
<!option value="0">No Recurring Reminders Found</!option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="number" inputmode="numeric" id="reminderMileage" class="form-control" placeholder="@translator.Translate(userLanguage,"Future Odometer Reading")" value="@(isNew ? "" : Model.Mileage)">
|
<input type="number" inputmode="numeric" id="reminderMileage" class="form-control" placeholder="@translator.Translate(userLanguage,"Future Odometer Reading")" value="@(isNew ? "" : Model.Mileage)">
|
||||||
<div class="input-group-text">
|
<div class="input-group-text">
|
||||||
<button type="button" class="btn btn-sm btn-primary" onclick="appendMileageToOdometer(500)">+500</button>
|
<button type="button" class="btn btn-sm btn-primary zero-y-padding" onclick="appendMileageToOdometer(500)">+500</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-check form-check-inline">
|
<div class="form-check form-check-inline">
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
@foreach (ReminderRecordViewModel reminderRecord in Model)
|
@foreach (ReminderRecordViewModel reminderRecord in Model)
|
||||||
{
|
{
|
||||||
<tr class="d-flex" style="cursor:pointer;" onclick="showEditReminderRecordModal(@reminderRecord.Id)">
|
<tr class="d-flex user-select-none" style="cursor:pointer;" ontouchstart="detectRowLongTouch(this)" ontouchend="detectRowTouchEndPremature(this)" data-rowId="@reminderRecord.Id" oncontextmenu="showTableContextMenu(this)" onmousemove="rangeMouseMove(this)" onclick="handleTableRowClick(this, showEditReminderRecordModal,@reminderRecord.Id)">
|
||||||
@if (reminderRecord.Urgency == ReminderUrgency.VeryUrgent)
|
@if (reminderRecord.Urgency == ReminderUrgency.VeryUrgent)
|
||||||
{
|
{
|
||||||
<td class="col-1"><span class="badge text-bg-danger">@translator.Translate(userLanguage, "Very Urgent")</span></td>
|
<td class="col-1"><span class="badge text-bg-danger">@translator.Translate(userLanguage, "Very Urgent")</span></td>
|
||||||
@@ -99,4 +99,12 @@
|
|||||||
<div class="modal-content" id="planRecordModalContent">
|
<div class="modal-content" id="planRecordModalContent">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<ul class="table-context-menu dropdown-menu" style="display:none;">
|
||||||
|
<li><a class="context-menu-multiple context-menu-select-all dropdown-item" href="#" onclick="selectAllRows()">@translator.Translate(userLanguage, "Select All")</a></li>
|
||||||
|
<li><a class="context-menu-multiple context-menu-deselect-all dropdown-item" href="#" onclick="clearSelectedRows()">@translator.Translate(userLanguage, "Deselect All")</a></li>
|
||||||
|
<li><hr class="context-menu-multiple dropdown-divider"></li>
|
||||||
|
<li><a class="dropdown-item" href="#" onclick="duplicateRecords(selectedRow, 'ReminderRecord')">@translator.Translate(userLanguage, "Duplicate")</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#" onclick="deleteRecords(selectedRow, 'ReminderRecord')">@translator.Translate(userLanguage, "Delete")</a></li>
|
||||||
|
</ul>
|
||||||
@@ -26,6 +26,14 @@
|
|||||||
<input type="number" inputmode="numeric" id="serviceRecordMileage" class="form-control" placeholder="@translator.Translate(userLanguage,"Odometer reading when serviced")" value="@(isNew ? "" : Model.Mileage)">
|
<input type="number" inputmode="numeric" id="serviceRecordMileage" class="form-control" placeholder="@translator.Translate(userLanguage,"Odometer reading when serviced")" value="@(isNew ? "" : Model.Mileage)">
|
||||||
<label for="serviceRecordDescription">@translator.Translate(userLanguage,"Description")</label>
|
<label for="serviceRecordDescription">@translator.Translate(userLanguage,"Description")</label>
|
||||||
<input type="text" id="serviceRecordDescription" class="form-control" placeholder="@translator.Translate(userLanguage,"Description of item(s) serviced(i.e. Oil Change)")" value="@Model.Description">
|
<input type="text" id="serviceRecordDescription" class="form-control" placeholder="@translator.Translate(userLanguage,"Description of item(s) serviced(i.e. Oil Change)")" value="@Model.Description">
|
||||||
|
@if (isNew)
|
||||||
|
{
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<a onclick="showRecurringReminderSelector('serviceRecordDescription')" class="btn btn-link">@translator.Translate(userLanguage, "Select Reminder")</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
<label for="serviceRecordCost">@translator.Translate(userLanguage,"Cost")</label>
|
<label for="serviceRecordCost">@translator.Translate(userLanguage,"Cost")</label>
|
||||||
<input type="text" inputmode="decimal" id="serviceRecordCost" class="form-control" placeholder="@translator.Translate(userLanguage,"Cost of the service")" value="@(isNew ? "" : Model.Cost)">
|
<input type="text" inputmode="decimal" id="serviceRecordCost" class="form-control" placeholder="@translator.Translate(userLanguage,"Cost of the service")" value="@(isNew ? "" : Model.Cost)">
|
||||||
@if (isNew)
|
@if (isNew)
|
||||||
@@ -113,6 +121,7 @@
|
|||||||
<script>
|
<script>
|
||||||
var uploadedFiles = [];
|
var uploadedFiles = [];
|
||||||
var selectedSupplies = [];
|
var selectedSupplies = [];
|
||||||
|
var recurringReminderRecordId = 0;
|
||||||
getUploadedFilesFromModel();
|
getUploadedFilesFromModel();
|
||||||
function getUploadedFilesFromModel() {
|
function getUploadedFilesFromModel() {
|
||||||
@foreach (UploadedFiles filesUploaded in Model.Files)
|
@foreach (UploadedFiles filesUploaded in Model.Files)
|
||||||
|
|||||||
@@ -68,7 +68,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
@foreach (ServiceRecord serviceRecord in Model)
|
@foreach (ServiceRecord serviceRecord in Model)
|
||||||
{
|
{
|
||||||
<tr class="d-flex" style="cursor:pointer;" onclick="showEditServiceRecordModal(@serviceRecord.Id)" data-tags='@string.Join(" ",serviceRecord.Tags)'>
|
<tr class="d-flex user-select-none" style="cursor:pointer;" ontouchstart="detectRowLongTouch(this)" ontouchend="detectRowTouchEndPremature(this)" data-rowId="@serviceRecord.Id" oncontextmenu="showTableContextMenu(this)" onmousemove="rangeMouseMove(this)" onclick="handleTableRowClick(this, showEditServiceRecordModal,@serviceRecord.Id)" data-tags='@string.Join(" ", serviceRecord.Tags)'>
|
||||||
<td class="col-2 col-xl-1">@serviceRecord.Date.ToShortDateString()</td>
|
<td class="col-2 col-xl-1">@serviceRecord.Date.ToShortDateString()</td>
|
||||||
<td class="col-2">@serviceRecord.Mileage</td>
|
<td class="col-2">@serviceRecord.Mileage</td>
|
||||||
<td class="col-3 col-xl-4">@serviceRecord.Description</td>
|
<td class="col-3 col-xl-4">@serviceRecord.Description</td>
|
||||||
@@ -88,4 +88,17 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<ul class="table-context-menu dropdown-menu" style="display:none;">
|
||||||
|
<li><a class="context-menu-multiple context-menu-select-all dropdown-item" href="#" onclick="selectAllRows()">@translator.Translate(userLanguage, "Select All")</a></li>
|
||||||
|
<li><a class="context-menu-multiple context-menu-deselect-all dropdown-item" href="#" onclick="clearSelectedRows()">@translator.Translate(userLanguage, "Deselect All")</a></li>
|
||||||
|
<li><a class="context-menu-active-multiple dropdown-item" href="#" onclick="editMultipleRecords(selectedRow, 'ServiceRecord')">@translator.Translate(userLanguage, "Edit Multiple")</a></li>
|
||||||
|
<li><hr class="context-menu-multiple dropdown-divider"></li>
|
||||||
|
<li><h6 class="dropdown-header">@translator.Translate(userLanguage, "Move To")</h6></li>
|
||||||
|
<li><a class="dropdown-item" href="#" onclick="moveRecords(selectedRow, 'ServiceRecord', 'RepairRecord')">@translator.Translate(userLanguage, "Repairs")</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#" onclick="moveRecords(selectedRow, 'ServiceRecord', 'UpgradeRecord')">@translator.Translate(userLanguage, "Upgrades")</a></li>
|
||||||
|
<li><hr class="dropdown-divider"></li>
|
||||||
|
<li><a class="dropdown-item" href="#" onclick="duplicateRecords(selectedRow, 'ServiceRecord')">@translator.Translate(userLanguage, "Duplicate")</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#" onclick="deleteRecords(selectedRow, 'ServiceRecord')">@translator.Translate(userLanguage, "Delete")</a></li>
|
||||||
|
</ul>
|
||||||
@@ -31,7 +31,12 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6 col-12">
|
<div class="col-md-6 col-12">
|
||||||
<label for="supplyRecordQuantity">@translator.Translate(userLanguage,"Quantity")</label>
|
<label for="supplyRecordQuantity">@translator.Translate(userLanguage,"Quantity")</label>
|
||||||
<input type="text" inputmode="decimal" id="supplyRecordQuantity" class="form-control" placeholder="@translator.Translate(userLanguage,"Quantity")" value="@(isNew ? "1" : Model.Quantity)">
|
<div class="input-group">
|
||||||
|
<input type="text" inputmode="decimal" id="supplyRecordQuantity" class="form-control" placeholder="@translator.Translate(userLanguage,"Quantity")" value="@(isNew ? "1" : Model.Quantity)">
|
||||||
|
<div class="input-group-text">
|
||||||
|
<button type="button" class="btn btn-sm zero-y-padding btn-primary" onclick="replenishSupplies()">+</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 col-12">
|
<div class="col-md-6 col-12">
|
||||||
<label for="supplyRecordCost">@translator.Translate(userLanguage,"Cost")</label>
|
<label for="supplyRecordCost">@translator.Translate(userLanguage,"Cost")</label>
|
||||||
|
|||||||
@@ -70,7 +70,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
@foreach (SupplyRecord supplyRecord in Model)
|
@foreach (SupplyRecord supplyRecord in Model)
|
||||||
{
|
{
|
||||||
<tr class="d-flex" style="cursor:pointer;" onclick="showEditSupplyRecordModal(@supplyRecord.Id)" data-tags='@string.Join(" ", supplyRecord.Tags)'>
|
<tr class="d-flex user-select-none" style="cursor:pointer;" ontouchstart="detectRowLongTouch(this)" ontouchend="detectRowTouchEndPremature(this)" data-rowId="@supplyRecord.Id" oncontextmenu="showTableContextMenu(this)" onmousemove="rangeMouseMove(this)" onclick="handleTableRowClick(this, showEditSupplyRecordModal,@supplyRecord.Id)" data-tags='@string.Join(" ", supplyRecord.Tags)'>
|
||||||
<td class="col-2 col-xl-1">@supplyRecord.Date.ToShortDateString()</td>
|
<td class="col-2 col-xl-1">@supplyRecord.Date.ToShortDateString()</td>
|
||||||
<td class="col-2">@supplyRecord.PartNumber</td>
|
<td class="col-2">@supplyRecord.PartNumber</td>
|
||||||
<td class="col-2">@supplyRecord.PartSupplier</td>
|
<td class="col-2">@supplyRecord.PartSupplier</td>
|
||||||
@@ -91,4 +91,12 @@
|
|||||||
<div class="modal-content" id="supplyRecordModalContent">
|
<div class="modal-content" id="supplyRecordModalContent">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<ul class="table-context-menu dropdown-menu" style="display:none;">
|
||||||
|
<li><a class="context-menu-multiple context-menu-select-all dropdown-item" href="#" onclick="selectAllRows()">@translator.Translate(userLanguage, "Select All")</a></li>
|
||||||
|
<li><a class="context-menu-multiple context-menu-deselect-all dropdown-item" href="#" onclick="clearSelectedRows()">@translator.Translate(userLanguage, "Deselect All")</a></li>
|
||||||
|
<li><hr class="context-menu-multiple dropdown-divider"></li>
|
||||||
|
<li><a class="dropdown-item" href="#" onclick="duplicateRecords(selectedRow, 'SupplyRecord')">@translator.Translate(userLanguage, "Duplicate")</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#" onclick="deleteRecords(selectedRow, 'SupplyRecord')">@translator.Translate(userLanguage, "Delete")</a></li>
|
||||||
|
</ul>
|
||||||
@@ -24,6 +24,14 @@
|
|||||||
</div>
|
</div>
|
||||||
<label for="taxRecordDescription">@translator.Translate(userLanguage,"Description")</label>
|
<label for="taxRecordDescription">@translator.Translate(userLanguage,"Description")</label>
|
||||||
<input type="text" id="taxRecordDescription" class="form-control" placeholder="@translator.Translate(userLanguage,"Description of tax paid(i.e. Registration)")" value="@Model.Description">
|
<input type="text" id="taxRecordDescription" class="form-control" placeholder="@translator.Translate(userLanguage,"Description of tax paid(i.e. Registration)")" value="@Model.Description">
|
||||||
|
@if (isNew)
|
||||||
|
{
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<a onclick="showRecurringReminderSelector('taxRecordDescription')" class="btn btn-link">@translator.Translate(userLanguage, "Select Reminder")</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
<label for="taxRecordCost">@translator.Translate(userLanguage,"Cost")</label>
|
<label for="taxRecordCost">@translator.Translate(userLanguage,"Cost")</label>
|
||||||
<input type="text" inputmode="decimal" id="taxRecordCost" class="form-control" placeholder="@translator.Translate(userLanguage,"Cost of tax paid")" value="@(isNew? "" : Model.Cost)">
|
<input type="text" inputmode="decimal" id="taxRecordCost" class="form-control" placeholder="@translator.Translate(userLanguage,"Cost of tax paid")" value="@(isNew? "" : Model.Cost)">
|
||||||
<label for="taxRecordTag">@translator.Translate(userLanguage,"Tags(optional)")</label>
|
<label for="taxRecordTag">@translator.Translate(userLanguage,"Tags(optional)")</label>
|
||||||
@@ -107,6 +115,7 @@
|
|||||||
<script>
|
<script>
|
||||||
var uploadedFiles = [];
|
var uploadedFiles = [];
|
||||||
var customMonthInterval = @Model.CustomMonthInterval;
|
var customMonthInterval = @Model.CustomMonthInterval;
|
||||||
|
var recurringReminderRecordId = 0;
|
||||||
getUploadedFilesFromModel();
|
getUploadedFilesFromModel();
|
||||||
function getUploadedFilesFromModel() {
|
function getUploadedFilesFromModel() {
|
||||||
@foreach (UploadedFiles filesUploaded in Model.Files)
|
@foreach (UploadedFiles filesUploaded in Model.Files)
|
||||||
|
|||||||
@@ -67,7 +67,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
@foreach (TaxRecord taxRecord in Model)
|
@foreach (TaxRecord taxRecord in Model)
|
||||||
{
|
{
|
||||||
<tr class="d-flex" style="cursor:pointer;" onclick="showEditTaxRecordModal(@taxRecord.Id)" data-tags='@string.Join(" ", taxRecord.Tags)'>
|
<tr class="d-flex user-select-none" style="cursor:pointer;" ontouchstart="detectRowLongTouch(this)" ontouchend="detectRowTouchEndPremature(this)" data-rowId="@taxRecord.Id" oncontextmenu="showTableContextMenu(this)" onmousemove="rangeMouseMove(this)" onclick="handleTableRowClick(this, showEditTaxRecordModal,@taxRecord.Id)" data-tags='@string.Join(" ", taxRecord.Tags)'>
|
||||||
<td class="col-3 col-xl-1">@taxRecord.Date.ToShortDateString()</td>
|
<td class="col-3 col-xl-1">@taxRecord.Date.ToShortDateString()</td>
|
||||||
<td class="col-4 col-xl-6">@taxRecord.Description</td>
|
<td class="col-4 col-xl-6">@taxRecord.Description</td>
|
||||||
<td class="col-2" data-record-type="cost">@((hideZero && taxRecord.Cost == default) ? "---" : taxRecord.Cost.ToString("C"))</td>
|
<td class="col-2" data-record-type="cost">@((hideZero && taxRecord.Cost == default) ? "---" : taxRecord.Cost.ToString("C"))</td>
|
||||||
@@ -85,4 +85,12 @@
|
|||||||
<div class="modal-content" id="taxRecordModalContent">
|
<div class="modal-content" id="taxRecordModalContent">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<ul class="table-context-menu dropdown-menu" style="display:none;">
|
||||||
|
<li><a class="context-menu-multiple context-menu-select-all dropdown-item" href="#" onclick="selectAllRows()">@translator.Translate(userLanguage, "Select All")</a></li>
|
||||||
|
<li><a class="context-menu-multiple context-menu-deselect-all dropdown-item" href="#" onclick="clearSelectedRows()">@translator.Translate(userLanguage, "Deselect All")</a></li>
|
||||||
|
<li><hr class="context-menu-multiple dropdown-divider"></li>
|
||||||
|
<li><a class="dropdown-item" href="#" onclick="duplicateRecords(selectedRow, 'TaxRecord')">@translator.Translate(userLanguage, "Duplicate")</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#" onclick="deleteRecords(selectedRow, 'TaxRecord')">@translator.Translate(userLanguage, "Delete")</a></li>
|
||||||
|
</ul>
|
||||||
@@ -26,6 +26,14 @@
|
|||||||
<input type="number" inputmode="numeric" id="upgradeRecordMileage" class="form-control" placeholder="@translator.Translate(userLanguage,"Odometer reading when upgraded/modded")" value="@(isNew ? "" : Model.Mileage)">
|
<input type="number" inputmode="numeric" id="upgradeRecordMileage" class="form-control" placeholder="@translator.Translate(userLanguage,"Odometer reading when upgraded/modded")" value="@(isNew ? "" : Model.Mileage)">
|
||||||
<label for="upgradeRecordDescription">@translator.Translate(userLanguage,"Description")</label>
|
<label for="upgradeRecordDescription">@translator.Translate(userLanguage,"Description")</label>
|
||||||
<input type="text" id="upgradeRecordDescription" class="form-control" placeholder="@translator.Translate(userLanguage,"Description of item(s) upgraded/modded")" value="@Model.Description">
|
<input type="text" id="upgradeRecordDescription" class="form-control" placeholder="@translator.Translate(userLanguage,"Description of item(s) upgraded/modded")" value="@Model.Description">
|
||||||
|
@if (isNew)
|
||||||
|
{
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<a onclick="showRecurringReminderSelector('upgradeRecordDescription')" class="btn btn-link">@translator.Translate(userLanguage, "Select Reminder")</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
<label for="upgradeRecordCost">@translator.Translate(userLanguage,"Cost")</label>
|
<label for="upgradeRecordCost">@translator.Translate(userLanguage,"Cost")</label>
|
||||||
<input type="text" inputmode="decimal" id="upgradeRecordCost" class="form-control" placeholder="@translator.Translate(userLanguage,"Cost of the upgrade/mods")" value="@(isNew ? "" : Model.Cost)">
|
<input type="text" inputmode="decimal" id="upgradeRecordCost" class="form-control" placeholder="@translator.Translate(userLanguage,"Cost of the upgrade/mods")" value="@(isNew ? "" : Model.Cost)">
|
||||||
@if (isNew)
|
@if (isNew)
|
||||||
@@ -113,6 +121,7 @@
|
|||||||
<script>
|
<script>
|
||||||
var uploadedFiles = [];
|
var uploadedFiles = [];
|
||||||
var selectedSupplies = [];
|
var selectedSupplies = [];
|
||||||
|
var recurringReminderRecordId = 0;
|
||||||
getUploadedFilesFromModel();
|
getUploadedFilesFromModel();
|
||||||
function getUploadedFilesFromModel() {
|
function getUploadedFilesFromModel() {
|
||||||
@foreach (UploadedFiles filesUploaded in Model.Files)
|
@foreach (UploadedFiles filesUploaded in Model.Files)
|
||||||
|
|||||||
@@ -68,7 +68,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
@foreach (UpgradeRecord upgradeRecord in Model)
|
@foreach (UpgradeRecord upgradeRecord in Model)
|
||||||
{
|
{
|
||||||
<tr class="d-flex" style="cursor:pointer;" onclick="showEditUpgradeRecordModal(@upgradeRecord.Id)" data-tags='@string.Join(" ", upgradeRecord.Tags)'>
|
<tr class="d-flex user-select-none" style="cursor:pointer;" ontouchstart="detectRowLongTouch(this)" ontouchend="detectRowTouchEndPremature(this)" data-rowId="@upgradeRecord.Id" oncontextmenu="showTableContextMenu(this)" onmousemove="rangeMouseMove(this)" onclick="handleTableRowClick(this, showEditUpgradeRecordModal,@upgradeRecord.Id)" data-tags='@string.Join(" ", upgradeRecord.Tags)'>
|
||||||
<td class="col-2 col-xl-1">@upgradeRecord.Date.ToShortDateString()</td>
|
<td class="col-2 col-xl-1">@upgradeRecord.Date.ToShortDateString()</td>
|
||||||
<td class="col-2">@upgradeRecord.Mileage</td>
|
<td class="col-2">@upgradeRecord.Mileage</td>
|
||||||
<td class="col-3 col-xl-4">@upgradeRecord.Description</td>
|
<td class="col-3 col-xl-4">@upgradeRecord.Description</td>
|
||||||
@@ -86,4 +86,17 @@
|
|||||||
<div class="modal-content" id="upgradeRecordModalContent">
|
<div class="modal-content" id="upgradeRecordModalContent">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<ul class="table-context-menu dropdown-menu" style="display:none;">
|
||||||
|
<li><a class="context-menu-multiple context-menu-select-all dropdown-item" href="#" onclick="selectAllRows()">@translator.Translate(userLanguage, "Select All")</a></li>
|
||||||
|
<li><a class="context-menu-multiple context-menu-deselect-all dropdown-item" href="#" onclick="clearSelectedRows()">@translator.Translate(userLanguage, "Deselect All")</a></li>
|
||||||
|
<li><a class="context-menu-active-multiple dropdown-item" href="#" onclick="editMultipleRecords(selectedRow, 'UpgradeRecord')">@translator.Translate(userLanguage, "Edit Multiple")</a></li>
|
||||||
|
<li><hr class="context-menu-multiple dropdown-divider"></li>
|
||||||
|
<li><h6 class="dropdown-header">@translator.Translate(userLanguage, "Move To")</h6></li>
|
||||||
|
<li><a class="dropdown-item" href="#" onclick="moveRecords(selectedRow, 'UpgradeRecord', 'ServiceRecord')">@translator.Translate(userLanguage, "Service Records")</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#" onclick="moveRecords(selectedRow, 'UpgradeRecord', 'RepairRecord')">@translator.Translate(userLanguage, "Repairs")</a></li>
|
||||||
|
<li><hr class="dropdown-divider"></li>
|
||||||
|
<li><a class="dropdown-item" href="#" onclick="duplicateRecords(selectedRow, 'UpgradeRecord')">@translator.Translate(userLanguage, "Duplicate")</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#" onclick="deleteRecords(selectedRow, 'UpgradeRecord')">@translator.Translate(userLanguage, "Delete")</a></li>
|
||||||
|
</ul>
|
||||||
@@ -163,6 +163,31 @@ html {
|
|||||||
transform-origin: top center;
|
transform-origin: top center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tablerow-shake {
|
||||||
|
animation: tablerowshake 1.2s cubic-bezier(.36, .07, .19, .97) both;
|
||||||
|
backface-visibility: hidden;
|
||||||
|
transform: translate3d(0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes tablerowshake {
|
||||||
|
|
||||||
|
10%, 90% {
|
||||||
|
transform: translate3d(-1px, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
20%, 80% {
|
||||||
|
transform: translate3d(2px, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
30%, 50%, 70% {
|
||||||
|
transform: translate3d(-4px, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
40%, 60% {
|
||||||
|
transform: translate3d(4px, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes bellshake {
|
@keyframes bellshake {
|
||||||
0% {
|
0% {
|
||||||
transform: rotate(0);
|
transform: rotate(0);
|
||||||
@@ -270,6 +295,10 @@ html {
|
|||||||
z-index: 1030;
|
z-index: 1030;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.table-context-menu {
|
||||||
|
z-index: 1030;
|
||||||
|
}
|
||||||
|
|
||||||
input[type="file"] {
|
input[type="file"] {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
@@ -325,4 +354,8 @@ input[type="file"] {
|
|||||||
}
|
}
|
||||||
.reminder-calendar-item{
|
.reminder-calendar-item{
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.zero-y-padding{
|
||||||
|
padding-top: 0rem;
|
||||||
|
padding-bottom: 0rem;
|
||||||
}
|
}
|
||||||
File diff suppressed because one or more lines are too long
@@ -130,6 +130,7 @@ function getAndValidateCollisionRecordValues() {
|
|||||||
tags: collisionTags,
|
tags: collisionTags,
|
||||||
addReminderRecord: addReminderRecord,
|
addReminderRecord: addReminderRecord,
|
||||||
extraFields: extraFields.extraFields,
|
extraFields: extraFields.extraFields,
|
||||||
requisitionHistory: supplyUsageHistory
|
requisitionHistory: supplyUsageHistory,
|
||||||
|
reminderRecordId: recurringReminderRecordId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -100,4 +100,12 @@ function getAndValidateNoteValues() {
|
|||||||
pinned: noteIsPinned,
|
pinned: noteIsPinned,
|
||||||
tags: noteTags
|
tags: noteTags
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
function pinNotes(ids, toggle, pinStatus) {
|
||||||
|
$.post('/Vehicle/PinNotes', { noteIds: ids, isToggle: toggle, pinStatus: pinStatus }, function (data) {
|
||||||
|
if (data) {
|
||||||
|
successToast(ids.length > 1 ? `${ids.length} Notes Updated` : "Note Updated.");
|
||||||
|
getVehicleNotes(GetVehicleId().vehicleId);
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
@@ -130,6 +130,7 @@ function getAndValidateServiceRecordValues() {
|
|||||||
tags: serviceTags,
|
tags: serviceTags,
|
||||||
addReminderRecord: addReminderRecord,
|
addReminderRecord: addReminderRecord,
|
||||||
extraFields: extraFields.extraFields,
|
extraFields: extraFields.extraFields,
|
||||||
requisitionHistory: supplyUsageHistory
|
requisitionHistory: supplyUsageHistory,
|
||||||
|
reminderRecordId: recurringReminderRecordId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -158,7 +158,7 @@ function hideMobileNav() {
|
|||||||
$(".lubelogger-mobile-nav").removeClass("lubelogger-mobile-nav-show");
|
$(".lubelogger-mobile-nav").removeClass("lubelogger-mobile-nav-show");
|
||||||
}
|
}
|
||||||
function bindWindowResize() {
|
function bindWindowResize() {
|
||||||
$(window).resize(function () {
|
$(window).on('resize', function () {
|
||||||
hideMobileNav();
|
hideMobileNav();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -422,4 +422,443 @@ function toggleSupplyUsageHistory() {
|
|||||||
} else {
|
} else {
|
||||||
container.addClass("d-none");
|
container.addClass("d-none");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
function moveRecords(ids, source, dest) {
|
||||||
|
if (ids.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$("#workAroundInput").show();
|
||||||
|
var friendlySource = "";
|
||||||
|
var friendlyDest = "";
|
||||||
|
var refreshDataCallBack;
|
||||||
|
var recordVerbiage = ids.length > 1 ? `these ${ids.length} records` : "this record";
|
||||||
|
switch (source) {
|
||||||
|
case "ServiceRecord":
|
||||||
|
friendlySource = "Service Records";
|
||||||
|
refreshDataCallBack = getVehicleServiceRecords;
|
||||||
|
break;
|
||||||
|
case "RepairRecord":
|
||||||
|
friendlySource = "Repairs";
|
||||||
|
refreshDataCallBack = getVehicleCollisionRecords;
|
||||||
|
break;
|
||||||
|
case "UpgradeRecord":
|
||||||
|
friendlySource = "Upgrades";
|
||||||
|
refreshDataCallBack = getVehicleUpgradeRecords;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (dest) {
|
||||||
|
case "ServiceRecord":
|
||||||
|
friendlyDest = "Service Records";
|
||||||
|
break;
|
||||||
|
case "RepairRecord":
|
||||||
|
friendlyDest = "Repairs";
|
||||||
|
break;
|
||||||
|
case "UpgradeRecord":
|
||||||
|
friendlyDest = "Upgrades";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Swal.fire({
|
||||||
|
title: "Confirm Move?",
|
||||||
|
text: `Move ${recordVerbiage} from ${friendlySource} to ${friendlyDest}?`,
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonText: "Move",
|
||||||
|
confirmButtonColor: "#dc3545"
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
$.post('/Vehicle/MoveRecords', { recordIds: ids, source: source, destination: dest }, function (data) {
|
||||||
|
if (data) {
|
||||||
|
successToast(`${ids.length} Record(s) Moved`);
|
||||||
|
var vehicleId = GetVehicleId().vehicleId;
|
||||||
|
refreshDataCallBack(vehicleId);
|
||||||
|
} else {
|
||||||
|
errorToast(genericErrorMessage());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$("#workAroundInput").hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function deleteRecords(ids, source) {
|
||||||
|
if (ids.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$("#workAroundInput").show();
|
||||||
|
var friendlySource = "";
|
||||||
|
var refreshDataCallBack;
|
||||||
|
var recordVerbiage = ids.length > 1 ? `these ${ids.length} records` : "this record";
|
||||||
|
switch (source) {
|
||||||
|
case "ServiceRecord":
|
||||||
|
friendlySource = "Service Records";
|
||||||
|
refreshDataCallBack = getVehicleServiceRecords;
|
||||||
|
break;
|
||||||
|
case "RepairRecord":
|
||||||
|
friendlySource = "Repairs";
|
||||||
|
refreshDataCallBack = getVehicleCollisionRecords;
|
||||||
|
break;
|
||||||
|
case "UpgradeRecord":
|
||||||
|
friendlySource = "Upgrades";
|
||||||
|
refreshDataCallBack = getVehicleUpgradeRecords;
|
||||||
|
break;
|
||||||
|
case "TaxRecord":
|
||||||
|
friendlySource = "Taxes";
|
||||||
|
refreshDataCallBack = getVehicleTaxRecords;
|
||||||
|
break;
|
||||||
|
case "SupplyRecord":
|
||||||
|
friendlySource = "Supplies";
|
||||||
|
refreshDataCallBack = getVehicleSupplyRecords;
|
||||||
|
break;
|
||||||
|
case "NoteRecord":
|
||||||
|
friendlySource = "Notes";
|
||||||
|
refreshDataCallBack = getVehicleNotes;
|
||||||
|
break;
|
||||||
|
case "OdometerRecord":
|
||||||
|
friendlySource = "Odometer Records";
|
||||||
|
refreshDataCallBack = getVehicleOdometerRecords;
|
||||||
|
break;
|
||||||
|
case "ReminderRecord":
|
||||||
|
friendlySource = "Reminders";
|
||||||
|
refreshDataCallBack = getVehicleReminders;
|
||||||
|
break;
|
||||||
|
case "GasRecord":
|
||||||
|
friendlySource = "Fuel Records";
|
||||||
|
refreshDataCallBack = getVehicleGasRecords;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Swal.fire({
|
||||||
|
title: "Confirm Delete?",
|
||||||
|
text: `Delete ${recordVerbiage} from ${friendlySource}?`,
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonText: "Delete",
|
||||||
|
confirmButtonColor: "#dc3545"
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
$.post('/Vehicle/DeleteRecords', { recordIds: ids, importMode: source }, function (data) {
|
||||||
|
if (data) {
|
||||||
|
successToast(`${ids.length} Record(s) Deleted`);
|
||||||
|
var vehicleId = GetVehicleId().vehicleId;
|
||||||
|
refreshDataCallBack(vehicleId);
|
||||||
|
} else {
|
||||||
|
errorToast(genericErrorMessage());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$("#workAroundInput").hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function duplicateRecords(ids, source) {
|
||||||
|
if (ids.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$("#workAroundInput").show();
|
||||||
|
var friendlySource = "";
|
||||||
|
var refreshDataCallBack;
|
||||||
|
var recordVerbiage = ids.length > 1 ? `these ${ids.length} records` : "this record";
|
||||||
|
switch (source) {
|
||||||
|
case "ServiceRecord":
|
||||||
|
friendlySource = "Service Records";
|
||||||
|
refreshDataCallBack = getVehicleServiceRecords;
|
||||||
|
break;
|
||||||
|
case "RepairRecord":
|
||||||
|
friendlySource = "Repairs";
|
||||||
|
refreshDataCallBack = getVehicleCollisionRecords;
|
||||||
|
break;
|
||||||
|
case "UpgradeRecord":
|
||||||
|
friendlySource = "Upgrades";
|
||||||
|
refreshDataCallBack = getVehicleUpgradeRecords;
|
||||||
|
break;
|
||||||
|
case "TaxRecord":
|
||||||
|
friendlySource = "Taxes";
|
||||||
|
refreshDataCallBack = getVehicleTaxRecords;
|
||||||
|
break;
|
||||||
|
case "SupplyRecord":
|
||||||
|
friendlySource = "Supplies";
|
||||||
|
refreshDataCallBack = getVehicleSupplyRecords;
|
||||||
|
break;
|
||||||
|
case "NoteRecord":
|
||||||
|
friendlySource = "Notes";
|
||||||
|
refreshDataCallBack = getVehicleNotes;
|
||||||
|
break;
|
||||||
|
case "OdometerRecord":
|
||||||
|
friendlySource = "Odometer Records";
|
||||||
|
refreshDataCallBack = getVehicleOdometerRecords;
|
||||||
|
break;
|
||||||
|
case "ReminderRecord":
|
||||||
|
friendlySource = "Reminders";
|
||||||
|
refreshDataCallBack = getVehicleReminders;
|
||||||
|
break;
|
||||||
|
case "GasRecord":
|
||||||
|
friendlySource = "Fuel Records";
|
||||||
|
refreshDataCallBack = getVehicleGasRecords;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Swal.fire({
|
||||||
|
title: "Confirm Duplicate?",
|
||||||
|
text: `Duplicate ${recordVerbiage}?`,
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonText: "Duplicate",
|
||||||
|
confirmButtonColor: "#dc3545"
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
$.post('/Vehicle/DuplicateRecords', { recordIds: ids, importMode: source }, function (data) {
|
||||||
|
if (data) {
|
||||||
|
successToast(`${ids.length} Record(s) Duplicated`);
|
||||||
|
var vehicleId = GetVehicleId().vehicleId;
|
||||||
|
refreshDataCallBack(vehicleId);
|
||||||
|
} else {
|
||||||
|
errorToast(genericErrorMessage());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$("#workAroundInput").hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
var selectedRow = [];
|
||||||
|
var isDragging = false;
|
||||||
|
$(window).on('mouseup', function (e) {
|
||||||
|
rangeMouseUp(e);
|
||||||
|
});
|
||||||
|
$(window).on('mousedown', function (e) {
|
||||||
|
rangeMouseDown(e);
|
||||||
|
});
|
||||||
|
$(window).on('keydown', function (e) {
|
||||||
|
var userOnInput = $(e.target).is("input") || $(e.target).is("textarea");
|
||||||
|
if (!userOnInput) {
|
||||||
|
if (e.ctrlKey && e.which == 65) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
selectAllRows();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
function selectAllRows() {
|
||||||
|
clearSelectedRows();
|
||||||
|
$('.vehicleDetailTabContainer .table tbody tr:visible').addClass('table-active');
|
||||||
|
$('.vehicleDetailTabContainer .table tbody tr:visible').map((index, elem) => {
|
||||||
|
addToSelectedRows($(elem).attr('data-rowId'));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function rangeMouseDown(e) {
|
||||||
|
if (isRightClick(e)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var contextMenuAction = $(e.target).is(".table-context-menu > li > .dropdown-item")
|
||||||
|
if (!e.ctrlKey && !contextMenuAction) {
|
||||||
|
clearSelectedRows();
|
||||||
|
}
|
||||||
|
isDragging = true;
|
||||||
|
|
||||||
|
document.documentElement.onselectstart = function () { return false; };
|
||||||
|
}
|
||||||
|
function isRightClick(e) {
|
||||||
|
if (e.which) {
|
||||||
|
return (e.which == 3);
|
||||||
|
} else if (e.button) {
|
||||||
|
return (e.button == 2);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
function rangeMouseUp(e) {
|
||||||
|
if ($(".table-context-menu").length > 0) {
|
||||||
|
$(".table-context-menu").hide();
|
||||||
|
}
|
||||||
|
if (isRightClick(e)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
isDragging = false;
|
||||||
|
document.documentElement.onselectstart = function () { return true; };
|
||||||
|
}
|
||||||
|
function rangeMouseMove(e) {
|
||||||
|
if (isDragging) {
|
||||||
|
if (!$(e).hasClass('table-active')) {
|
||||||
|
addToSelectedRows($(e).attr('data-rowId'));
|
||||||
|
$(e).addClass('table-active');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function addToSelectedRows(id) {
|
||||||
|
if (selectedRow.findIndex(x => x == id) == -1) {
|
||||||
|
selectedRow.push(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function removeFromSelectedRows(id) {
|
||||||
|
var rowIndex = selectedRow.findIndex(x => x == id)
|
||||||
|
if (rowIndex != -1) {
|
||||||
|
selectedRow.splice(rowIndex, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function clearSelectedRows() {
|
||||||
|
selectedRow = [];
|
||||||
|
$('.table tr').removeClass('table-active');
|
||||||
|
}
|
||||||
|
function getDeviceIsTouchOnly() {
|
||||||
|
if (navigator.maxTouchPoints > 0 && matchMedia('(pointer: coarse)').matches && !matchMedia('(any-pointer: fine)').matches) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function showTableContextMenu(e) {
|
||||||
|
if (event != undefined) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
if (getDeviceIsTouchOnly()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$(".table-context-menu").show();
|
||||||
|
determineContextMenuItems();
|
||||||
|
$(".table-context-menu").css({
|
||||||
|
position: "absolute",
|
||||||
|
left: getMenuPosition(event.clientX, 'width', 'scrollLeft'),
|
||||||
|
top: getMenuPosition(event.clientY, 'height', 'scrollTop')
|
||||||
|
});
|
||||||
|
if (!$(e).hasClass('table-active')) {
|
||||||
|
clearSelectedRows();
|
||||||
|
addToSelectedRows($(e).attr('data-rowId'));
|
||||||
|
$(e).addClass('table-active');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function determineContextMenuItems() {
|
||||||
|
var tableRows = $('.table tbody tr:visible');
|
||||||
|
var tableRowsActive = $('.table tr.table-active');
|
||||||
|
if (tableRowsActive.length == 1) {
|
||||||
|
//only one row selected
|
||||||
|
$(".context-menu-active-single").show();
|
||||||
|
$(".context-menu-active-multiple").hide();
|
||||||
|
} else if (tableRowsActive.length > 1) {
|
||||||
|
//multiple rows selected
|
||||||
|
$(".context-menu-active-single").hide();
|
||||||
|
$(".context-menu-active-multiple").show();
|
||||||
|
} else {
|
||||||
|
//nothing was selected, bug case.
|
||||||
|
$(".context-menu-active-single").hide();
|
||||||
|
$(".context-menu-active-multiple").hide();
|
||||||
|
}
|
||||||
|
if (tableRows.length > 1) {
|
||||||
|
$(".context-menu-multiple").show();
|
||||||
|
if (tableRows.length == tableRowsActive.length) {
|
||||||
|
//all rows are selected, show deselect all button.
|
||||||
|
$(".context-menu-deselect-all").show();
|
||||||
|
$(".context-menu-select-all").hide();
|
||||||
|
} else if (tableRows.length != tableRowsActive.length) {
|
||||||
|
//not all rows are selected, show select all button.
|
||||||
|
$(".context-menu-select-all").show();
|
||||||
|
$(".context-menu-deselect-all").hide();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$(".context-menu-multiple").hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function getMenuPosition(mouse, direction, scrollDir) {
|
||||||
|
var win = $(window)[direction](),
|
||||||
|
scroll = $(window)[scrollDir](),
|
||||||
|
menu = $(".table-context-menu")[direction](),
|
||||||
|
position = mouse + scroll;
|
||||||
|
|
||||||
|
// opening menu would pass the side of the page
|
||||||
|
if (mouse + menu > win && menu < mouse)
|
||||||
|
position -= menu;
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
function handleTableRowClick(e, callBack, rowId) {
|
||||||
|
if (!event.ctrlKey) {
|
||||||
|
callBack(rowId);
|
||||||
|
} else if (!$(e).hasClass('table-active')) {
|
||||||
|
addToSelectedRows($(e).attr('data-rowId'));
|
||||||
|
$(e).addClass('table-active');
|
||||||
|
} else if ($(e).hasClass('table-active')) {
|
||||||
|
removeFromSelectedRows($(e).attr('data-rowId'));
|
||||||
|
$(e).removeClass('table-active');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showTableContextMenuForMobile(e, xPosition, yPosition) {
|
||||||
|
if (!$(e).hasClass('table-active')) {
|
||||||
|
addToSelectedRows($(e).attr('data-rowId'));
|
||||||
|
$(e).addClass('table-active');
|
||||||
|
shakeTableRow(e);
|
||||||
|
} else {
|
||||||
|
$(".table-context-menu").show();
|
||||||
|
determineContextMenuItems();
|
||||||
|
$(".table-context-menu").css({
|
||||||
|
position: "absolute",
|
||||||
|
left: getMenuPosition(xPosition, 'width', 'scrollLeft'),
|
||||||
|
top: getMenuPosition(yPosition, 'height', 'scrollTop')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function shakeTableRow(e) {
|
||||||
|
$(e).addClass('tablerow-shake');
|
||||||
|
setTimeout(function () { $(e).removeClass('tablerow-shake'); }, 1200)
|
||||||
|
}
|
||||||
|
var rowTouchTimer;
|
||||||
|
var rowTouchDuration = 800;
|
||||||
|
function detectRowLongTouch(sender) {
|
||||||
|
var touchX = event.touches[0].clientX;
|
||||||
|
var touchY = event.touches[0].clientY;
|
||||||
|
if (!rowTouchTimer) {
|
||||||
|
rowTouchTimer = setTimeout(function () { showTableContextMenuForMobile(sender, touchX, touchY); detectRowTouchEndPremature(sender); }, rowTouchDuration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function detectRowTouchEndPremature(sender) {
|
||||||
|
if (rowTouchTimer) {
|
||||||
|
clearTimeout(rowTouchTimer);
|
||||||
|
rowTouchTimer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function replenishSupplies() {
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Replenish Supplies',
|
||||||
|
html: `
|
||||||
|
<input type="text" id="inputSupplyAddQuantity" class="swal2-input" placeholder="Quantity">
|
||||||
|
<br />
|
||||||
|
<input type="text" id="inputSupplyAddCost" class="swal2-input" placeholder="Cost">
|
||||||
|
<br />
|
||||||
|
<span class='small'>leave blank to use unit cost calculation</span>
|
||||||
|
`,
|
||||||
|
confirmButtonText: 'Replenish',
|
||||||
|
focusConfirm: false,
|
||||||
|
preConfirm: () => {
|
||||||
|
const replquantity = globalParseFloat($("#inputSupplyAddQuantity").val());
|
||||||
|
const replcost = $("#inputSupplyAddCost").val();
|
||||||
|
const parsedReplCost = globalParseFloat(replcost);
|
||||||
|
var quantitybeforeRepl = globalParseFloat($('#supplyRecordQuantity').val());
|
||||||
|
if (isNaN(replquantity) || (replcost.trim() != '' && isNaN(parsedReplCost))) {
|
||||||
|
Swal.showValidationMessage(`Please enter a valid quantity and cost`);
|
||||||
|
} else if (replcost.trim() == '' && (isNaN(quantitybeforeRepl) || quantitybeforeRepl == 0)){
|
||||||
|
Swal.showValidationMessage(`Unable to use unit cost calculation, please provide cost`);
|
||||||
|
}
|
||||||
|
return { replquantity, replcost, parsedReplCost }
|
||||||
|
},
|
||||||
|
}).then(function (result) {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
var replenishedCost = result.value.replcost;
|
||||||
|
var parsedReplenishedCost = result.value.parsedReplCost;
|
||||||
|
var replenishedQuantity = result.value.replquantity;
|
||||||
|
var currentCost = globalParseFloat($('#supplyRecordCost').val())
|
||||||
|
if (isNaN(currentCost)) {
|
||||||
|
currentCost = 0;
|
||||||
|
}
|
||||||
|
var currentQuantity = globalParseFloat($('#supplyRecordQuantity').val());
|
||||||
|
var newQuantity = currentQuantity + replenishedQuantity;
|
||||||
|
if (replenishedCost.trim() == '') {
|
||||||
|
|
||||||
|
var unitCost = currentCost / currentQuantity;
|
||||||
|
var newCost = newQuantity * unitCost;
|
||||||
|
//set text fields.
|
||||||
|
$('#supplyRecordCost').val(globalFloatToString(newCost.toFixed(3).toString()));
|
||||||
|
$('#supplyRecordQuantity').val(globalFloatToString(newQuantity.toFixed(3).toString()));
|
||||||
|
} else {
|
||||||
|
var newCost = currentCost + parsedReplenishedCost;
|
||||||
|
//set text fields.
|
||||||
|
$('#supplyRecordCost').val(globalFloatToString(newCost.toFixed(3).toString()));
|
||||||
|
$('#supplyRecordQuantity').val(globalFloatToString(newQuantity.toFixed(3).toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
@@ -162,6 +162,7 @@ function getAndValidateTaxRecordValues() {
|
|||||||
tags: taxTags,
|
tags: taxTags,
|
||||||
files: uploadedFiles,
|
files: uploadedFiles,
|
||||||
addReminderRecord: addReminderRecord,
|
addReminderRecord: addReminderRecord,
|
||||||
extraFields: extraFields.extraFields
|
extraFields: extraFields.extraFields,
|
||||||
|
reminderRecordId: recurringReminderRecordId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -130,6 +130,7 @@ function getAndValidateUpgradeRecordValues() {
|
|||||||
tags: upgradeTags,
|
tags: upgradeTags,
|
||||||
addReminderRecord: addReminderRecord,
|
addReminderRecord: addReminderRecord,
|
||||||
extraFields: extraFields.extraFields,
|
extraFields: extraFields.extraFields,
|
||||||
requisitionHistory: supplyUsageHistory
|
requisitionHistory: supplyUsageHistory,
|
||||||
|
reminderRecordId: recurringReminderRecordId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -241,7 +241,7 @@ function deleteVehicle(vehicleId) {
|
|||||||
}
|
}
|
||||||
function showAddReminderModal(reminderModalInput) {
|
function showAddReminderModal(reminderModalInput) {
|
||||||
if (reminderModalInput != undefined) {
|
if (reminderModalInput != undefined) {
|
||||||
$.post('/Vehicle/GetAddReminderRecordPartialView', {reminderModel: reminderModalInput}, function (data) {
|
$.post('/Vehicle/GetAddReminderRecordPartialView', { reminderModel: reminderModalInput }, function (data) {
|
||||||
$("#reminderRecordModalContent").html(data);
|
$("#reminderRecordModalContent").html(data);
|
||||||
initDatePicker($('#reminderDate'), true);
|
initDatePicker($('#reminderDate'), true);
|
||||||
$("#reminderRecordModal").modal("show");
|
$("#reminderRecordModal").modal("show");
|
||||||
@@ -313,7 +313,7 @@ function moveRecord(recordId, source, dest) {
|
|||||||
confirmButtonColor: "#dc3545"
|
confirmButtonColor: "#dc3545"
|
||||||
}).then((result) => {
|
}).then((result) => {
|
||||||
if (result.isConfirmed) {
|
if (result.isConfirmed) {
|
||||||
$.post('/Vehicle/MoveRecord', {recordId: recordId, source: source, destination: dest }, function (data) {
|
$.post('/Vehicle/MoveRecord', { recordId: recordId, source: source, destination: dest }, function (data) {
|
||||||
if (data) {
|
if (data) {
|
||||||
hideModalCallBack();
|
hideModalCallBack();
|
||||||
successToast("Record Moved");
|
successToast("Record Moved");
|
||||||
@@ -327,4 +327,115 @@ function moveRecord(recordId, source, dest) {
|
|||||||
$("#workAroundInput").hide();
|
$("#workAroundInput").hide();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
function showRecurringReminderSelector(descriptionFieldName) {
|
||||||
|
$.get(`/Vehicle/GetRecurringReminderRecordsByVehicleId?vehicleId=${GetVehicleId().vehicleId}`, function (data) {
|
||||||
|
if (data) {
|
||||||
|
//prompt user to select a recurring reminder
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Select Recurring Reminder',
|
||||||
|
html: data,
|
||||||
|
confirmButtonText: 'Select',
|
||||||
|
focusConfirm: false,
|
||||||
|
preConfirm: () => {
|
||||||
|
const selectedRecurringReminder = $("#recurringReminderInput").val();
|
||||||
|
const selectedRecurringReminderText = $("#recurringReminderInput option:selected").text();
|
||||||
|
if (!selectedRecurringReminder || parseInt(selectedRecurringReminder) == 0) {
|
||||||
|
Swal.showValidationMessage(`You must select a recurring reminder`);
|
||||||
|
}
|
||||||
|
return { selectedRecurringReminder, selectedRecurringReminderText }
|
||||||
|
},
|
||||||
|
}).then(function (result) {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
recurringReminderRecordId = result.value.selectedRecurringReminder;
|
||||||
|
var descriptionField = $(`#${descriptionFieldName}`);
|
||||||
|
if (descriptionField.length > 0) {
|
||||||
|
descriptionField.val(result.value.selectedRecurringReminderText.trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
errorToast(genericErrorMessage());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function editMultipleRecords(ids, dataType) {
|
||||||
|
$.post('/Vehicle/GetGenericRecordModal', { recordIds: ids, dataType: dataType }, function (data) {
|
||||||
|
if (data) {
|
||||||
|
$("#genericRecordEditModalContent").html(data);
|
||||||
|
initDatePicker($('#genericRecordDate'));
|
||||||
|
initTagSelector($("#genericRecordTag"));
|
||||||
|
$("#genericRecordEditModal").modal('show');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function hideGenericRecordModal() {
|
||||||
|
$("#genericRecordEditModal").modal('hide');
|
||||||
|
}
|
||||||
|
function saveGenericRecord() {
|
||||||
|
//get values
|
||||||
|
var formValues = getAndValidateGenericRecordValues();
|
||||||
|
//validate
|
||||||
|
if (formValues.hasError) {
|
||||||
|
errorToast("Please check the form data");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var refreshDataCallBack;
|
||||||
|
switch (formValues.dataType) {
|
||||||
|
case "ServiceRecord":
|
||||||
|
refreshDataCallBack = getVehicleServiceRecords;
|
||||||
|
break;
|
||||||
|
case "RepairRecord":
|
||||||
|
refreshDataCallBack = getVehicleCollisionRecords;
|
||||||
|
break;
|
||||||
|
case "UpgradeRecord":
|
||||||
|
refreshDataCallBack = getVehicleUpgradeRecords;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//save to db.
|
||||||
|
$.post('/Vehicle/EditMultipleRecords', { genericRecordEditModel: formValues }, function (data) {
|
||||||
|
if (data) {
|
||||||
|
successToast(formValues.recordIds.length > 1 ? "Records Updated" : "Record Updated.");
|
||||||
|
hideGenericRecordModal();
|
||||||
|
refreshDataCallBack(GetVehicleId().vehicleId);
|
||||||
|
} else {
|
||||||
|
errorToast(genericErrorMessage());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function getAndValidateGenericRecordValues() {
|
||||||
|
var genericDate = $("#genericRecordDate").val();
|
||||||
|
var genericMileage = $("#genericRecordMileage").val();
|
||||||
|
var genericMileageToParse = parseInt(globalParseFloat($("#genericRecordMileage").val())).toString();
|
||||||
|
var genericDescription = $("#genericRecordDescription").val();
|
||||||
|
var genericCost = $("#genericRecordCost").val();
|
||||||
|
var genericNotes = $("#genericRecordNotes").val();
|
||||||
|
var genericTags = $("#genericRecordTag").val();
|
||||||
|
//validation
|
||||||
|
var hasError = false;
|
||||||
|
if (genericMileage.trim() != '' && (isNaN(genericMileageToParse) || parseInt(genericMileageToParse) < 0)) {
|
||||||
|
hasError = true;
|
||||||
|
$("#genericRecordMileage").addClass("is-invalid");
|
||||||
|
} else {
|
||||||
|
$("#genericRecordMileage").removeClass("is-invalid");
|
||||||
|
}
|
||||||
|
if (genericCost.trim() != '' && !isValidMoney(genericCost)) {
|
||||||
|
hasError = true;
|
||||||
|
$("#genericRecordCost").addClass("is-invalid");
|
||||||
|
} else {
|
||||||
|
$("#genericRecordCost").removeClass("is-invalid");
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
hasError: hasError,
|
||||||
|
dataType: getGenericRecordEditModelData().dataType,
|
||||||
|
recordIds: recordsToEdit,
|
||||||
|
editRecord: {
|
||||||
|
date: genericDate,
|
||||||
|
mileage: genericMileageToParse,
|
||||||
|
description: genericDescription,
|
||||||
|
cost: genericCost,
|
||||||
|
notes: genericNotes,
|
||||||
|
tags: genericTags
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user