Merge pull request #224 from hargata/Hargata/translation.helper

UI Translation
This commit is contained in:
Hargata Softworks
2024-02-04 10:55:09 -07:00
committed by GitHub
50 changed files with 1011 additions and 629 deletions

1
.gitignore vendored
View File

@@ -7,3 +7,4 @@ data/cartracker.db
wwwroot/documents/ wwwroot/documents/
wwwroot/temp/ wwwroot/temp/
wwwroot/imports/ wwwroot/imports/
wwwroot/translations/

View File

@@ -33,6 +33,26 @@ namespace CarCareTracker.Controllers
return Json(fileName); return Json(fileName);
} }
[HttpPost]
public IActionResult HandleTranslationFileUpload(IFormFile file)
{
var originalFileName = Path.GetFileNameWithoutExtension(file.FileName);
if (originalFileName == "en_US")
{
return Json(new OperationResponse { Success = false, Message = "The translation file name en_US is reserved." });
}
var fileName = UploadFile(file);
//move file from temp to translation folder.
var uploadedFilePath = _fileHelper.MoveFileFromTemp(fileName, "translations/");
//rename uploaded file so that it preserves original name.
if (!string.IsNullOrWhiteSpace(uploadedFilePath))
{
var result = _fileHelper.RenameFile(uploadedFilePath, originalFileName);
return Json(new OperationResponse { Success = result, Message = string.Empty });
}
return Json(new OperationResponse { Success = false, Message = StaticHelper.GenericErrorMessage });
}
[HttpPost] [HttpPost]
public IActionResult HandleMultipleFileUpload(List<IFormFile> file) public IActionResult HandleMultipleFileUpload(List<IFormFile> file)
{ {
@@ -44,7 +64,7 @@ namespace CarCareTracker.Controllers
} }
return Json(uploadedFiles); return Json(uploadedFiles);
} }
[Authorize(Roles = nameof(UserData.IsRootUser))]
[HttpPost] [HttpPost]
public IActionResult DeleteFiles(string fileLocation) public IActionResult DeleteFiles(string fileLocation)
{ {

View File

@@ -15,17 +15,20 @@ namespace CarCareTracker.Controllers
private readonly ILogger<HomeController> _logger; private readonly ILogger<HomeController> _logger;
private readonly IVehicleDataAccess _dataAccess; private readonly IVehicleDataAccess _dataAccess;
private readonly IUserLogic _userLogic; private readonly IUserLogic _userLogic;
private readonly IFileHelper _fileHelper;
private readonly IConfigHelper _config; private readonly IConfigHelper _config;
public HomeController(ILogger<HomeController> logger, public HomeController(ILogger<HomeController> logger,
IVehicleDataAccess dataAccess, IVehicleDataAccess dataAccess,
IUserLogic userLogic, IUserLogic userLogic,
IConfigHelper configuration) IConfigHelper configuration,
IFileHelper fileHelper)
{ {
_logger = logger; _logger = logger;
_dataAccess = dataAccess; _dataAccess = dataAccess;
_config = configuration; _config = configuration;
_userLogic = userLogic; _userLogic = userLogic;
_fileHelper = fileHelper;
} }
private int GetUserID() private int GetUserID()
{ {
@@ -47,7 +50,13 @@ namespace CarCareTracker.Controllers
public IActionResult Settings() public IActionResult Settings()
{ {
var userConfig = _config.GetUserConfig(User); var userConfig = _config.GetUserConfig(User);
return PartialView("_Settings", userConfig); var languages = _fileHelper.GetLanguages();
var viewModel = new SettingsViewModel
{
UserConfig = userConfig,
UILanguages = languages
};
return PartialView("_Settings", viewModel);
} }
[HttpPost] [HttpPost]
public IActionResult WriteToSettings(UserConfig userConfig) public IActionResult WriteToSettings(UserConfig userConfig)

View File

@@ -110,6 +110,7 @@ namespace CarCareTracker.Helper
EnableAutoOdometerInsert = bool.Parse(_config[nameof(UserConfig.EnableAutoOdometerInsert)]), EnableAutoOdometerInsert = bool.Parse(_config[nameof(UserConfig.EnableAutoOdometerInsert)]),
PreferredGasMileageUnit = _config[nameof(UserConfig.PreferredGasMileageUnit)], PreferredGasMileageUnit = _config[nameof(UserConfig.PreferredGasMileageUnit)],
PreferredGasUnit = _config[nameof(UserConfig.PreferredGasUnit)], PreferredGasUnit = _config[nameof(UserConfig.PreferredGasUnit)],
UserLanguage = _config[nameof(UserConfig.UserLanguage)],
VisibleTabs = _config.GetSection("VisibleTabs").Get<List<ImportMode>>(), VisibleTabs = _config.GetSection("VisibleTabs").Get<List<ImportMode>>(),
DefaultTab = (ImportMode)int.Parse(_config[nameof(UserConfig.DefaultTab)]) DefaultTab = (ImportMode)int.Parse(_config[nameof(UserConfig.DefaultTab)])
}; };

View File

@@ -7,10 +7,12 @@ namespace CarCareTracker.Helper
{ {
string GetFullFilePath(string currentFilePath, bool mustExist = true); string GetFullFilePath(string currentFilePath, bool mustExist = true);
string MoveFileFromTemp(string currentFilePath, string newFolder); string MoveFileFromTemp(string currentFilePath, string newFolder);
bool RenameFile(string currentFilePath, string newName);
bool DeleteFile(string currentFilePath); bool DeleteFile(string currentFilePath);
string MakeBackup(); string MakeBackup();
bool RestoreBackup(string fileName, bool clearExisting = false); bool RestoreBackup(string fileName, bool clearExisting = false);
string MakeAttachmentsExport(List<GenericReportModel> exportData); string MakeAttachmentsExport(List<GenericReportModel> exportData);
List<string> GetLanguages();
} }
public class FileHelper : IFileHelper public class FileHelper : IFileHelper
{ {
@@ -21,6 +23,40 @@ namespace CarCareTracker.Helper
_webEnv = webEnv; _webEnv = webEnv;
_logger = logger; _logger = logger;
} }
public List<string> GetLanguages()
{
var languagePath = Path.Combine(_webEnv.WebRootPath, "translations");
var defaultList = new List<string>() { "en_US" };
if (Directory.Exists(languagePath))
{
var listOfLanguages = Directory.GetFiles(languagePath);
if (listOfLanguages.Any())
{
defaultList.AddRange(listOfLanguages.Select(x => Path.GetFileNameWithoutExtension(x)));
}
}
return defaultList;
}
public bool RenameFile(string currentFilePath, string newName)
{
var fullFilePath = GetFullFilePath(currentFilePath);
if (!string.IsNullOrWhiteSpace(fullFilePath))
{
try
{
var originalFileName = Path.GetFileNameWithoutExtension(fullFilePath);
var newFilePath = fullFilePath.Replace(originalFileName, newName);
File.Move(fullFilePath, newFilePath);
return true;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
return false;
}
public string GetFullFilePath(string currentFilePath, bool mustExist = true) public string GetFullFilePath(string currentFilePath, bool mustExist = true)
{ {
if (currentFilePath.StartsWith("/")) if (currentFilePath.StartsWith("/"))
@@ -132,9 +168,9 @@ namespace CarCareTracker.Helper
if (!Directory.Exists(tempPath)) if (!Directory.Exists(tempPath))
Directory.CreateDirectory(tempPath); Directory.CreateDirectory(tempPath);
int fileIndex = 0; int fileIndex = 0;
foreach(GenericReportModel reportModel in exportData) foreach (GenericReportModel reportModel in exportData)
{ {
foreach(UploadedFiles file in reportModel.Files) foreach (UploadedFiles file in reportModel.Files)
{ {
var fileToCopy = GetFullFilePath(file.Location); var fileToCopy = GetFullFilePath(file.Location);
var destFileName = $"{tempPath}/{fileIndex}{Path.GetExtension(file.Location)}"; var destFileName = $"{tempPath}/{fileIndex}{Path.GetExtension(file.Location)}";

View File

@@ -0,0 +1,56 @@
using CarCareTracker.Models;
using Microsoft.Extensions.Caching.Memory;
using System.Text.Json;
namespace CarCareTracker.Helper
{
public interface ITranslationHelper
{
string Translate(string userLanguage, string text);
}
public class TranslationHelper : ITranslationHelper
{
private readonly IFileHelper _fileHelper;
private readonly IConfiguration _config;
private IMemoryCache _cache;
public TranslationHelper(IFileHelper fileHelper, IConfiguration config, IMemoryCache memoryCache)
{
_fileHelper = fileHelper;
_config = config;
_cache = memoryCache;
}
public string Translate(string userLanguage, string text)
{
bool create = bool.Parse(_config["LUBELOGGER_TRANSLATOR"] ?? "false");
//transform input text into key.
string translationKey = text.Replace(" ", "_");
var translationFilePath = userLanguage == "en_US" ? _fileHelper.GetFullFilePath($"/defaults/en_US.json") : _fileHelper.GetFullFilePath($"/translations/{userLanguage}.json", false);
var dictionary = _cache.GetOrCreate<Dictionary<string, string>>($"lang_{userLanguage}", entry =>
{
entry.SlidingExpiration = TimeSpan.FromHours(1);
if (File.Exists(translationFilePath))
{
var translationFile = File.ReadAllText(translationFilePath);
var translationDictionary = JsonSerializer.Deserialize<Dictionary<string, string>>(translationFile);
return translationDictionary ?? new Dictionary<string, string>();
}
else
{
return new Dictionary<string, string>();
}
});
if (dictionary != null && dictionary.ContainsKey(translationKey))
{
return dictionary[translationKey];
}
else if (create && File.Exists(translationFilePath))
{
//create entry
dictionary.Add(translationKey, text);
File.WriteAllText(translationFilePath, JsonSerializer.Serialize(dictionary));
return text;
}
return text;
}
}
}

View File

@@ -0,0 +1,8 @@
namespace CarCareTracker.Models
{
public class SettingsViewModel
{
public UserConfig UserConfig { get; set; }
public List<string> UILanguages { get; set; }
}
}

View File

@@ -17,6 +17,7 @@
public string PreferredGasMileageUnit { get; set; } = string.Empty; public string PreferredGasMileageUnit { get; set; } = string.Empty;
public string UserNameHash { get; set; } public string UserNameHash { get; set; }
public string UserPasswordHash { get; set;} public string UserPasswordHash { get; set;}
public string UserLanguage { get; set; } = "en_US";
public List<ImportMode> VisibleTabs { get; set; } = new List<ImportMode>() { public List<ImportMode> VisibleTabs { get; set; } = new List<ImportMode>() {
ImportMode.Dashboard, ImportMode.Dashboard,
ImportMode.ServiceRecord, ImportMode.ServiceRecord,

View File

@@ -33,6 +33,7 @@ builder.Services.AddSingleton<IReminderHelper, ReminderHelper>();
builder.Services.AddSingleton<IReportHelper, ReportHelper>(); builder.Services.AddSingleton<IReportHelper, ReportHelper>();
builder.Services.AddSingleton<IMailHelper, MailHelper>(); builder.Services.AddSingleton<IMailHelper, MailHelper>();
builder.Services.AddSingleton<IConfigHelper, ConfigHelper>(); builder.Services.AddSingleton<IConfigHelper, ConfigHelper>();
builder.Services.AddSingleton<ITranslationHelper, TranslationHelper>();
//configure logic //configure logic
builder.Services.AddSingleton<ILoginLogic, LoginLogic>(); builder.Services.AddSingleton<ILoginLogic, LoginLogic>();

View File

@@ -1,10 +1,13 @@
@{ @using CarCareTracker.Helper
@{
ViewData["Title"] = "Admin"; ViewData["Title"] = "Admin";
} }
@inject IConfiguration config; @inject IConfiguration config;
@inject ITranslationHelper translator
@{ @{
bool emailServerIsSetup = true; bool emailServerIsSetup = true;
var mailConfig = config.GetSection("MailConfig").Get<MailConfig>(); var mailConfig = config.GetSection("MailConfig").Get<MailConfig>();
var userLanguage = config[nameof(UserConfig.UserLanguage)] ?? "en_US";
if (mailConfig is null || string.IsNullOrWhiteSpace(mailConfig.EmailServer)) if (mailConfig is null || string.IsNullOrWhiteSpace(mailConfig.EmailServer))
{ {
emailServerIsSetup = false; emailServerIsSetup = false;
@@ -17,31 +20,31 @@
<a href="/Home" class="btn btn-secondary btn-md mt-1 mb-1"><i class="bi bi-arrow-left-square"></i></a> <a href="/Home" class="btn btn-secondary btn-md mt-1 mb-1"><i class="bi bi-arrow-left-square"></i></a>
</div> </div>
<div class="col-11"> <div class="col-11">
<span class="display-6">Admin Panel</span> <span class="display-6">@translator.Translate(userLanguage, "Admin Panel")</span>
</div> </div>
</div> </div>
<hr /> <hr />
<div class="row"> <div class="row">
<div class="col-md-5 col-12"> <div class="col-md-5 col-12">
<span class="lead">Tokens</span> <span class="lead">@translator.Translate(userLanguage, "Tokens")</span>
<hr /> <hr />
<div class="row"> <div class="row">
<div class="col-6"> <div class="col-6">
<button onclick="generateNewToken()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>Generate User Token</button> <button onclick="generateNewToken()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>@translator.Translate(userLanguage, "Generate User Token")</button>
</div> </div>
<div class="col-6 d-flex align-items-center"> <div class="col-6 d-flex align-items-center">
<div class="form-check form-switch"> <div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="enableAutoNotify" @(emailServerIsSetup ? "checked" : "disabled")> <input class="form-check-input" type="checkbox" role="switch" id="enableAutoNotify" @(emailServerIsSetup ? "checked" : "disabled")>
<label class="form-check-label" for="enableAutoNotify">Auto Notify(via Email)</label> <label class="form-check-label" for="enableAutoNotify">@translator.Translate(userLanguage, "Auto Notify(via Email)")</label>
</div> </div>
</div> </div>
</div> </div>
<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-4">Token</th> <th scope="col" class="col-4">@translator.Translate(userLanguage, "Token")</th>
<th scope="col" class="col-6">Issued To</th> <th scope="col" class="col-6">@translator.Translate(userLanguage, "Issued To")</th>
<th scope="col" class="col-2">Delete</th> <th scope="col" class="col-2">@translator.Translate(userLanguage, "Delete")</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@@ -59,15 +62,15 @@
</table> </table>
</div> </div>
<div class="col-12 col-md-7"> <div class="col-12 col-md-7">
<span class="lead">Users</span> <span class="lead">@translator.Translate(userLanguage, "Users")</span>
<hr /> <hr />
<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-4">Username</th> <th scope="col" class="col-4">@translator.Translate(userLanguage, "Username")</th>
<th scope="col" class="col-4">Email</th> <th scope="col" class="col-4">@translator.Translate(userLanguage, "Email")</th>
<th scope="col" class="col-2">Is Admin</th> <th scope="col" class="col-2">@translator.Translate(userLanguage, "Is Admin")</th>
<th scope="col" class="col-2">Delete</th> <th scope="col" class="col-2">@translator.Translate(userLanguage, "Delete")</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>

View File

@@ -1,7 +1,10 @@
@using CarCareTracker.Helper @using CarCareTracker.Helper
@inject IConfigHelper config @inject IConfigHelper config
@inject ITranslationHelper translator
@{ @{
var enableAuth = config.GetUserConfig(User).EnableAuth; var userConfig = config.GetUserConfig(User);
var enableAuth = userConfig.EnableAuth;
var userLanguage = userConfig.UserLanguage;
var logoUrl = config.GetLogoUrl(); var logoUrl = config.GetLogoUrl();
} }
@model string @model string
@@ -14,21 +17,21 @@
<div class="lubelogger-mobile-nav" onclick="hideMobileNav()"> <div class="lubelogger-mobile-nav" onclick="hideMobileNav()">
<ul class="navbar-nav" id="homeTab" role="tablist"> <ul class="navbar-nav" id="homeTab" role="tablist">
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link user-select-none @(Model == "garage" ? "active" : "")" ontouchstart="detectLongTouch(this)" ontouchend="detectTouchEndPremature(this)" id="garage-tab" data-bs-toggle="tab" data-bs-target="#garage-tab-pane" type="button" role="tab"><span class="ms-2 display-3"><i class="bi bi-car-front me-2"></i>Garage</span></button> <button class="nav-link user-select-none @(Model == "garage" ? "active" : "")" ontouchstart="detectLongTouch(this)" ontouchend="detectTouchEndPremature(this)" id="garage-tab" data-bs-toggle="tab" data-bs-target="#garage-tab-pane" type="button" role="tab"><span class="ms-2 display-3"><i class="bi bi-car-front me-2"></i>@translator.Translate(userLanguage,"Garage")</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>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>
</li> </li>
@if (User.IsInRole("CookieAuth")) @if (User.IsInRole("CookieAuth"))
{ {
@if (User.IsInRole(nameof(UserData.IsAdmin))) @if (User.IsInRole(nameof(UserData.IsAdmin)))
{ {
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<a class="dropdown-item" href="/Admin"><span class="display-3 ms-2"><i class="bi bi-people me-2"></i>Admin Panel</span></a> <a class="dropdown-item" href="/Admin"><span class="display-3 ms-2"><i class="bi bi-people me-2"></i>@translator.Translate(userLanguage,"Admin Panel")</span></a>
</li> </li>
} }
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link" onclick="performLogOut()"><span class="display-3 ms-2"><i class="bi bi-box-arrow-right me-2"></i>Logout</span></button> <button class="nav-link" onclick="performLogOut()"><span class="display-3 ms-2"><i class="bi bi-box-arrow-right me-2"></i>@translator.Translate(userLanguage,"Logout")</span></button>
</li> </li>
} }
</ul> </ul>
@@ -45,10 +48,10 @@
<hr /> <hr />
<ul class="nav nav-tabs lubelogger-tab" id="homeTab" role="tablist"> <ul class="nav nav-tabs lubelogger-tab" id="homeTab" role="tablist">
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link @(Model == "garage" ? "active" : "")" oncontextmenu="sortGarage(this)" id="garage-tab" data-bs-toggle="tab" data-bs-target="#garage-tab-pane" type="button" role="tab"><i class="bi bi-car-front me-2"></i>Garage</button> <button class="nav-link @(Model == "garage" ? "active" : "")" oncontextmenu="sortGarage(this)" id="garage-tab" data-bs-toggle="tab" data-bs-target="#garage-tab-pane" type="button" role="tab"><i class="bi bi-car-front me-2"></i>@translator.Translate(userLanguage,"Garage")</button>
</li> </li>
<li class="nav-item ms-auto" role="presentation"> <li class="nav-item ms-auto" 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"><i class="bi bi-gear me-2"></i>Settings</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"><i class="bi bi-gear me-2"></i>@translator.Translate(userLanguage,"Settings")</button>
</li> </li>
@if (User.IsInRole("CookieAuth")) @if (User.IsInRole("CookieAuth"))
{ {
@@ -58,11 +61,11 @@
@if (User.IsInRole(nameof(UserData.IsAdmin))) @if (User.IsInRole(nameof(UserData.IsAdmin)))
{ {
<li> <li>
<a class="dropdown-item" href="/Admin"><i class="bi bi-people me-2"></i>Admin Panel</a> <a class="dropdown-item" href="/Admin"><i class="bi bi-people me-2"></i>@translator.Translate(userLanguage,"Admin Panel")</a>
</li> </li>
} }
<li> <li>
<button class="dropdown-item" onclick="performLogOut()"><i class="bi bi-box-arrow-right me-2"></i>Logout</button> <button class="dropdown-item" onclick="performLogOut()"><i class="bi bi-box-arrow-right me-2"></i>@translator.Translate(userLanguage,"Logout")</button>
</li> </li>
</ul> </ul>
</li> </li>

View File

@@ -1,158 +1,185 @@
@using CarCareTracker.Helper @using CarCareTracker.Helper
@model UserConfig @model SettingsViewModel
@inject ITranslationHelper translator
@{
var userLanguage = Model.UserConfig.UserLanguage;
}
<div class="row"> <div class="row">
<div class="d-flex justify-content-center"> <div class="d-flex justify-content-center">
<h6 class="display-6 mt-2">Settings</h6> <h6 class="display-6 mt-2">@translator.Translate(userLanguage, "Settings")</h6>
</div> </div>
<hr /> <hr />
<div class="col-12 col-md-6"> <div class="col-12 col-md-6">
<input id="preferredGasUnit" style="display:none;" value="@Model.PreferredGasUnit"/> <input id="preferredGasUnit" style="display:none;" value="@Model.UserConfig.PreferredGasUnit" />
<input id="preferredFuelMileageUnit" style="display:none;" value="@Model.PreferredGasMileageUnit" /> <input id="preferredFuelMileageUnit" style="display:none;" value="@Model.UserConfig.PreferredGasMileageUnit" />
<div class="form-check form-switch"> <div class="form-check form-switch">
<input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="enableDarkMode" checked="@Model.UseDarkMode"> <input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="enableDarkMode" checked="@Model.UserConfig.UseDarkMode">
<label class="form-check-label" for="enableDarkMode">Dark Mode</label> <label class="form-check-label" for="enableDarkMode">@translator.Translate(userLanguage, "Dark Mode")</label>
</div> </div>
<div class="form-check form-switch"> <div class="form-check form-switch">
<input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="enableCsvImports" checked="@Model.EnableCsvImports"> <input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="enableCsvImports" checked="@Model.UserConfig.EnableCsvImports">
<label class="form-check-label" for="enableCsvImports">Enable CSV Imports</label> <label class="form-check-label" for="enableCsvImports">@translator.Translate(userLanguage, "Enable CSV Imports")</label>
</div> </div>
<div class="form-check form-switch"> <div class="form-check form-switch">
<input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="useMPG" checked="@Model.UseMPG"> <input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="useMPG" checked="@Model.UserConfig.UseMPG">
<label class="form-check-label" for="useMPG">Use Imperial Calculation for Fuel Economy Calculations(MPG)<br /><small class="text-body-secondary">This Will Also Change Units to Miles and Gallons</small></label> <label class="form-check-label" for="useMPG">@translator.Translate(userLanguage, "Use Imperial Calculation for Fuel Economy Calculations(MPG)")<br /><small class="text-body-secondary">@translator.Translate(userLanguage, "This Will Also Change Units to Miles and Gallons")</small></label>
</div> </div>
<div class="form-check form-switch"> <div class="form-check form-switch">
<input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="useUKMPG" checked="@Model.UseUKMPG"> <input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="useUKMPG" checked="@Model.UserConfig.UseUKMPG">
<label class="form-check-label" for="useUKMPG">Use UK MPG Calculation<br /><small class="text-body-secondary">Input Gas Consumption in Liters, it will be converted to UK Gals for MPG Calculation</small></label> <label class="form-check-label" for="useUKMPG">@translator.Translate(userLanguage, "Use UK MPG Calculation")<br /><small class="text-body-secondary">@translator.Translate(userLanguage, "Input Gas Consumption in Liters, it will be converted to UK Gals for MPG Calculation")</small></label>
</div> </div>
<div class="form-check form-switch"> <div class="form-check form-switch">
<input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="useDescending" checked="@Model.UseDescending"> <input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="useDescending" checked="@Model.UserConfig.UseDescending">
<label class="form-check-label" for="useDescending">Sort lists in Descending Order(Newest to Oldest)</label> <label class="form-check-label" for="useDescending">@translator.Translate(userLanguage, "Sort lists in Descending Order(Newest to Oldest)")</label>
</div> </div>
<div class="form-check form-switch"> <div class="form-check form-switch">
<input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="hideZero" checked="@Model.HideZero"> <input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="hideZero" checked="@Model.UserConfig.HideZero">
<label class="form-check-label" for="hideZero">Replace @(0.ToString("C")) Costs with ---</label> <label class="form-check-label" for="hideZero">@translator.Translate(userLanguage, "Replace $0.00 Costs with ---")</label>
</div> </div>
<div class="form-check form-switch"> <div class="form-check form-switch">
<input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="useThreeDecimal" checked="@Model.UseThreeDecimalGasCost"> <input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="useThreeDecimal" checked="@Model.UserConfig.UseThreeDecimalGasCost">
<label class="form-check-label" for="useThreeDecimal">Use Three Decimals For Fuel Cost</label> <label class="form-check-label" for="useThreeDecimal">@translator.Translate(userLanguage, "Use Three Decimals For Fuel Cost")</label>
</div> </div>
<div class="form-check form-switch"> <div class="form-check form-switch">
<input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="useMarkDownOnSavedNotes" checked="@Model.UseMarkDownOnSavedNotes"> <input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="useMarkDownOnSavedNotes" checked="@Model.UserConfig.UseMarkDownOnSavedNotes">
<label class="form-check-label" for="useMarkDownOnSavedNotes">Display Saved Notes in Markdown</label> <label class="form-check-label" for="useMarkDownOnSavedNotes">@translator.Translate(userLanguage, "Display Saved Notes in Markdown")</label>
</div> </div>
<div class="form-check form-switch"> <div class="form-check form-switch">
<input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="enableAutoReminderRefresh" checked="@Model.EnableAutoReminderRefresh"> <input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="enableAutoReminderRefresh" checked="@Model.UserConfig.EnableAutoReminderRefresh">
<label class="form-check-label" for="enableAutoReminderRefresh">Auto Refresh Lapsed Recurring Reminders</label> <label class="form-check-label" for="enableAutoReminderRefresh">@translator.Translate(userLanguage, "Auto Refresh Lapsed Recurring Reminders")</label>
</div> </div>
<div class="form-check form-switch"> <div class="form-check form-switch">
<input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="enableAutoOdometerInsert" checked="@Model.EnableAutoOdometerInsert"> <input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="enableAutoOdometerInsert" checked="@Model.UserConfig.EnableAutoOdometerInsert">
<label class="form-check-label" for="enableAutoOdometerInsert">Auto Insert Odometer Records<br /><small class="text-body-secondary">Only when Adding Service/Repair/Upgrade/Fuel Record or Completing a Plan</small></label> <label class="form-check-label" for="enableAutoOdometerInsert">@translator.Translate(userLanguage, "Auto Insert Odometer Records")<br /><small class="text-body-secondary">@translator.Translate(userLanguage, "Only when Adding Service/Repair/Upgrade/Fuel Record or Completing a Plan")</small></label>
</div> </div>
@if (User.IsInRole(nameof(UserData.IsRootUser))) @if (User.IsInRole(nameof(UserData.IsRootUser)))
{ {
<div class="form-check form-switch"> <div class="form-check form-switch">
<input class="form-check-input" onChange="enableAuthCheckChanged()" type="checkbox" role="switch" id="enableAuth" checked="@Model.EnableAuth"> <input class="form-check-input" onChange="enableAuthCheckChanged()" type="checkbox" role="switch" id="enableAuth" checked="@Model.UserConfig.EnableAuth">
<label class="form-check-label" for="enableAuth">Enable Authentication</label> <label class="form-check-label" for="enableAuth">@translator.Translate(userLanguage, "Enable Authentication")</label>
</div> </div>
} }
</div> </div>
<div class="col-12 col-md-6"> <div class="col-12 col-md-6">
<div class="row" id="visibleTabs"> <div class="row" id="visibleTabs">
<div class="col-12"> <div class="col-12">
<span class="lead">Visible Tabs</span> <span class="lead">@translator.Translate(userLanguage, "Visible Tabs")</span>
</div> </div>
<div class="col-12 col-md-6"> <div class="col-12 col-md-6">
<ul class="list-group"> <ul class="list-group">
<li class="list-group-item"> <li class="list-group-item">
<input onChange="updateSettings()" class="form-check-input me-1" type="checkbox" value="ServiceRecord" id="serviceRecordTab" @(Model.VisibleTabs.Contains(ImportMode.ServiceRecord) ? "checked" : "")> <input onChange="updateSettings()" class="form-check-input me-1" type="checkbox" value="ServiceRecord" id="serviceRecordTab" @(Model.UserConfig.VisibleTabs.Contains(ImportMode.ServiceRecord) ? "checked" : "")>
<label class="form-check-label stretched-link" for="serviceRecordTab">Service Records</label> <label class="form-check-label stretched-link" for="serviceRecordTab">@translator.Translate(userLanguage, "Service Records")</label>
</li> </li>
<li class="list-group-item d-none"> <li class="list-group-item d-none">
<input onChange="updateSettings()" disabled class="form-check-input me-1" type="checkbox" value="Dashboard" id="dashboardTab" @(Model.VisibleTabs.Contains(ImportMode.Dashboard) ? "checked" : "")> <input onChange="updateSettings()" disabled class="form-check-input me-1" type="checkbox" value="Dashboard" id="dashboardTab" @(Model.UserConfig.VisibleTabs.Contains(ImportMode.Dashboard) ? "checked" : "")>
<label class="form-check-label stretched-link" for="dashboardTab">Dashboard</label> <label class="form-check-label stretched-link" for="dashboardTab">@translator.Translate(userLanguage, "Dashboard")</label>
</li> </li>
<li class="list-group-item"> <li class="list-group-item">
<input onChange="updateSettings()" class="form-check-input me-1" type="checkbox" value="RepairRecord" id="repairRecordTab" @(Model.VisibleTabs.Contains(ImportMode.RepairRecord) ? "checked" : "")> <input onChange="updateSettings()" class="form-check-input me-1" type="checkbox" value="RepairRecord" id="repairRecordTab" @(Model.UserConfig.VisibleTabs.Contains(ImportMode.RepairRecord) ? "checked" : "")>
<label class="form-check-label stretched-link" for="repairRecordTab">Repairs</label> <label class="form-check-label stretched-link" for="repairRecordTab">@translator.Translate(userLanguage, "Repairs")</label>
</li> </li>
<li class="list-group-item"> <li class="list-group-item">
<input onChange="updateSettings()" class="form-check-input me-1" type="checkbox" value="UpgradeRecord" id="upgradeRecordTab" @(Model.VisibleTabs.Contains(ImportMode.UpgradeRecord) ? "checked" : "")> <input onChange="updateSettings()" class="form-check-input me-1" type="checkbox" value="UpgradeRecord" id="upgradeRecordTab" @(Model.UserConfig.VisibleTabs.Contains(ImportMode.UpgradeRecord) ? "checked" : "")>
<label class="form-check-label stretched-link" for="upgradeRecordTab">Upgrades</label> <label class="form-check-label stretched-link" for="upgradeRecordTab">@translator.Translate(userLanguage, "Upgrades")</label>
</li> </li>
<li class="list-group-item"> <li class="list-group-item">
<input onChange="updateSettings()" class="form-check-input me-1" type="checkbox" value="GasRecord" id="gasRecordTab" @(Model.VisibleTabs.Contains(ImportMode.GasRecord) ? "checked" : "")> <input onChange="updateSettings()" class="form-check-input me-1" type="checkbox" value="GasRecord" id="gasRecordTab" @(Model.UserConfig.VisibleTabs.Contains(ImportMode.GasRecord) ? "checked" : "")>
<label class="form-check-label stretched-link" for="gasRecordTab">Fuel</label> <label class="form-check-label stretched-link" for="gasRecordTab">@translator.Translate(userLanguage, "Fuel")</label>
</li> </li>
<li class="list-group-item"> <li class="list-group-item">
<input onChange="updateSettings()" class="form-check-input me-1" type="checkbox" value="OdometerRecord" id="odometerRecordTab" @(Model.VisibleTabs.Contains(ImportMode.OdometerRecord) ? "checked" : "")> <input onChange="updateSettings()" class="form-check-input me-1" type="checkbox" value="OdometerRecord" id="odometerRecordTab" @(Model.UserConfig.VisibleTabs.Contains(ImportMode.OdometerRecord) ? "checked" : "")>
<label class="form-check-label stretched-link" for="odometerRecordTab">Odometer</label> <label class="form-check-label stretched-link" for="odometerRecordTab">@translator.Translate(userLanguage, "Odometer")</label>
</li> </li>
</ul> </ul>
</div> </div>
<div class="col-12 col-md-6"> <div class="col-12 col-md-6">
<ul class="list-group"> <ul class="list-group">
<li class="list-group-item"> <li class="list-group-item">
<input onChange="updateSettings()" class="form-check-input me-1" type="checkbox" value="TaxRecord" id="taxRecordTab" @(Model.VisibleTabs.Contains(ImportMode.TaxRecord) ? "checked" : "")> <input onChange="updateSettings()" class="form-check-input me-1" type="checkbox" value="TaxRecord" id="taxRecordTab" @(Model.UserConfig.VisibleTabs.Contains(ImportMode.TaxRecord) ? "checked" : "")>
<label class="form-check-label stretched-link" for="taxRecordTab">Taxes</label> <label class="form-check-label stretched-link" for="taxRecordTab">@translator.Translate(userLanguage, "Taxes")</label>
</li> </li>
<li class="list-group-item"> <li class="list-group-item">
<input onChange="updateSettings()" class="form-check-input me-1" type="checkbox" value="NoteRecord" id="noteRecordTab" @(Model.VisibleTabs.Contains(ImportMode.NoteRecord) ? "checked" : "")> <input onChange="updateSettings()" class="form-check-input me-1" type="checkbox" value="NoteRecord" id="noteRecordTab" @(Model.UserConfig.VisibleTabs.Contains(ImportMode.NoteRecord) ? "checked" : "")>
<label class="form-check-label stretched-link" for="noteRecordTab">Notes</label> <label class="form-check-label stretched-link" for="noteRecordTab">@translator.Translate(userLanguage, "Notes")</label>
</li> </li>
<li class="list-group-item"> <li class="list-group-item">
<input onChange="updateSettings()" class="form-check-input me-1" type="checkbox" value="ReminderRecord" id="reminderRecordTab" @(Model.VisibleTabs.Contains(ImportMode.ReminderRecord) ? "checked" : "")> <input onChange="updateSettings()" class="form-check-input me-1" type="checkbox" value="ReminderRecord" id="reminderRecordTab" @(Model.UserConfig.VisibleTabs.Contains(ImportMode.ReminderRecord) ? "checked" : "")>
<label class="form-check-label stretched-link" for="reminderRecordTab">Reminder</label> <label class="form-check-label stretched-link" for="reminderRecordTab">@translator.Translate(userLanguage, "Reminder")</label>
</li> </li>
<li class="list-group-item"> <li class="list-group-item">
<input onChange="updateSettings()" class="form-check-input me-1" type="checkbox" value="SupplyRecord" id="supplyRecordTab" @(Model.VisibleTabs.Contains(ImportMode.SupplyRecord) ? "checked" : "")> <input onChange="updateSettings()" class="form-check-input me-1" type="checkbox" value="SupplyRecord" id="supplyRecordTab" @(Model.UserConfig.VisibleTabs.Contains(ImportMode.SupplyRecord) ? "checked" : "")>
<label class="form-check-label stretched-link" for="supplyRecordTab">Supplies</label> <label class="form-check-label stretched-link" for="supplyRecordTab">@translator.Translate(userLanguage, "Supplies")</label>
</li> </li>
<li class="list-group-item"> <li class="list-group-item">
<input onChange="updateSettings()" class="form-check-input me-1" type="checkbox" value="PlanRecord" id="planRecordTab" @(Model.VisibleTabs.Contains(ImportMode.PlanRecord) ? "checked" : "")> <input onChange="updateSettings()" class="form-check-input me-1" type="checkbox" value="PlanRecord" id="planRecordTab" @(Model.UserConfig.VisibleTabs.Contains(ImportMode.PlanRecord) ? "checked" : "")>
<label class="form-check-label stretched-link" for="planRecordTab">Planner</label> <label class="form-check-label stretched-link" for="planRecordTab">@translator.Translate(userLanguage, "Planner")</label>
</li> </li>
</ul> </ul>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-12 col-md-6"> <div class="col-12 col-md-6">
<span class="lead">Default Tab</span> <span class="lead">@translator.Translate(userLanguage, "Default Tab")</span>
<select class="form-select" onchange="updateSettings()" id="defaultTab"> <select class="form-select" onchange="updateSettings()" id="defaultTab">
<!option @(StaticHelper.DefaultTabSelected(Model, ImportMode.Dashboard)) value="Dashboard">Dashboard</!option> <!option @(StaticHelper.DefaultTabSelected(Model.UserConfig, ImportMode.Dashboard)) value="Dashboard">@translator.Translate(userLanguage, "Dashboard")</!option>
<!option @(StaticHelper.DefaultTabSelected(Model,ImportMode.ServiceRecord)) value="ServiceRecord">Service Record</!option> <!option @(StaticHelper.DefaultTabSelected(Model.UserConfig, ImportMode.ServiceRecord)) value="ServiceRecord">@translator.Translate(userLanguage, "Service Record")</!option>
<!option @(StaticHelper.DefaultTabSelected(Model, ImportMode.RepairRecord)) value="RepairRecord">Repairs</!option> <!option @(StaticHelper.DefaultTabSelected(Model.UserConfig, ImportMode.RepairRecord)) value="RepairRecord">@translator.Translate(userLanguage, "Repairs")</!option>
<!option @(StaticHelper.DefaultTabSelected(Model, ImportMode.UpgradeRecord)) value="UpgradeRecord">Upgrades</!option> <!option @(StaticHelper.DefaultTabSelected(Model.UserConfig, ImportMode.UpgradeRecord)) value="UpgradeRecord">@translator.Translate(userLanguage, "Upgrades")</!option>
<!option @(StaticHelper.DefaultTabSelected(Model, ImportMode.GasRecord)) value="GasRecord">Fuel</!option> <!option @(StaticHelper.DefaultTabSelected(Model.UserConfig, ImportMode.GasRecord)) value="GasRecord">@translator.Translate(userLanguage, "Fuel")</!option>
<!option @(StaticHelper.DefaultTabSelected(Model, ImportMode.TaxRecord)) value="TaxRecord">Tax</!option> <!option @(StaticHelper.DefaultTabSelected(Model.UserConfig, ImportMode.TaxRecord)) value="TaxRecord">@translator.Translate(userLanguage, "Tax")</!option>
<!option @(StaticHelper.DefaultTabSelected(Model, ImportMode.NoteRecord)) value="NoteRecord">Notes</!option> <!option @(StaticHelper.DefaultTabSelected(Model.UserConfig, ImportMode.NoteRecord)) value="NoteRecord">@translator.Translate(userLanguage, "Notes")</!option>
<!option @(StaticHelper.DefaultTabSelected(Model, ImportMode.ReminderRecord)) value="ReminderRecord">Reminders</!option> <!option @(StaticHelper.DefaultTabSelected(Model.UserConfig, ImportMode.ReminderRecord)) value="ReminderRecord">@translator.Translate(userLanguage, "Reminders")</!option>
<!option @(StaticHelper.DefaultTabSelected(Model, ImportMode.SupplyRecord)) value="SupplyRecord">Supplies</!option> <!option @(StaticHelper.DefaultTabSelected(Model.UserConfig, ImportMode.SupplyRecord)) value="SupplyRecord">@translator.Translate(userLanguage, "Supplies")</!option>
<!option @(StaticHelper.DefaultTabSelected(Model, ImportMode.PlanRecord)) value="PlanRecord">Planner</!option> <!option @(StaticHelper.DefaultTabSelected(Model.UserConfig, ImportMode.PlanRecord)) value="PlanRecord">@translator.Translate(userLanguage, "Planner")</!option>
<!option @(StaticHelper.DefaultTabSelected(Model, ImportMode.OdometerRecord)) value="OdometerRecord">Odometer</!option> <!option @(StaticHelper.DefaultTabSelected(Model.UserConfig, ImportMode.OdometerRecord)) value="OdometerRecord">@translator.Translate(userLanguage, "Odometer")</!option>
</select> </select>
</div> </div>
@if (User.IsInRole(nameof(UserData.IsRootUser))) <div class="col-12 col-md-6">
{ <span class="lead">@translator.Translate(userLanguage, "Language")</span>
<select class="form-select" onchange="updateSettings()" id="defaultLanguage">
@foreach (string uiLanguage in Model.UILanguages)
{
<!option @(Model.UserConfig.UserLanguage == uiLanguage ? "selected" : "")>@uiLanguage</!option>
}
</select>
</div>
</div>
@if (User.IsInRole(nameof(UserData.IsRootUser)))
{
<div class="row">
<div class="col-12 col-md-6"> <div class="col-12 col-md-6">
<span class="lead">Backups</span> <span class="lead">@translator.Translate(userLanguage, "Backups")</span>
<div class="row"> <div class="row">
<div class="col-6 d-grid"> <div class="col-6 d-grid">
<button onclick="makeBackup()" class="btn btn-primary btn-md">Make</button> <button onclick="makeBackup()" class="btn btn-primary btn-md">@translator.Translate(userLanguage, "Make")</button>
</div> </div>
<div class="col-6 d-grid"> <div class="col-6 d-grid">
<input onChange="restoreBackup(this)" type="file" accept=".zip" class="d-none" id="inputBackup"> <input onChange="restoreBackup(this)" type="file" accept=".zip" class="d-none" id="inputBackup">
<button onclick="openRestoreBackup()" class="btn btn-secondary btn-md">Restore</button> <button onclick="openRestoreBackup()" class="btn btn-secondary btn-md">@translator.Translate(userLanguage, "Restore")</button>
</div>
</div> </div>
</div>
</div> </div>
} <div class="col-12 col-md-6">
</div> <span class="lead">@translator.Translate(userLanguage, "Manage Languages")</span>
<div class="row">
<div class="col-6 d-grid">
<input onChange="uploadLanguage(this)" type="file" accept=".json" class="d-none" id="inputLanguage">
<button onclick="openUploadLanguage()" class="btn btn-primary btn-md">@translator.Translate(userLanguage, "Upload")</button>
</div>
<div class="col-6 d-grid">
<button onclick="deleteLanguage()" @(Model.UserConfig.UserLanguage == "en_US" ? "disabled" : "") class="btn btn-danger btn-md">@translator.Translate(userLanguage, "Delete")</button>
</div>
</div>
</div>
</div>
}
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="d-flex justify-content-center"> <div class="d-flex justify-content-center">
<h6 class="display-6 mt-2">About</h6> <h6 class="display-6 mt-2">@translator.Translate(userLanguage, "About")</h6>
</div> </div>
<hr /> <hr />
<div class="col-12 col-md-6"> <div class="col-12 col-md-6">
@@ -204,10 +231,18 @@
}); });
return visibleTabs.toArray(); return visibleTabs.toArray();
} }
function updateSettings(){ function deleteLanguage() {
var languageFileLocation = `/translations/${$("#defaultLanguage").val()}.json`;
$.post('/Files/DeleteFiles', { fileLocation: languageFileLocation }, function (data) {
//reset user language back to en_US
$("#defaultLanguage").val('en_US');
updateSettings();
});
}
function updateSettings() {
var visibleTabs = getCheckedTabs(); var visibleTabs = getCheckedTabs();
var defaultTab = $("#defaultTab").val(); var defaultTab = $("#defaultTab").val();
if (!visibleTabs.includes(defaultTab)){ if (!visibleTabs.includes(defaultTab)) {
defaultTab = "Dashboard"; //default to dashboard. defaultTab = "Dashboard"; //default to dashboard.
} }
var userConfigObject = { var userConfigObject = {
@@ -223,11 +258,12 @@
enableAutoOdometerInsert: $("#enableAutoOdometerInsert").is(":checked"), enableAutoOdometerInsert: $("#enableAutoOdometerInsert").is(":checked"),
preferredGasUnit: $("#preferredGasUnit").val(), preferredGasUnit: $("#preferredGasUnit").val(),
preferredGasMileageUnit: $("#preferredFuelMileageUnit").val(), preferredGasMileageUnit: $("#preferredFuelMileageUnit").val(),
userLanguage: $("#defaultLanguage").val(),
visibleTabs: visibleTabs, visibleTabs: visibleTabs,
defaultTab: defaultTab defaultTab: defaultTab
} }
sloader.show(); sloader.show();
$.post('/Home/WriteToSettings', { userConfig: userConfigObject}, function(data){ $.post('/Home/WriteToSettings', { userConfig: userConfigObject }, function (data) {
sloader.hide(); sloader.hide();
if (data) { if (data) {
setTimeout(function () { window.location.href = '/Home/Index?tab=settings' }, 500); setTimeout(function () { window.location.href = '/Home/Index?tab=settings' }, 500);
@@ -241,9 +277,37 @@
window.location.href = data; window.location.href = data;
}); });
} }
function openRestoreBackup(){ function openUploadLanguage(){
$("#inputLanguage").click();
}
function openRestoreBackup() {
$("#inputBackup").click(); $("#inputBackup").click();
} }
function uploadLanguage(event){
let formData = new FormData();
formData.append("file", event.files[0]);
sloader.show();
$.ajax({
url: "/Files/HandleTranslationFileUpload",
data: formData,
cache: false,
processData: false,
contentType: false,
type: 'POST',
success: function (response) {
sloader.hide();
if (response.success) {
setTimeout(function () { window.location.href = '/Home/Index?tab=settings' }, 500);
} else {
errorToast(response.message);
}
},
error: function(){
sloader.hide();
errorToast("An error has occurred, please check the file size and try again later.");
}
});
}
function restoreBackup(event) { function restoreBackup(event) {
let formData = new FormData(); let formData = new FormData();
formData.append("file", event.files[0]); formData.append("file", event.files[0]);
@@ -257,9 +321,9 @@
type: 'POST', type: 'POST',
success: function (response) { success: function (response) {
if (response.trim() != '') { if (response.trim() != '') {
$.post('/Files/RestoreBackup', { fileName : response}, function (data) { $.post('/Files/RestoreBackup', { fileName: response }, function (data) {
sloader.hide(); sloader.hide();
if (data){ if (data) {
successToast("Backup Restored"); successToast("Backup Restored");
setTimeout(function () { window.location.href = '/Home/Index' }, 500); setTimeout(function () { window.location.href = '/Home/Index' }, 500);
} else { } else {
@@ -267,19 +331,23 @@
} }
}); });
} }
},
error: function () {
sloader.hide();
errorToast("An error has occurred, please check the file size and try again later.");
} }
}); });
} }
function enableAuthCheckChanged(){ function enableAuthCheckChanged() {
var enableAuth = $("#enableAuth").is(":checked"); var enableAuth = $("#enableAuth").is(":checked");
if (enableAuth) { if (enableAuth) {
//swal dialog to set up username and password. //swal dialog to set up username and password.
Swal.fire({ Swal.fire({
title: 'Setup Credentials', title: 'Setup Credentials',
html: ` html: `
<input type="text" id="authUsername" class="swal2-input" placeholder="Username"> <input type="text" id="authUsername" class="swal2-input" placeholder="Username">
<input type="password" id="authPassword" class="swal2-input" placeholder="Password"> <input type="password" id="authPassword" class="swal2-input" placeholder="Password">
`, `,
confirmButtonText: 'Setup', confirmButtonText: 'Setup',
focusConfirm: false, focusConfirm: false,
preConfirm: () => { preConfirm: () => {

View File

@@ -3,8 +3,10 @@
ViewData["Title"] = "LubeLogger - View Vehicle"; ViewData["Title"] = "LubeLogger - View Vehicle";
} }
@inject IConfigHelper config @inject IConfigHelper config
@inject ITranslationHelper translator
@{ @{
var userConfig = config.GetUserConfig(User); var userConfig = config.GetUserConfig(User);
var userLanguage = userConfig.UserLanguage;
} }
@model Vehicle @model Vehicle
@section Scripts { @section Scripts {
@@ -26,46 +28,46 @@
<div class="lubelogger-mobile-nav" onclick="hideMobileNav()"> <div class="lubelogger-mobile-nav" onclick="hideMobileNav()">
<ul class="nav navbar-nav" id="vehicleTab" role="tablist"> <ul class="nav navbar-nav" id="vehicleTab" role="tablist">
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link" onclick="returnToGarage()"><span class="display-3 ms-2"><i class="bi bi-arrow-left-square"></i>Garage</span></button> <button class="nav-link" onclick="returnToGarage()"><span class="display-3 ms-2"><i class="bi bi-arrow-left-square me-2"></i>@translator.Translate(userLanguage,"Garage")</span></button>
</li> </li>
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link" onclick="editVehicle(@Model.Id)"><span class="display-3 ms-2"><i class="bi bi-pencil-square"></i>Edit Vehicle</span></button> <button class="nav-link" onclick="editVehicle(@Model.Id)"><span class="display-3 ms-2"><i class="bi bi-pencil-square me-2"></i>@translator.Translate(userLanguage, "Edit Vehicle")</span></button>
</li> </li>
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.Dashboard)" id="report-tab" data-bs-toggle="tab" data-bs-target="#report-tab-pane" type="button" role="tab" aria-selected="false"><span class="display-3 ms-2"><i class="bi bi-file-bar-graph me-2"></i>Dashboard</span></button> <button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.Dashboard)" id="report-tab" data-bs-toggle="tab" data-bs-target="#report-tab-pane" type="button" role="tab" aria-selected="false"><span class="display-3 ms-2"><i class="bi bi-file-bar-graph me-2"></i>@translator.Translate(userLanguage, "Dashboard")</span></button>
</li> </li>
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.PlanRecord)" id="plan-tab" data-bs-toggle="tab" data-bs-target="#plan-tab-pane" type="button" role="tab" aria-selected="false"><span class="display-3 ms-2"><i class="bi bi-bar-chart-steps me-2"></i>Planner</span></button> <button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.PlanRecord)" id="plan-tab" data-bs-toggle="tab" data-bs-target="#plan-tab-pane" type="button" role="tab" aria-selected="false"><span class="display-3 ms-2"><i class="bi bi-bar-chart-steps me-2"></i>@translator.Translate(userLanguage, "Planner")</span></button>
</li> </li>
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.OdometerRecord)" id="odometer-tab" data-bs-toggle="tab" data-bs-target="#odometer-tab-pane" type="button" role="tab" aria-selected="false"><span class="display-3 ms-2"><i class="bi bi-speedometer me-2"></i>Odometer</span></button> <button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.OdometerRecord)" id="odometer-tab" data-bs-toggle="tab" data-bs-target="#odometer-tab-pane" type="button" role="tab" aria-selected="false"><span class="display-3 ms-2"><i class="bi bi-speedometer me-2"></i>@translator.Translate(userLanguage, "Odometer")</span></button>
</li> </li>
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.ServiceRecord)" id="servicerecord-tab" data-bs-toggle="tab" data-bs-target="#servicerecord-tab-pane" type="button" role="tab" aria-selected="true"><span class="display-3 ms-2"><i class="bi bi-card-checklist me-2"></i>Service Records</span></button> <button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.ServiceRecord)" id="servicerecord-tab" data-bs-toggle="tab" data-bs-target="#servicerecord-tab-pane" type="button" role="tab" aria-selected="true"><span class="display-3 ms-2"><i class="bi bi-card-checklist me-2"></i>@translator.Translate(userLanguage, "Service Records")</span></button>
</li> </li>
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.RepairRecord)" id="accident-tab" data-bs-toggle="tab" data-bs-target="#accident-tab-pane" type="button" role="tab" aria-selected="false"><span class="display-3 ms-2"><i class="bi bi-exclamation-octagon me-2"></i>Repairs</span></button> <button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.RepairRecord)" id="accident-tab" data-bs-toggle="tab" data-bs-target="#accident-tab-pane" type="button" role="tab" aria-selected="false"><span class="display-3 ms-2"><i class="bi bi-exclamation-octagon me-2"></i>@translator.Translate(userLanguage,"Repairs")</span></button>
</li> </li>
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.UpgradeRecord)" id="upgrade-tab" data-bs-toggle="tab" data-bs-target="#upgrade-tab-pane" type="button" role="tab" aria-selected="false"><span class="display-3 ms-2"><i class="bi bi-wrench-adjustable me-2"></i>Upgrades</span></button> <button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.UpgradeRecord)" id="upgrade-tab" data-bs-toggle="tab" data-bs-target="#upgrade-tab-pane" type="button" role="tab" aria-selected="false"><span class="display-3 ms-2"><i class="bi bi-wrench-adjustable me-2"></i>@translator.Translate(userLanguage, "Upgrades")</span></button>
</li> </li>
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.GasRecord)" id="gas-tab" data-bs-toggle="tab" data-bs-target="#gas-tab-pane" type="button" role="tab" aria-selected="false"><span class="display-3 ms-2"><i class="bi bi-fuel-pump me-2"></i>Fuel</span></button> <button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.GasRecord)" id="gas-tab" data-bs-toggle="tab" data-bs-target="#gas-tab-pane" type="button" role="tab" aria-selected="false"><span class="display-3 ms-2"><i class="bi bi-fuel-pump me-2"></i>@translator.Translate(userLanguage, "Fuel")</span></button>
</li> </li>
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.SupplyRecord)" id="supply-tab" data-bs-toggle="tab" data-bs-target="#supply-tab-pane" type="button" role="tab" aria-selected="false"><span class="display-3 ms-2"><i class="bi bi-shop me-2"></i>Supplies</span></button> <button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.SupplyRecord)" id="supply-tab" data-bs-toggle="tab" data-bs-target="#supply-tab-pane" type="button" role="tab" aria-selected="false"><span class="display-3 ms-2"><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 @StaticHelper.DefaultActiveTab(userConfig, ImportMode.TaxRecord)" id="tax-tab" data-bs-toggle="tab" data-bs-target="#tax-tab-pane" type="button" role="tab" aria-selected="false"><span class="display-3 ms-2"><i class="bi bi-currency-dollar me-2"></i>Taxes</span></button> <button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.TaxRecord)" id="tax-tab" data-bs-toggle="tab" data-bs-target="#tax-tab-pane" type="button" role="tab" aria-selected="false"><span class="display-3 ms-2"><i class="bi bi-currency-dollar me-2"></i>@translator.Translate(userLanguage, "Taxes")</span></button>
</li> </li>
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.NoteRecord)" id="notes-tab" data-bs-toggle="tab" data-bs-target="#notes-tab-pane" type="button" role="tab" aria-selected="false"><span class="display-3 ms-2"><i class="bi bi-journal-bookmark me-2"></i>Notes</span></button> <button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.NoteRecord)" id="notes-tab" data-bs-toggle="tab" data-bs-target="#notes-tab-pane" type="button" role="tab" aria-selected="false"><span class="display-3 ms-2"><i class="bi bi-journal-bookmark me-2"></i>@translator.Translate(userLanguage, "Notes")</span></button>
</li> </li>
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.ReminderRecord)" id="reminder-tab" data-bs-toggle="tab" data-bs-target="#reminder-tab-pane" type="button" role="tab" aria-selected="false"><span class="display-3 ms-2"><div class="reminderBellDiv" style="display:inline-flex;"><i class="reminderBell bi bi-bell me-2"></i></div>Reminders</span></button> <button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.ReminderRecord)" id="reminder-tab" data-bs-toggle="tab" data-bs-target="#reminder-tab-pane" type="button" role="tab" aria-selected="false"><span class="display-3 ms-2"><div class="reminderBellDiv" style="display:inline-flex;"><i class="reminderBell bi bi-bell me-2"></i></div>@translator.Translate(userLanguage, "Reminders")</span></button>
</li> </li>
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button onclick="deleteVehicle(@Model.Id)" class="dropdown-item"><span class="display-3 ms-2"><i class="bi bi-trash me-2"></i>Delete Vehicle</span></button> <button onclick="deleteVehicle(@Model.Id)" class="dropdown-item"><span class="display-3 ms-2"><i class="bi bi-trash me-2"></i>@translator.Translate(userLanguage, "Delete Vehicle")</span></button>
</li> </li>
</ul> </ul>
</div> </div>
@@ -83,42 +85,42 @@
<hr /> <hr />
<ul class="nav nav-tabs lubelogger-tab" id="vehicleTab" role="tablist"> <ul class="nav nav-tabs lubelogger-tab" id="vehicleTab" role="tablist">
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.Dashboard)" id="report-tab" data-bs-toggle="tab" data-bs-target="#report-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-file-bar-graph me-2"></i>Dash</button> <button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.Dashboard)" id="report-tab" data-bs-toggle="tab" data-bs-target="#report-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-file-bar-graph me-2"></i>@translator.Translate(userLanguage,"Dashboard")</button>
</li> </li>
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.PlanRecord)" id="plan-tab" data-bs-toggle="tab" data-bs-target="#plan-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-bar-chart-steps me-2"></i>Planner</button> <button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.PlanRecord)" id="plan-tab" data-bs-toggle="tab" data-bs-target="#plan-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-bar-chart-steps me-2"></i>@translator.Translate(userLanguage, "Planner")</button>
</li> </li>
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.OdometerRecord)" id="odometer-tab" data-bs-toggle="tab" data-bs-target="#odometer-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-speedometer me-2"></i>Odometer</button> <button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.OdometerRecord)" id="odometer-tab" data-bs-toggle="tab" data-bs-target="#odometer-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-speedometer me-2"></i>@translator.Translate(userLanguage, "Odometer")</button>
</li> </li>
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.ServiceRecord)" id="servicerecord-tab" data-bs-toggle="tab" data-bs-target="#servicerecord-tab-pane" type="button" role="tab" aria-selected="true"><i class="bi bi-card-checklist me-2"></i>Service Records</button> <button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.ServiceRecord)" id="servicerecord-tab" data-bs-toggle="tab" data-bs-target="#servicerecord-tab-pane" type="button" role="tab" aria-selected="true"><i class="bi bi-card-checklist me-2"></i>@translator.Translate(userLanguage, "Service Records")</button>
</li> </li>
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.RepairRecord)" id="accident-tab" data-bs-toggle="tab" data-bs-target="#accident-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-exclamation-octagon me-2"></i>Repairs</button> <button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.RepairRecord)" id="accident-tab" data-bs-toggle="tab" data-bs-target="#accident-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-exclamation-octagon me-2"></i>@translator.Translate(userLanguage, "Repairs")</button>
</li> </li>
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.UpgradeRecord)" id="upgrade-tab" data-bs-toggle="tab" data-bs-target="#upgrade-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-wrench-adjustable me-2"></i>Upgrades</button> <button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.UpgradeRecord)" id="upgrade-tab" data-bs-toggle="tab" data-bs-target="#upgrade-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-wrench-adjustable me-2"></i>@translator.Translate(userLanguage, "Upgrades")</button>
</li> </li>
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.GasRecord)" id="gas-tab" data-bs-toggle="tab" data-bs-target="#gas-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-fuel-pump me-2"></i>Fuel</button> <button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.GasRecord)" id="gas-tab" data-bs-toggle="tab" data-bs-target="#gas-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-fuel-pump me-2"></i>@translator.Translate(userLanguage, "Fuel")</button>
</li> </li>
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.SupplyRecord)" id="supply-tab" data-bs-toggle="tab" data-bs-target="#supply-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-shop me-2"></i>Supplies</button> <button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.SupplyRecord)" id="supply-tab" data-bs-toggle="tab" data-bs-target="#supply-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-shop me-2"></i>@translator.Translate(userLanguage, "Supplies")</button>
</li> </li>
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.TaxRecord)" id="tax-tab" data-bs-toggle="tab" data-bs-target="#tax-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-currency-dollar me-2"></i>Taxes</button> <button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.TaxRecord)" id="tax-tab" data-bs-toggle="tab" data-bs-target="#tax-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-currency-dollar me-2"></i>@translator.Translate(userLanguage, "Taxes")</button>
</li> </li>
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.NoteRecord)" id="notes-tab" data-bs-toggle="tab" data-bs-target="#notes-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-journal-bookmark me-2"></i>Notes</button> <button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.NoteRecord)" id="notes-tab" data-bs-toggle="tab" data-bs-target="#notes-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-journal-bookmark me-2"></i>@translator.Translate(userLanguage, "Notes")</button>
</li> </li>
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.ReminderRecord)" id="reminder-tab" data-bs-toggle="tab" data-bs-target="#reminder-tab-pane" type="button" role="tab" aria-selected="false"><div class="reminderBellDiv" style="display:inline-flex;"><i class="reminderBell bi bi-bell me-2"></i></div>Reminders</button> <button class="nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.ReminderRecord)" id="reminder-tab" data-bs-toggle="tab" data-bs-target="#reminder-tab-pane" type="button" role="tab" aria-selected="false"><div class="reminderBellDiv" style="display:inline-flex;"><i class="reminderBell bi bi-bell me-2"></i></div>@translator.Translate(userLanguage, "Reminders")</button>
</li> </li>
<li class="nav-item dropdown ms-auto" role="presentation"> <li class="nav-item dropdown ms-auto" role="presentation">
<a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#" role="button" aria-expanded="false">Manage Vehicle</a> <a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#" role="button" aria-expanded="false">@translator.Translate(userLanguage, "Manage Vehicle")</a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><button onclick="deleteVehicle(@Model.Id)" class="dropdown-item"><i class="bi bi-trash me-2"></i>Delete Vehicle</button></li> <li><button onclick="deleteVehicle(@Model.Id)" class="dropdown-item"><i class="bi bi-trash me-2"></i>@translator.Translate(userLanguage, "Delete Vehicle")</button></li>
</ul> </ul>
</li> </li>
</ul> </ul>

View File

@@ -1,6 +1,13 @@
@model ImportMode @using CarCareTracker.Helper
@inject IConfigHelper config
@inject ITranslationHelper translator
@{
var userConfig = config.GetUserConfig(User);
var userLanguage = userConfig.UserLanguage;
}
@model ImportMode
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title">Import Data from CSV</h5> <h5 class="modal-title">@translator.Translate(userLanguage, "Import Data from CSV")</h5>
<button type="button" class="btn-close" onclick="hideBulkImportModal()" aria-label="Close"></button> <button type="button" class="btn-close" onclick="hideBulkImportModal()" aria-label="Close"></button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
@@ -9,37 +16,40 @@
<div class="form-group"> <div class="form-group">
<div class="col-12"> <div class="col-12">
<div class="alert alert-warning" role="alert"> <div class="alert alert-warning" role="alert">
In order for this utility to function properly, your CSV file MUST be formatted exactly like the provided sample. @translator.Translate(userLanguage, "In order for this utility to function properly, your CSV file MUST be formatted exactly like the provided sample. Dates must be supplied in a string. Numbers must be supplied as numbers without currency formatting.")
Dates must be supplied in a string.
Numbers must be supplied as numbers without currency formatting.
</div> </div>
<div class="alert alert-danger" role="alert"> <div class="alert alert-danger" role="alert">
Failure to format the data correctly can cause data corruption. Please make sure you make a copy of the local database before proceeding. @translator.Translate(userLanguage, "Failure to format the data correctly can cause data corruption. Please make sure you make a copy of the local database before proceeding.")
</div> </div>
@if (Model == ImportMode.GasRecord) @if (Model == ImportMode.GasRecord)
{ {
<a class="btn btn-link" href="/defaults/gassample.csv" target="_blank">Download Sample</a> <a class="btn btn-link" href="/defaults/gassample.csv" target="_blank">@translator.Translate(userLanguage, "Download Sample")</a>
} else if (Model == ImportMode.ServiceRecord || Model == ImportMode.RepairRecord || Model == ImportMode.UpgradeRecord) }
else if (Model == ImportMode.ServiceRecord || Model == ImportMode.RepairRecord || Model == ImportMode.UpgradeRecord)
{ {
<a class="btn btn-link" href="/defaults/servicerecordsample.csv" target="_blank">Download Sample</a> <a class="btn btn-link" href="/defaults/servicerecordsample.csv" target="_blank">@translator.Translate(userLanguage, "Download Sample")</a>
} else if (Model == ImportMode.TaxRecord) }
else if (Model == ImportMode.TaxRecord)
{ {
<a class="btn btn-link" href="/defaults/taxrecordsample.csv" target="_blank">Download Sample</a> <a class="btn btn-link" href="/defaults/taxrecordsample.csv" target="_blank">@translator.Translate(userLanguage, "Download Sample")</a>
} else if (Model == ImportMode.SupplyRecord) }
else if (Model == ImportMode.SupplyRecord)
{ {
<a class="btn btn-link" href="/defaults/supplysample.csv" target="_blank">Download Sample</a> <a class="btn btn-link" href="/defaults/supplysample.csv" target="_blank">@translator.Translate(userLanguage, "Download Sample")</a>
} else if (Model == ImportMode.PlanRecord) }
else if (Model == ImportMode.PlanRecord)
{ {
<a class="btn btn-link" href="/defaults/plansample.csv" target="_blank">Download Sample</a> <a class="btn btn-link" href="/defaults/plansample.csv" target="_blank">@translator.Translate(userLanguage, "Download Sample")</a>
} else if (Model == ImportMode.OdometerRecord) }
else if (Model == ImportMode.OdometerRecord)
{ {
<a class="btn btn-link" href="/defaults/odometersample.csv" target="_blank">Download Sample</a> <a class="btn btn-link" href="/defaults/odometersample.csv" target="_blank">@translator.Translate(userLanguage, "Download Sample")</a>
} }
</div> </div>
</div> </div>
<div class="row mt-2"> <div class="row mt-2">
<div class="col-12"> <div class="col-12">
<label for="csvFileUploader">Upload CSV File</label> <label for="csvFileUploader">@translator.Translate(userLanguage, "Upload CSV File")</label>
<input onChange="uploadFileAsync(this)" type="file" multiple accept=".csv" class="form-control-file" id="csvFileUploader"> <input onChange="uploadFileAsync(this)" type="file" multiple accept=".csv" class="form-control-file" id="csvFileUploader">
</div> </div>
</div> </div>
@@ -47,8 +57,8 @@
</form> </form>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-secondary" onclick="hideBulkImportModal()">Cancel</button> <button type="button" class="btn btn-secondary" onclick="hideBulkImportModal()">@translator.Translate(userLanguage, "Cancel")</button>
<button type="button" onclick="importFromCsv()" class="btn btn-primary">Import</button> <button type="button" onclick="importFromCsv()" class="btn btn-primary">@translator.Translate(userLanguage, "Import")</button>
</div> </div>
<script> <script>
var uploadedFile = ""; var uploadedFile = "";
@@ -73,7 +83,7 @@
getVehicleUpgradeRecords(vehicleId); getVehicleUpgradeRecords(vehicleId);
} else if (mode == "SupplyRecord") { } else if (mode == "SupplyRecord") {
getVehicleSupplyRecords(vehicleId); getVehicleSupplyRecords(vehicleId);
} else if (mode == "PlanRecord"){ } else if (mode == "PlanRecord") {
getVehiclePlanRecords(vehicleId); getVehiclePlanRecords(vehicleId);
} else if (mode == "OdometerRecord") { } else if (mode == "OdometerRecord") {
getVehicleOdometerRecords(vehicleId); getVehicleOdometerRecords(vehicleId);

View File

@@ -1,7 +1,14 @@
@model List<UserCollaborator> @using CarCareTracker.Helper
@inject IConfigHelper config
@inject ITranslationHelper translator
@{
var userConfig = config.GetUserConfig(User);
var userLanguage = userConfig.UserLanguage;
}
@model List<UserCollaborator>
<div class="row"> <div class="row">
<div class="col-8"> <div class="col-8">
<span class="lead">Collaborators</span> <span class="lead">@translator.Translate(userLanguage, "Collaborators")</span>
</div> </div>
<div class="col-4"> <div class="col-4">
<button onclick="addCollaborator()" class="btn btn-link btn-sm"><i class="bi bi-person-add"></i></button> <button onclick="addCollaborator()" class="btn btn-link btn-sm"><i class="bi bi-person-add"></i></button>
@@ -11,8 +18,8 @@
<table class="table table-hover"> <table class="table table-hover">
<thead> <thead>
<tr class="d-flex"> <tr class="d-flex">
<th scope="col" class="col-8">Username</th> <th scope="col" class="col-8">@translator.Translate(userLanguage, "Username")</th>
<th scope="col" class="col-4">Delete</th> <th scope="col" class="col-4">@translator.Translate(userLanguage, "Delete")</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>

View File

@@ -1,9 +1,14 @@
@model CollisionRecordInput @using CarCareTracker.Helper
@inject IConfigHelper config
@inject ITranslationHelper translator
@model CollisionRecordInput
@{ @{
var isNew = Model.Id == 0; var isNew = Model.Id == 0;
var userConfig = config.GetUserConfig(User);
var userLanguage = userConfig.UserLanguage;
} }
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title">@(isNew ? "Add New Repair Record" : "Edit Repair Record")</h5> <h5 class="modal-title">@(isNew ? translator.Translate(userLanguage,"Add New Repair Record") : translator.Translate(userLanguage,"Edit Repair Record"))</h5>
<button type="button" class="btn-close" onclick="hideAddCollisionRecordModal()" aria-label="Close"></button> <button type="button" class="btn-close" onclick="hideAddCollisionRecordModal()" aria-label="Close"></button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
@@ -12,22 +17,22 @@
<div class="row"> <div class="row">
<div class="col-md-6 col-12"> <div class="col-md-6 col-12">
<input type="text" id="workAroundInput" style="height:0px; width:0px; display:none;"> <input type="text" id="workAroundInput" style="height:0px; width:0px; display:none;">
<label for="collisionRecordDate">Date</label> <label for="collisionRecordDate">@translator.Translate(userLanguage,"Date")</label>
<div class="input-group"> <div class="input-group">
<input type="text" id="collisionRecordDate" class="form-control" placeholder="Date repair was performed" value="@Model.Date"> <input type="text" id="collisionRecordDate" class="form-control" placeholder="@translator.Translate(userLanguage,"Date repair was performed")" value="@Model.Date">
<span class="input-group-text"><i class="bi bi-calendar-event"></i></span> <span class="input-group-text"><i class="bi bi-calendar-event"></i></span>
</div> </div>
<label for="collisionRecordMileage">Odometer</label> <label for="collisionRecordMileage">@translator.Translate(userLanguage,"Odometer")</label>
<input type="number" id="collisionRecordMileage" class="form-control" placeholder="Odometer reading when repaired" value="@(isNew ? "" : Model.Mileage)"> <input type="number" id="collisionRecordMileage" class="form-control" placeholder="@translator.Translate(userLanguage,"Odometer reading when repaired")" value="@(isNew ? "" : Model.Mileage)">
<label for="collisionRecordDescription">Description</label> <label for="collisionRecordDescription">@translator.Translate(userLanguage,"Description")</label>
<input type="text" id="collisionRecordDescription" class="form-control" placeholder="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">
<label for="collisionRecordCost">Cost</label> <label for="collisionRecordCost">@translator.Translate(userLanguage,"Cost")</label>
<input type="text" id="collisionRecordCost" class="form-control" placeholder="Cost of the repair" value="@(isNew ? "" : Model.Cost)"> <input type="text" id="collisionRecordCost" class="form-control" placeholder="@translator.Translate(userLanguage,"Cost of the repair")" value="@(isNew ? "" : Model.Cost)">
@if (isNew) @if (isNew)
{ {
@await Html.PartialAsync("_SupplyStore", "RepairRecord") @await Html.PartialAsync("_SupplyStore", "RepairRecord")
} }
<label for="collisionRecordTag">Tags(optional)</label> <label for="collisionRecordTag">@translator.Translate(userLanguage,"Tags(optional)")</label>
<select multiple class="form-select" id="collisionRecordTag"> <select multiple class="form-select" id="collisionRecordTag">
@foreach (string tag in Model.Tags) @foreach (string tag in Model.Tags)
{ {
@@ -36,15 +41,15 @@
</select> </select>
</div> </div>
<div class="col-md-6 col-12"> <div class="col-md-6 col-12">
<label for="collisionRecordNotes">Notes(optional)<a class="link-underline link-underline-opacity-0" onclick="showLinks(this)"><i class="bi bi-markdown ms-2"></i></a></label> <label for="collisionRecordNotes">@translator.Translate(userLanguage,"Notes(optional)")<a class="link-underline link-underline-opacity-0" onclick="showLinks(this)"><i class="bi bi-markdown ms-2"></i></a></label>
<textarea id="collisionRecordNotes" class="form-control" rows="5">@Model.Notes</textarea> <textarea id="collisionRecordNotes" class="form-control" rows="5">@Model.Notes</textarea>
@if (Model.Files.Any()) @if (Model.Files.Any())
{ {
<div> <div>
@await Html.PartialAsync("_UploadedFiles", Model.Files) @await Html.PartialAsync("_UploadedFiles", Model.Files)
<label for="collisionRecordFiles">Upload more documents</label> <label for="collisionRecordFiles">@translator.Translate(userLanguage,"Upload more documents")</label>
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="collisionRecordFiles"> <input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="collisionRecordFiles">
<br /><small class="text-body-secondary">Max File Size: 28.6MB</small> <br /><small class="text-body-secondary">@translator.Translate(userLanguage,"Max File Size: 28.6MB")</small>
</div> </div>
} }
else else
@@ -54,13 +59,13 @@
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="addReminderCheck"> <input class="form-check-input" type="checkbox" value="" id="addReminderCheck">
<label class="form-check-label" for="addReminderCheck"> <label class="form-check-label" for="addReminderCheck">
Add Reminder @translator.Translate(userLanguage,"Add Reminder")
</label> </label>
</div> </div>
} }
<label for="collisionRecordFiles">Upload documents(optional)</label> <label for="collisionRecordFiles">@translator.Translate(userLanguage,"Upload documents(optional)")</label>
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="collisionRecordFiles"> <input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="collisionRecordFiles">
<br /><small class="text-body-secondary">Max File Size: 28.6MB</small> <br /><small class="text-body-secondary">@translator.Translate(userLanguage,"Max File Size: 28.6MB")</small>
} }
</div> </div>
</div> </div>
@@ -71,25 +76,25 @@
@if (!isNew) @if (!isNew)
{ {
<div class="btn-group" style="margin-right:auto;"> <div class="btn-group" style="margin-right:auto;">
<button type="button" class="btn btn-md mt-1 mb-1 btn-danger" onclick="deleteCollisionRecord(@Model.Id)">Delete</button> <button type="button" class="btn btn-md mt-1 mb-1 btn-danger" onclick="deleteCollisionRecord(@Model.Id)">@translator.Translate(userLanguage,"Delete")</button>
<button type="button" class="btn btn-md btn-danger 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-danger 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><h6 class="dropdown-header">Move To</h6></li> <li><h6 class="dropdown-header">@translator.Translate(userLanguage,"Move To")</h6></li>
<li><a class="dropdown-item" href="#" onclick="moveRecord(@Model.Id, 'RepairRecord', 'ServiceRecord')">Service Records</a></li> <li><a class="dropdown-item" href="#" onclick="moveRecord(@Model.Id, 'RepairRecord', 'ServiceRecord')">@translator.Translate(userLanguage,"Service Records")</a></li>
<li><a class="dropdown-item" href="#" onclick="moveRecord(@Model.Id, 'RepairRecord', 'UpgradeRecord')">Upgrades</a></li> <li><a class="dropdown-item" href="#" onclick="moveRecord(@Model.Id, 'RepairRecord', 'UpgradeRecord')">@translator.Translate(userLanguage,"Upgrades")</a></li>
</ul> </ul>
</div> </div>
} }
<button type="button" class="btn btn-secondary" onclick="hideAddCollisionRecordModal()">Cancel</button> <button type="button" class="btn btn-secondary" onclick="hideAddCollisionRecordModal()">@translator.Translate(userLanguage,"Cancel")</button>
@if (isNew) @if (isNew)
{ {
<button type="button" class="btn btn-primary" onclick="saveCollisionRecordToVehicle()">Add New Repair Record</button> <button type="button" class="btn btn-primary" onclick="saveCollisionRecordToVehicle()">@translator.Translate(userLanguage,"Add New Repair Record")</button>
} }
else if (!isNew) else if (!isNew)
{ {
<button type="button" class="btn btn-primary" onclick="saveCollisionRecordToVehicle(true)">Edit Repair Record</button> <button type="button" class="btn btn-primary" onclick="saveCollisionRecordToVehicle(true)">@translator.Translate(userLanguage,"Edit Repair Record")</button>
} }
</div> </div>
<script> <script>

View File

@@ -1,16 +1,19 @@
@using CarCareTracker.Helper @using CarCareTracker.Helper
@inject IConfigHelper config @inject IConfigHelper config
@inject ITranslationHelper translator
@{ @{
var enableCsvImports = config.GetUserConfig(User).EnableCsvImports; var userConfig = config.GetUserConfig(User);
var hideZero = config.GetUserConfig(User).HideZero; var enableCsvImports = userConfig.EnableCsvImports;
var hideZero = userConfig.HideZero;
var recordTags = Model.SelectMany(x => x.Tags).Distinct(); var recordTags = Model.SelectMany(x => x.Tags).Distinct();
var userLanguage = userConfig.UserLanguage;
} }
@model List<CollisionRecord> @model List<CollisionRecord>
<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">@($"# of Repair Records: {Model.Count()}")</span> <span class="ms-2 badge bg-success" data-aggregate-type="count">@($"{translator.Translate(userLanguage,"# of Repair Records")}: {Model.Count()}")</span>
<span class="ms-2 badge bg-primary" data-aggregate-type="sum">@($"Total: {Model.Sum(x => x.Cost).ToString("C")}")</span> <span class="ms-2 badge bg-primary" data-aggregate-type="sum">@($"{translator.Translate(userLanguage,"Total")}: {Model.Sum(x => x.Cost).ToString("C")}")</span>
@foreach (string recordTag in recordTags) @foreach (string recordTag in recordTags)
{ {
<span onclick="filterTable('accident-tab-pane', this)" class="user-select-none ms-2 rounded-pill badge bg-secondary tagfilter" style="cursor:pointer;">@recordTag</span> <span onclick="filterTable('accident-tab-pane', this)" class="user-select-none ms-2 rounded-pill badge bg-secondary tagfilter" style="cursor:pointer;">@recordTag</span>
@@ -26,21 +29,21 @@
@if (enableCsvImports) @if (enableCsvImports)
{ {
<div class="btn-group"> <div class="btn-group">
<button onclick="showAddCollisionRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>Add Repair Record</button> <button onclick="showAddCollisionRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>@translator.Translate(userLanguage,"Add Repair 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('RepairRecord')">Import via CSV</a></li> <li><a class="dropdown-item" href="#" onclick="showBulkImportModal('RepairRecord')">@translator.Translate(userLanguage,"Import via CSV")</a></li>
<li><a class="dropdown-item" href="#" onclick="exportVehicleData('RepairRecord')">Export to CSV</a></li> <li><a class="dropdown-item" href="#" onclick="exportVehicleData('RepairRecord')">@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()">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="showAddCollisionRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>Add Repair Record</button> <button onclick="showAddCollisionRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>@translator.Translate(userLanguage,"Add Repair Record")</button>
} }
</div> </div>
</div> </div>
@@ -55,11 +58,11 @@
<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">Date</th> <th scope="col" class="col-2 col-xl-1">@translator.Translate(userLanguage,"Date")</th>
<th scope="col" class="col-2">Odometer</th> <th scope="col" class="col-2">@translator.Translate(userLanguage,"Odometer")</th>
<th scope="col" class="col-3 col-xl-4">Description</th> <th scope="col" class="col-3 col-xl-4">@translator.Translate(userLanguage,"Description")</th>
<th scope="col" class="col-2" onclick="toggleSort('accident-tab-pane', this)" style="cursor:pointer;">Cost</th> <th scope="col" class="col-2" onclick="toggleSort('accident-tab-pane', this)" style="cursor:pointer;">@translator.Translate(userLanguage,"Cost")</th>
<th scope="col" class="col-3">Notes</th> <th scope="col" class="col-3">@translator.Translate(userLanguage,"Notes")</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>

View File

@@ -1,4 +1,11 @@
@model CostMakeUpForVehicle @using CarCareTracker.Helper
@inject IConfigHelper config
@inject ITranslationHelper translator
@{
var userConfig = config.GetUserConfig(User);
var userLanguage = userConfig.UserLanguage;
}
@model CostMakeUpForVehicle
@if (Model.CollisionRecordSum + Model.ServiceRecordSum + Model.GasRecordSum + Model.TaxRecordSum + Model.UpgradeRecordSum > 0) @if (Model.CollisionRecordSum + Model.ServiceRecordSum + Model.GasRecordSum + Model.TaxRecordSum + Model.UpgradeRecordSum > 0)
{ {
<canvas id="pie-chart"></canvas> <canvas id="pie-chart"></canvas>
@@ -9,10 +16,14 @@
new Chart($("#pie-chart"), { new Chart($("#pie-chart"), {
type: 'pie', type: 'pie',
data: { data: {
labels: ["Service Records", "Repairs", "Upgrades", "Tax", "Fuel"], labels: [decodeHTMLEntities('@translator.Translate(userLanguage, "Service Records")'),
decodeHTMLEntities('@translator.Translate(userLanguage, "Repairs")'),
decodeHTMLEntities('@translator.Translate(userLanguage, "Upgrades")'),
decodeHTMLEntities('@translator.Translate(userLanguage, "Tax")'),
decodeHTMLEntities('@translator.Translate(userLanguage, "Fuel")')],
datasets: [ datasets: [
{ {
label: "Expenses by Type", label: decodeHTMLEntities('@translator.Translate(userLanguage, "Expenses by Type")'),
backgroundColor: ["#003f5c", "#58508d", "#bc5090", "#ff6361", "#ffa600"], backgroundColor: ["#003f5c", "#58508d", "#bc5090", "#ff6361", "#ffa600"],
data: [ data: [
globalParseFloat('@Model.ServiceRecordSum'), globalParseFloat('@Model.ServiceRecordSum'),
@@ -20,7 +31,7 @@
globalParseFloat('@Model.UpgradeRecordSum'), globalParseFloat('@Model.UpgradeRecordSum'),
globalParseFloat('@Model.TaxRecordSum'), globalParseFloat('@Model.TaxRecordSum'),
globalParseFloat('@Model.GasRecordSum') globalParseFloat('@Model.GasRecordSum')
] ]
} }
] ]
}, },
@@ -34,7 +45,7 @@
}, },
title: { title: {
display: true, display: true,
text: "Expenses by Type", text: decodeHTMLEntities('@translator.Translate(userLanguage, "Expenses by Type")'),
color: useDarkMode ? "#fff" : "#000" color: useDarkMode ? "#fff" : "#000"
}, },
} }
@@ -46,6 +57,6 @@
else else
{ {
<div class="text-center"> <div class="text-center">
<h4>No data found or all records have zero sums, insert records with non-zero sums to see visualizations here.</h4> <h4>@translator.Translate(userLanguage, "No data found or all records have zero sums, insert records with non-zero sums to see visualizations here.")</h4>
</div> </div>
} }

View File

@@ -1,6 +1,7 @@
@using CarCareTracker.Helper @using CarCareTracker.Helper
@inject IConfigHelper config @inject IConfigHelper config
@inject IGasHelper gasHelper @inject IGasHelper gasHelper
@inject ITranslationHelper translator
@model GasRecordViewModelContainer @model GasRecordViewModelContainer
@{ @{
var userConfig = config.GetUserConfig(User); var userConfig = config.GetUserConfig(User);
@@ -10,6 +11,7 @@
var hideZero = userConfig.HideZero; var hideZero = userConfig.HideZero;
var useThreeDecimals = userConfig.UseThreeDecimalGasCost; var useThreeDecimals = userConfig.UseThreeDecimalGasCost;
var gasCostFormat = useThreeDecimals ? "C3" : "C2"; var gasCostFormat = useThreeDecimals ? "C3" : "C2";
var userLanguage = userConfig.UserLanguage;
var useKwh = Model.UseKwh; var useKwh = Model.UseKwh;
var useHours = Model.UseHours; var useHours = Model.UseHours;
var recordTags = Model.GasRecords.SelectMany(x => x.Tags).Distinct(); var recordTags = Model.GasRecords.SelectMany(x => x.Tags).Distinct();
@@ -42,22 +44,22 @@
<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">@($"# of Gas Records: {Model.GasRecords.Count()}")</span> <span class="ms-2 badge bg-success" data-aggregate-type="count">@($"{translator.Translate(userLanguage,"# of Gas Records")}: {Model.GasRecords.Count()}")</span>
@if (Model.GasRecords.Where(x => x.MilesPerGallon > 0).Any()) @if (Model.GasRecords.Where(x => x.MilesPerGallon > 0).Any())
{ {
<span class="ms-2 badge bg-primary" id="averageFuelMileageLabel">@($"Average Fuel Economy: {gasHelper.GetAverageGasMileage(Model.GasRecords, useMPG)}")</span> <span class="ms-2 badge bg-primary" id="averageFuelMileageLabel">@($"{translator.Translate(userLanguage,"Average Fuel Economy")}: {gasHelper.GetAverageGasMileage(Model.GasRecords, useMPG)}")</span>
if (useMPG) if (useMPG)
{ {
<span class="ms-2 badge bg-primary" id="minFuelMileageLabel">@($"Min Fuel Economy: {Model.GasRecords.Where(y => y.MilesPerGallon > 0)?.Min(x => x.MilesPerGallon).ToString("F") ?? "0"}")</span> <span class="ms-2 badge bg-primary" id="minFuelMileageLabel">@($"{translator.Translate(userLanguage,"Min Fuel Economy")}: {Model.GasRecords.Where(y => y.MilesPerGallon > 0)?.Min(x => x.MilesPerGallon).ToString("F") ?? "0"}")</span>
<span class="ms-2 badge bg-primary" id="maxFuelMileageLabel">@($"Max Fuel Economy: {Model.GasRecords.Max(x => x.MilesPerGallon).ToString("F") ?? "0"}")</span> <span class="ms-2 badge bg-primary" id="maxFuelMileageLabel">@($"{translator.Translate(userLanguage,"Max Fuel Economy")}: {Model.GasRecords.Max(x => x.MilesPerGallon).ToString("F") ?? "0"}")</span>
} else } else
{ {
<span class="ms-2 badge bg-primary" id="minFuelMileageLabel">@($"Min Fuel Economy: {Model.GasRecords.Max(x => x.MilesPerGallon).ToString("F") ?? "0"}")</span> <span class="ms-2 badge bg-primary" id="minFuelMileageLabel">@($"{translator.Translate(userLanguage,"Min Fuel Economy")}: {Model.GasRecords.Max(x => x.MilesPerGallon).ToString("F") ?? "0"}")</span>
<span class="ms-2 badge bg-primary" id="maxFuelMileageLabel">@($"Max Fuel Economy: {Model.GasRecords.Where(y => y.MilesPerGallon > 0)?.Min(x => x.MilesPerGallon).ToString("F") ?? "0"}")</span> <span class="ms-2 badge bg-primary" id="maxFuelMileageLabel">@($"{translator.Translate(userLanguage,"Max Fuel Economy")}: {Model.GasRecords.Where(y => y.MilesPerGallon > 0)?.Min(x => x.MilesPerGallon).ToString("F") ?? "0"}")</span>
} }
} }
<span class="ms-2 badge bg-success">@($"Total Fuel Consumed: {Model.GasRecords.Sum(x => x.Gallons).ToString("F")}")</span> <span class="ms-2 badge bg-success">@($"{translator.Translate(userLanguage,"Total Fuel Consumed")}: {Model.GasRecords.Sum(x => x.Gallons).ToString("F")}")</span>
<span class="ms-2 badge bg-success" data-aggregate-type="sum">@($"Total Cost: {Model.GasRecords.Sum(x => x.Cost).ToString(gasCostFormat)}")</span> <span class="ms-2 badge bg-success" data-aggregate-type="sum">@($"{translator.Translate(userLanguage,"Total Cost")}: {Model.GasRecords.Sum(x => x.Cost).ToString(gasCostFormat)}")</span>
@foreach (string recordTag in recordTags) @foreach (string recordTag in recordTags)
{ {
<span onclick="toggleGasFilter(this)" class="user-select-none ms-2 rounded-pill badge bg-secondary tagfilter" style="cursor:pointer;">@recordTag</span> <span onclick="toggleGasFilter(this)" class="user-select-none ms-2 rounded-pill badge bg-secondary tagfilter" style="cursor:pointer;">@recordTag</span>
@@ -72,19 +74,19 @@
@if (enableCsvImports) @if (enableCsvImports)
{ {
<div class="btn-group"> <div class="btn-group">
<button onclick="showAddGasRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>Add Gas Record</button> <button onclick="showAddGasRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>@translator.Translate(userLanguage,"Add Gas 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('GasRecord')">Import via CSV</a></li> <li><a class="dropdown-item" href="#" onclick="showBulkImportModal('GasRecord')">@translator.Translate(userLanguage,"Import via CSV")</a></li>
<li><a class="dropdown-item" href="#" onclick="exportVehicleData('GasRecord')">Export to CSV</a></li> <li><a class="dropdown-item" href="#" onclick="exportVehicleData('GasRecord')">@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()">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="showAddGasRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>Add Gas Record</button> <button onclick="showAddGasRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>@translator.Translate(userLanguage,"Add Gas Record")</button>
} }
</div> </div>
</div> </div>
@@ -98,12 +100,12 @@
<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">Date Refueled</th> <th scope="col" class="col-2">@translator.Translate(userLanguage,"Date Refueled")</th>
<th scope="col" class="col-2">Odometer(@(distanceUnit))</th> <th scope="col" class="col-2">@($"{translator.Translate(userLanguage,"Odometer")}({distanceUnit})")</th>
<th scope="col" class="col-2" data-gas="consumption" data-unit="@consumptionUnit" onclick="toggleSort('gas-tab-pane', this)" oncontextmenu="toggleUnits(this)" style="cursor:pointer;">Consumption(@(consumptionUnit))</th> <th scope="col" class="col-2" data-gas="consumption" data-unit="@consumptionUnit" onclick="toggleSort('gas-tab-pane', this)" oncontextmenu="toggleUnits(this)" style="cursor:pointer;">@($"{translator.Translate(userLanguage,"Consumption")}({consumptionUnit})")</th>
<th scope="col" class="col-4" data-gas="fueleconomy" data-unit="@fuelEconomyUnit" onclick="toggleSort('gas-tab-pane', this)" oncontextmenu="toggleUnits(this)" style="cursor:pointer;">Fuel Economy(@(fuelEconomyUnit))</th> <th scope="col" class="col-4" data-gas="fueleconomy" data-unit="@fuelEconomyUnit" onclick="toggleSort('gas-tab-pane', this)" oncontextmenu="toggleUnits(this)" style="cursor:pointer;">@($"{@translator.Translate(userLanguage,"Fuel Economy")}({fuelEconomyUnit})")</th>
<th scope="col" class="col-1" onclick="toggleSort('gas-tab-pane', this)" style="cursor:pointer;">Cost</th> <th scope="col" class="col-1" onclick="toggleSort('gas-tab-pane', this)" style="cursor:pointer;">@translator.Translate(userLanguage,"Cost")</th>
<th scope="col" class="col-1" onclick="toggleSort('gas-tab-pane', this)" style="cursor:pointer;">Unit Cost</th> <th scope="col" class="col-1" onclick="toggleSort('gas-tab-pane', this)" style="cursor:pointer;">@translator.Translate(userLanguage,"Unit Cost")</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>

View File

@@ -1,5 +1,10 @@
@model List<CostForVehicleByMonth> @using CarCareTracker.Helper
@inject IConfigHelper config
@inject ITranslationHelper translator
@model List<CostForVehicleByMonth>
@{ @{
var userConfig = config.GetUserConfig(User);
var userLanguage = userConfig.UserLanguage;
var barGraphColors = new string[] { "#00876c", "#43956e", "#67a371", "#89b177", "#a9be80", "#c8cb8b", "#e6d79b", "#e4c281", "#e3ab6b", "#e2925b", "#e07952", "#db5d4f" }; var barGraphColors = new string[] { "#00876c", "#43956e", "#67a371", "#89b177", "#a9be80", "#c8cb8b", "#e6d79b", "#e4c281", "#e3ab6b", "#e2925b", "#e07952", "#db5d4f" };
var sortedByMPG = Model.OrderBy(x => x.Cost).ToList(); var sortedByMPG = Model.OrderBy(x => x.Cost).ToList();
} }
@@ -27,7 +32,7 @@
labels: barGraphLabels, labels: barGraphLabels,
datasets: [ datasets: [
{ {
label: "Expenses by Month", label: decodeHTMLEntities('@translator.Translate(userLanguage, "Expenses by Month")'),
backgroundColor: barGraphColors, backgroundColor: barGraphColors,
data: barGraphData data: barGraphData
} }
@@ -38,7 +43,7 @@
title: { title: {
display: true, display: true,
color: useDarkMode ? "#fff" : "#000", color: useDarkMode ? "#fff" : "#000",
text: 'Expenses by Month' text: decodeHTMLEntities('@translator.Translate(userLanguage, "Expenses by Month")')
}, },
legend: { legend: {
display: false, display: false,
@@ -67,6 +72,6 @@
} else } else
{ {
<div class="text-center"> <div class="text-center">
<h4>No data found, insert/select some data to see visualizations here.</h4> <h4>@translator.Translate(userLanguage,"No data found, insert/select some data to see visualizations here.")</h4>
</div> </div>
} }

View File

@@ -1,9 +1,12 @@
@using CarCareTracker.Helper @using CarCareTracker.Helper
@inject IConfigHelper config @inject IConfigHelper config
@inject ITranslationHelper translator
@model GasRecordInputContainer @model GasRecordInputContainer
@{ @{
var useMPG = config.GetUserConfig(User).UseMPG; var userConfig = config.GetUserConfig(User);
var useUKMPG = config.GetUserConfig(User).UseUKMPG; var useMPG = userConfig.UseMPG;
var useUKMPG = userConfig.UseUKMPG;
var userLanguage = userConfig.UserLanguage;
var useKwh = Model.UseKwh; var useKwh = Model.UseKwh;
var useHours = Model.UseHours; var useHours = Model.UseHours;
var isNew = Model.GasRecord.Id == 0; var isNew = Model.GasRecord.Id == 0;
@@ -34,7 +37,7 @@
} }
} }
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title">@(isNew ? "Add New Gas Record" : "Edit Gas Record")</h5> <h5 class="modal-title">@(isNew ? translator.Translate(userLanguage,"Add New Gas Record") : translator.Translate(userLanguage,"Edit Gas Record"))</h5>
<button type="button" class="btn-close" onclick="hideAddGasRecordModal()" aria-label="Close"></button> <button type="button" class="btn-close" onclick="hideAddGasRecordModal()" aria-label="Close"></button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
@@ -43,40 +46,40 @@
<div class="row"> <div class="row">
<div class="col-md-6 col-12"> <div class="col-md-6 col-12">
<input type="text" id="workAroundInput" style="height:0px; width:0px; display:none;"> <input type="text" id="workAroundInput" style="height:0px; width:0px; display:none;">
<label for="gasRecordDate">Date</label> <label for="gasRecordDate">@translator.Translate(userLanguage,"Date")</label>
<div class="input-group"> <div class="input-group">
<input type="text" id="gasRecordDate" placeholder="Date refueled" class="form-control" value="@Model.GasRecord.Date"> <input type="text" id="gasRecordDate" placeholder="@translator.Translate(userLanguage,"Date refueled")" class="form-control" value="@Model.GasRecord.Date">
<span class="input-group-text"><i class="bi bi-calendar-event"></i></span> <span class="input-group-text"><i class="bi bi-calendar-event"></i></span>
</div> </div>
<label for="gasRecordMileage">Odometer Reading(@distanceUnit)</label> <label for="gasRecordMileage">@($"{translator.Translate(userLanguage,"Odometer Reading")}({distanceUnit})")</label>
<input type="number" id="gasRecordMileage" class="form-control" placeholder="Odometer reading when refueled" value="@(isNew ? "" : Model.GasRecord.Mileage)"> <input type="number" id="gasRecordMileage" class="form-control" placeholder="@translator.Translate(userLanguage,"Odometer reading when refueled")" value="@(isNew ? "" : Model.GasRecord.Mileage)">
<label for="gasRecordGallons">Fuel Consumption(@(consumptionUnit))</label> <label for="gasRecordGallons">@($"{translator.Translate(userLanguage, "Fuel Consumption")}({consumptionUnit})")</label>
<input type="text" id="gasRecordGallons" class="form-control" placeholder="Amount of gas refueled" value="@(isNew ? "" : Model.GasRecord.Gallons)"> <input type="text" id="gasRecordGallons" class="form-control" placeholder="@translator.Translate(userLanguage,"Amount of gas refueled")" value="@(isNew ? "" : Model.GasRecord.Gallons)">
<div class="form-check form-switch"> <div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="gasIsFillToFull" checked="@Model.GasRecord.IsFillToFull"> <input class="form-check-input" type="checkbox" role="switch" id="gasIsFillToFull" checked="@Model.GasRecord.IsFillToFull">
<label class="form-check-label" for="gasIsFillToFull">Is Filled To Full</label> <label class="form-check-label" for="gasIsFillToFull">@translator.Translate(userLanguage,"Is Filled To Full")</label>
</div> </div>
<div class="form-check form-switch"> <div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="gasIsMissed" checked="@Model.GasRecord.MissedFuelUp"> <input class="form-check-input" type="checkbox" role="switch" id="gasIsMissed" checked="@Model.GasRecord.MissedFuelUp">
<label class="form-check-label" for="gasIsMissed">Missed Fuel Up(Skip MPG Calculation)</label> <label class="form-check-label" for="gasIsMissed">@translator.Translate(userLanguage,"Missed Fuel Up(Skip MPG Calculation)")</label>
</div> </div>
<label for="GasRecordCost">Cost</label> <label for="GasRecordCost">@translator.Translate(userLanguage,"Cost")</label>
@if (isNew) @if (isNew)
{ {
<div class="input-group"> <div class="input-group">
<input type="text" id="gasRecordCost" class="form-control" placeholder="Cost of gas refueled" value="@(isNew ? "" : Model.GasRecord.Cost)"> <input type="text" id="gasRecordCost" class="form-control" placeholder="@translator.Translate(userLanguage,"Cost of gas refueled")" value="@(isNew ? "" : Model.GasRecord.Cost)">
<div class="input-group-text"> <div class="input-group-text">
<select class="form-select form-select-sm" id="gasCostType"> <select class="form-select form-select-sm" id="gasCostType">
<option value="total">Total</option> <option value="total">@translator.Translate(userLanguage,"Total")</option>
<option value="unit">Unit</option> <option value="unit">@translator.Translate(userLanguage,"Unit")</option>
</select> </select>
</div> </div>
</div> </div>
} else } else
{ {
<input type="text" id="gasRecordCost" class="form-control" placeholder="Cost of gas refueled" value="@(isNew ? "" : Model.GasRecord.Cost)"> <input type="text" id="gasRecordCost" class="form-control" placeholder="@translator.Translate(userLanguage,"Cost of gas refueled")" value="@(isNew ? "" : Model.GasRecord.Cost)">
} }
<label for="gasRecordTag">Tags(optional)</label> <label for="gasRecordTag">@translator.Translate(userLanguage,"Tags(optional)")</label>
<select multiple class="form-select" id="gasRecordTag"> <select multiple class="form-select" id="gasRecordTag">
@foreach (string tag in Model.GasRecord.Tags) @foreach (string tag in Model.GasRecord.Tags)
{ {
@@ -85,22 +88,22 @@
</select> </select>
</div> </div>
<div class="col-md-6 col-12"> <div class="col-md-6 col-12">
<label for="gasRecordNotes">Notes(optional)<a class="link-underline link-underline-opacity-0" onclick="showLinks(this)"><i class="bi bi-markdown ms-2"></i></a></label> <label for="gasRecordNotes">@translator.Translate(userLanguage,"Notes(optional)")<a class="link-underline link-underline-opacity-0" onclick="showLinks(this)"><i class="bi bi-markdown ms-2"></i></a></label>
<textarea id="gasRecordNotes" class="form-control" rows="5">@Model.GasRecord.Notes</textarea> <textarea id="gasRecordNotes" class="form-control" rows="5">@Model.GasRecord.Notes</textarea>
@if (Model.GasRecord.Files.Any()) @if (Model.GasRecord.Files.Any())
{ {
<div> <div>
@await Html.PartialAsync("_UploadedFiles", Model.GasRecord.Files) @await Html.PartialAsync("_UploadedFiles", Model.GasRecord.Files)
<label for="gasRecordFiles">Upload more documents</label> <label for="gasRecordFiles">@translator.Translate(userLanguage,"Upload more documents")</label>
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="gasRecordFiles"> <input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="gasRecordFiles">
<br /><small class="text-body-secondary">Max File Size: 28.6MB</small> <br /><small class="text-body-secondary">@translator.Translate(userLanguage,"Max File Size: 28.6MB")</small>
</div> </div>
} }
else else
{ {
<label for="gasRecordFiles">Upload documents(optional)</label> <label for="gasRecordFiles">@translator.Translate(userLanguage,"Upload documents(optional)")</label>
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="gasRecordFiles"> <input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="gasRecordFiles">
<br /><small class="text-body-secondary">Max File Size: 28.6MB</small> <br /><small class="text-body-secondary">@translator.Translate(userLanguage,"Max File Size: 28.6MB")</small>
} }
</div> </div>
</div> </div>
@@ -110,16 +113,16 @@
<div class="modal-footer"> <div class="modal-footer">
@if (!isNew) @if (!isNew)
{ {
<button type="button" class="btn btn-danger" onclick="deleteGasRecord(@Model.GasRecord.Id)" style="margin-right:auto;">Delete</button> <button type="button" class="btn btn-danger" onclick="deleteGasRecord(@Model.GasRecord.Id)" style="margin-right:auto;">@translator.Translate(userLanguage,"Delete")</button>
} }
<button type="button" class="btn btn-secondary" onclick="hideAddGasRecordModal()">Cancel</button> <button type="button" class="btn btn-secondary" onclick="hideAddGasRecordModal()">@translator.Translate(userLanguage,"Cancel")</button>
@if (isNew) @if (isNew)
{ {
<button type="button" class="btn btn-primary" onclick="saveGasRecordToVehicle()">Add New Gas Record</button> <button type="button" class="btn btn-primary" onclick="saveGasRecordToVehicle()">@translator.Translate(userLanguage,"Add New Gas Record")</button>
} }
else if (!isNew) else if (!isNew)
{ {
<button type="button" class="btn btn-primary" onclick="saveGasRecordToVehicle(true)">Edit Gas Record</button> <button type="button" class="btn btn-primary" onclick="saveGasRecordToVehicle(true)">@translator.Translate(userLanguage,"Edit Gas Record")</button>
} }
</div> </div>
<script> <script>

View File

@@ -1,20 +1,25 @@
@model List<CostForVehicleByMonth> @using CarCareTracker.Helper
@inject IConfigHelper config
@inject ITranslationHelper translator
@model List<CostForVehicleByMonth>
@{ @{
var barGraphColors = new string[] { "#00876c", "#43956e", "#67a371", "#89b177", "#a9be80", "#c8cb8b", "#e6d79b", "#e4c281", "#e3ab6b", "#e2925b", "#e07952", "#db5d4f" }; var barGraphColors = new string[] { "#00876c", "#43956e", "#67a371", "#89b177", "#a9be80", "#c8cb8b", "#e6d79b", "#e4c281", "#e3ab6b", "#e2925b", "#e07952", "#db5d4f" };
var sortedByMPG = Model.OrderByDescending(x => x.Cost).ToList(); var sortedByMPG = Model.OrderByDescending(x => x.Cost).ToList();
var userConfig = config.GetUserConfig(User);
var userLanguage = userConfig.UserLanguage;
} }
@if (Model.Where(x=>x.Cost > 0).Any()) @if (Model.Where(x => x.Cost > 0).Any())
{ {
<canvas id="bar-chart-mpg"></canvas> <canvas id="bar-chart-mpg"></canvas>
<script> <script>
renderChart(); renderChart();
function renderChart() { function renderChart() {
var barGraphLabels = []; var barGraphLabels = [];
var barGraphData = []; var barGraphData = [];
//color gradient from high to low //color gradient from high to low
var barGraphColors = []; var barGraphColors = [];
var useDarkMode = getGlobalConfig().useDarkMode; var useDarkMode = getGlobalConfig().useDarkMode;
@foreach (CostForVehicleByMonth gasCost in Model) @foreach (CostForVehicleByMonth gasCost in Model)
{ {
@:barGraphLabels.push(decodeHTMLEntities("@gasCost.MonthName")); @:barGraphLabels.push(decodeHTMLEntities("@gasCost.MonthName"));
@@ -22,13 +27,13 @@
var index = sortedByMPG.FindIndex(x => x.MonthName == gasCost.MonthName); var index = sortedByMPG.FindIndex(x => x.MonthName == gasCost.MonthName);
@:barGraphColors.push('@barGraphColors[index]'); @:barGraphColors.push('@barGraphColors[index]');
} }
new Chart($("#bar-chart-mpg"), { new Chart($("#bar-chart-mpg"), {
type: 'bar', type: 'bar',
data: { data: {
labels: barGraphLabels, labels: barGraphLabels,
datasets: [ datasets: [
{ {
label: "Fuel Mileage by Month", label: decodeHTMLEntities('@translator.Translate(userLanguage, "Fuel Mileage by Month")'),
backgroundColor: barGraphColors, backgroundColor: barGraphColors,
data: barGraphData data: barGraphData
} }
@@ -39,7 +44,7 @@
title: { title: {
display: true, display: true,
color: useDarkMode ? "#fff" : "#000", color: useDarkMode ? "#fff" : "#000",
text: 'Fuel Mileage by Month' text: decodeHTMLEntities('@translator.Translate(userLanguage, "Fuel Mileage by Month")')
}, },
legend: { legend: {
display: false, display: false,
@@ -65,9 +70,10 @@
}); });
} }
</script> </script>
} else }
else
{ {
<div class="text-center"> <div class="text-center">
<h4>No data found, insert/select some data to see visualizations here.</h4> <h4>@translator.Translate(userLanguage,"No data found, insert/select some data to see visualizations here.")</h4>
</div> </div>
} }

View File

@@ -1,9 +1,14 @@
@model Note @using CarCareTracker.Helper
@inject IConfigHelper config
@inject ITranslationHelper translator
@model Note
@{ @{
var isNew = Model.Id == 0; var isNew = Model.Id == 0;
var userConfig = config.GetUserConfig(User);
var userLanguage = userConfig.UserLanguage;
} }
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title">@(isNew ? "Add New Note" : "Edit Note")</h5> <h5 class="modal-title">@(isNew ? translator.Translate(userLanguage, "Add New Note") : translator.Translate(userLanguage, "Edit Note"))</h5>
<button type="button" class="btn-close" onclick="hideAddNoteModal()" aria-label="Close"></button> <button type="button" class="btn-close" onclick="hideAddNoteModal()" aria-label="Close"></button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
@@ -14,17 +19,17 @@
<input type="text" id="workAroundInput" style="height:0px; width:0px; display:none;"> <input type="text" id="workAroundInput" style="height:0px; width:0px; display:none;">
<div class="form-check form-switch"> <div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="noteIsPinned" checked="@Model.Pinned"> <input class="form-check-input" type="checkbox" role="switch" id="noteIsPinned" checked="@Model.Pinned">
<label class="form-check-label" for="noteIsPinned">Pinned</label> <label class="form-check-label" for="noteIsPinned">@translator.Translate(userLanguage,"Pinned")</label>
</div> </div>
<label for="noteDescription">Description</label> <label for="noteDescription">@translator.Translate(userLanguage,"Description")</label>
<input type="text" id="noteDescription" class="form-control" placeholder="Description of the note" value="@(isNew ? "" : Model.Description)"> <input type="text" id="noteDescription" class="form-control" placeholder="@translator.Translate(userLanguage,"Description of the note")" value="@(isNew ? "" : Model.Description)">
</div> </div>
<div class="col-12"> <div class="col-12">
<label for="noteTextArea">Notes<a class="link-underline link-underline-opacity-0" onclick="showLinks(this)"><i class="bi bi-markdown ms-2"></i></a></label> <label for="noteTextArea">@translator.Translate(userLanguage,"Notes")<a class="link-underline link-underline-opacity-0" onclick="showLinks(this)"><i class="bi bi-markdown ms-2"></i></a></label>
<textarea class="form-control vehicleNoteContainer" id="noteTextArea">@Model.NoteText</textarea> <textarea class="form-control vehicleNoteContainer" id="noteTextArea">@Model.NoteText</textarea>
</div> </div>
<div class="col-12"> <div class="col-12">
<label for="noteRecordTag">Tags(optional)</label> <label for="noteRecordTag">@translator.Translate(userLanguage,"Tags(optional)")</label>
<select multiple class="form-select" id="noteRecordTag"> <select multiple class="form-select" id="noteRecordTag">
@foreach (string tag in Model.Tags) @foreach (string tag in Model.Tags)
{ {
@@ -39,16 +44,16 @@
<div class="modal-footer"> <div class="modal-footer">
@if (!isNew) @if (!isNew)
{ {
<button type="button" class="btn btn-danger" onclick="deleteNote(@Model.Id)" style="margin-right:auto;">Delete</button> <button type="button" class="btn btn-danger" onclick="deleteNote(@Model.Id)" style="margin-right:auto;">@translator.Translate(userLanguage,"Delete")</button>
} }
<button type="button" class="btn btn-secondary" onclick="hideAddNoteModal()">Cancel</button> <button type="button" class="btn btn-secondary" onclick="hideAddNoteModal()">@translator.Translate(userLanguage,"Cancel")</button>
@if (isNew) @if (isNew)
{ {
<button type="button" class="btn btn-primary" onclick="saveNoteToVehicle()">Add New Note</button> <button type="button" class="btn btn-primary" onclick="saveNoteToVehicle()">@translator.Translate(userLanguage,"Add New Note")</button>
} }
else if (!isNew) else if (!isNew)
{ {
<button type="button" class="btn btn-primary" onclick="saveNoteToVehicle(true)">Edit Note</button> <button type="button" class="btn btn-primary" onclick="saveNoteToVehicle(true)">@translator.Translate(userLanguage,"Edit Note")</button>
} }
</div> </div>
<script> <script>

View File

@@ -1,11 +1,16 @@
@model List<Note> @using CarCareTracker.Helper
@inject IConfigHelper config
@inject ITranslationHelper translator
@model List<Note>
@{ @{
var recordTags = Model.SelectMany(x => x.Tags).Distinct(); var recordTags = Model.SelectMany(x => x.Tags).Distinct();
var userConfig = config.GetUserConfig(User);
var userLanguage = userConfig.UserLanguage;
} }
<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">@($"# of Notes: {Model.Count()}")</span> <span class="ms-2 badge bg-success" data-aggregate-type="count">@($"{translator.Translate(userLanguage,"# of Notes")}: {Model.Count()}")</span>
@foreach (string recordTag in recordTags) @foreach (string recordTag in recordTags)
{ {
<span onclick="filterTable('notes-tab-pane', this)" class="user-select-none ms-2 rounded-pill badge bg-secondary tagfilter" style="cursor:pointer;">@recordTag</span> <span onclick="filterTable('notes-tab-pane', this)" class="user-select-none ms-2 rounded-pill badge bg-secondary tagfilter" style="cursor:pointer;">@recordTag</span>
@@ -18,7 +23,7 @@
</datalist> </datalist>
</div> </div>
<div> <div>
<button onclick="showAddNoteModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>Add Note</button> <button onclick="showAddNoteModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>@translator.Translate(userLanguage,"Add Note")</button>
</div> </div>
</div> </div>
</div> </div>
@@ -32,8 +37,8 @@
<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-3">Description</th> <th scope="col" class="col-3">@translator.Translate(userLanguage,"Description")</th>
<th scope="col" class="col-9">Note</th> <th scope="col" class="col-9">@translator.Translate(userLanguage,"Note")</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>

View File

@@ -1,9 +1,14 @@
@model OdometerRecordInput @using CarCareTracker.Helper
@inject IConfigHelper config
@inject ITranslationHelper translator
@model OdometerRecordInput
@{ @{
var isNew = Model.Id == 0; var isNew = Model.Id == 0;
var userConfig = config.GetUserConfig(User);
var userLanguage = userConfig.UserLanguage;
} }
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title">@(isNew ? "Add New Odometer Record" : "Edit Odometer Record")</h5> <h5 class="modal-title">@(isNew ? translator.Translate(userLanguage,"Add New Odometer Record") : translator.Translate(userLanguage,"Edit Odometer Record"))</h5>
<button type="button" class="btn-close" onclick="hideAddOdometerRecordModal()" aria-label="Close"></button> <button type="button" class="btn-close" onclick="hideAddOdometerRecordModal()" aria-label="Close"></button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
@@ -12,14 +17,14 @@
<div class="row"> <div class="row">
<div class="col-md-6 col-12"> <div class="col-md-6 col-12">
<input type="text" id="workAroundInput" style="height:0px; width:0px; display:none;"> <input type="text" id="workAroundInput" style="height:0px; width:0px; display:none;">
<label for="odometerRecordDate">Date</label> <label for="odometerRecordDate">@translator.Translate(userLanguage,"Date")</label>
<div class="input-group"> <div class="input-group">
<input type="text" id="odometerRecordDate" class="form-control" placeholder="Date recorded" value="@Model.Date"> <input type="text" id="odometerRecordDate" class="form-control" placeholder="@translator.Translate(userLanguage,"Date recorded")" value="@Model.Date">
<span class="input-group-text"><i class="bi bi-calendar-event"></i></span> <span class="input-group-text"><i class="bi bi-calendar-event"></i></span>
</div> </div>
<label for="odometerRecordMileage">Odometer</label> <label for="odometerRecordMileage">@translator.Translate(userLanguage,"Odometer")</label>
<input type="number" id="odometerRecordMileage" class="form-control" placeholder="Odometer reading" value="@(isNew ? "" : Model.Mileage)"> <input type="number" id="odometerRecordMileage" class="form-control" placeholder="@translator.Translate(userLanguage,"Odometer reading")" value="@(isNew ? "" : Model.Mileage)">
<label for="odometerRecordTag">Tags(optional)</label> <label for="odometerRecordTag">@translator.Translate(userLanguage,"Tags(optional)")</label>
<select multiple class="form-select" id="odometerRecordTag"> <select multiple class="form-select" id="odometerRecordTag">
@foreach (string tag in Model.Tags) @foreach (string tag in Model.Tags)
{ {
@@ -28,22 +33,22 @@
</select> </select>
</div> </div>
<div class="col-md-6 col-12"> <div class="col-md-6 col-12">
<label for="odometerRecordNotes">Notes(optional)<a class="link-underline link-underline-opacity-0" onclick="showLinks(this)"><i class="bi bi-markdown ms-2"></i></a></label> <label for="odometerRecordNotes">@translator.Translate(userLanguage,"Notes(optional)")<a class="link-underline link-underline-opacity-0" onclick="showLinks(this)"><i class="bi bi-markdown ms-2"></i></a></label>
<textarea id="odometerRecordNotes" class="form-control" rows="5">@Model.Notes</textarea> <textarea id="odometerRecordNotes" class="form-control" rows="5">@Model.Notes</textarea>
@if (Model.Files.Any()) @if (Model.Files.Any())
{ {
<div> <div>
@await Html.PartialAsync("_UploadedFiles", Model.Files) @await Html.PartialAsync("_UploadedFiles", Model.Files)
<label for="odometerRecordFiles">Upload more documents</label> <label for="odometerRecordFiles">@translator.Translate(userLanguage,"Upload more documents")</label>
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="odometerRecordFiles"> <input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="odometerRecordFiles">
<br /><small class="text-body-secondary">Max File Size: 28.6MB</small> <br /><small class="text-body-secondary">@translator.Translate(userLanguage,"Max File Size: 28.6MB")</small>
</div> </div>
} }
else else
{ {
<label for="odometerRecordFiles">Upload documents(optional)</label> <label for="odometerRecordFiles">@translator.Translate(userLanguage,"Upload documents(optional)")</label>
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="odometerRecordFiles"> <input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="odometerRecordFiles">
<br /><small class="text-body-secondary">Max File Size: 28.6MB</small> <br /><small class="text-body-secondary">@translator.Translate(userLanguage,"Max File Size: 28.6MB")</small>
} }
</div> </div>
</div> </div>
@@ -53,16 +58,16 @@
<div class="modal-footer"> <div class="modal-footer">
@if (!isNew) @if (!isNew)
{ {
<button type="button" class="btn btn-danger" onclick="deleteOdometerRecord(@Model.Id)" style="margin-right:auto;">Delete</button> <button type="button" class="btn btn-danger" onclick="deleteOdometerRecord(@Model.Id)" style="margin-right:auto;">@translator.Translate(userLanguage,"Delete")</button>
} }
<button type="button" class="btn btn-secondary" onclick="hideAddOdometerRecordModal()">Cancel</button> <button type="button" class="btn btn-secondary" onclick="hideAddOdometerRecordModal()">@translator.Translate(userLanguage,"Cancel")</button>
@if (isNew) @if (isNew)
{ {
<button type="button" class="btn btn-primary" onclick="saveOdometerRecordToVehicle()">Add New Odometer Record</button> <button type="button" class="btn btn-primary" onclick="saveOdometerRecordToVehicle()">@translator.Translate(userLanguage,"Add New Odometer Record")</button>
} }
else if (!isNew) else if (!isNew)
{ {
<button type="button" class="btn btn-primary" onclick="saveOdometerRecordToVehicle(true)">Edit Odometer Record</button> <button type="button" class="btn btn-primary" onclick="saveOdometerRecordToVehicle(true)">@translator.Translate(userLanguage,"Edit Odometer Record")</button>
} }
</div> </div>
<script> <script>

View File

@@ -1,15 +1,18 @@
@using CarCareTracker.Helper @using CarCareTracker.Helper
@inject IConfigHelper config @inject IConfigHelper config
@inject ITranslationHelper translator
@{ @{
var enableCsvImports = config.GetUserConfig(User).EnableCsvImports; var userConfig = config.GetUserConfig(User);
var hideZero = config.GetUserConfig(User).HideZero; var enableCsvImports = userConfig.EnableCsvImports;
var hideZero = userConfig.HideZero;
var recordTags = Model.SelectMany(x => x.Tags).Distinct(); var recordTags = Model.SelectMany(x => x.Tags).Distinct();
var userLanguage = userConfig.UserLanguage;
} }
@model List<OdometerRecord> @model List<OdometerRecord>
<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">@($"# 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>
@@ -25,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>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')">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')">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()">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>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>
@@ -54,9 +57,9 @@
<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">Date</th> <th scope="col" class="col-2 col-xl-1">@translator.Translate(userLanguage,"Date")</th>
<th scope="col" class="col-3">Odometer</th> <th scope="col" class="col-3">@translator.Translate(userLanguage,"Odometer")</th>
<th scope="col" class="col-7 col-xl-8">Notes</th> <th scope="col" class="col-7 col-xl-8">@translator.Translate(userLanguage,"Notes")</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>

View File

@@ -1,9 +1,14 @@
@model PlanRecordInput @using CarCareTracker.Helper
@inject IConfigHelper config
@inject ITranslationHelper translator
@model PlanRecordInput
@{ @{
var isNew = Model.Id == 0; var isNew = Model.Id == 0;
var userConfig = config.GetUserConfig(User);
var userLanguage = userConfig.UserLanguage;
} }
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title">@(isNew ? "Add New Plan Record" : "Edit Plan Record")</h5> <h5 class="modal-title">@(isNew ? translator.Translate(userLanguage, "Add New Plan Record") : translator.Translate(userLanguage, "Edit Plan Record"))</h5>
<button type="button" class="btn-close" onclick="hideAddPlanRecordModal()" aria-label="Close"></button> <button type="button" class="btn-close" onclick="hideAddPlanRecordModal()" aria-label="Close"></button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
@@ -12,55 +17,57 @@
<div class="row"> <div class="row">
<div class="col-md-6 col-12"> <div class="col-md-6 col-12">
<input type="text" id="workAroundInput" style="height:0px; width:0px; display:none;"> <input type="text" id="workAroundInput" style="height:0px; width:0px; display:none;">
<label for="planRecordDescription">Description</label> <label for="planRecordDescription">@translator.Translate(userLanguage, "Description")</label>
<input type="text" id="planRecordDescription" class="form-control" placeholder="Describe the Plan" value="@Model.Description"> <input type="text" id="planRecordDescription" class="form-control" placeholder="@translator.Translate(userLanguage, "Describe the Plan")" value="@Model.Description">
<label for="planRecordCost">Cost</label> <label for="planRecordCost">@translator.Translate(userLanguage, "Cost")</label>
<input type="text" id="planRecordCost" class="form-control" placeholder="Cost of the Plan" value="@Model.Cost"> <input type="text" id="planRecordCost" class="form-control" placeholder="@translator.Translate(userLanguage, "Cost of the Plan")" value="@Model.Cost">
@if (isNew) @if (isNew)
{ {
@await Html.PartialAsync("_SupplyStore", "PlanRecord") @await Html.PartialAsync("_SupplyStore", "PlanRecord")
} }
<label for="planRecordType">Type</label> <label for="planRecordType">@translator.Translate(userLanguage, "Type")</label>
<select class="form-select" id="planRecordType"> <select class="form-select" id="planRecordType">
<!option value="ServiceRecord" @(Model.ImportMode == ImportMode.ServiceRecord || isNew ? "selected" : "")>Service</!option> <!option value="ServiceRecord" @(Model.ImportMode == ImportMode.ServiceRecord || isNew ? "selected" : "")>@translator.Translate(userLanguage, "Service")</!option>
<!option value="RepairRecord" @(Model.ImportMode == ImportMode.RepairRecord ? "selected" : "")>Repair</!option> <!option value="RepairRecord" @(Model.ImportMode == ImportMode.RepairRecord ? "selected" : "")>@translator.Translate(userLanguage, "Repair")</!option>
<!option value="UpgradeRecord" @(Model.ImportMode == ImportMode.UpgradeRecord ? "selected" : "")>Upgrade</!option> <!option value="UpgradeRecord" @(Model.ImportMode == ImportMode.UpgradeRecord ? "selected" : "")>@translator.Translate(userLanguage, "Upgrade")</!option>
</select> </select>
<label for="planRecordPriority">Priority</label> <label for="planRecordPriority">@translator.Translate(userLanguage, "Priority")</label>
<select class="form-select" id="planRecordPriority"> <select class="form-select" id="planRecordPriority">
<!option value="Critical" @(Model.Priority == PlanPriority.Critical ? "selected" : "")>Critical</!option> <!option value="Critical" @(Model.Priority == PlanPriority.Critical ? "selected" : "")>@translator.Translate(userLanguage, "Critical")</!option>
<!option value="Normal" @(Model.Priority == PlanPriority.Normal || isNew ? "selected" : "")>Normal</!option> <!option value="Normal" @(Model.Priority == PlanPriority.Normal || isNew ? "selected" : "")>@translator.Translate(userLanguage, "Normal")</!option>
<!option value="Low" @(Model.Priority == PlanPriority.Low ? "selected" : "")>Low</!option> <!option value="Low" @(Model.Priority == PlanPriority.Low ? "selected" : "")>@translator.Translate(userLanguage, "Low")</!option>
</select> </select>
<label for="planRecordProgress">Current Stage</label> <label for="planRecordProgress">@translator.Translate(userLanguage, "Current Stage")</label>
<select class="form-select" id="planRecordProgress"> <select class="form-select" id="planRecordProgress">
<!option value="Backlog" @(Model.Progress == PlanProgress.Backlog ||isNew ? "selected" : "")>Planned</!option> <!option value = "Backlog" @(Model.Progress == PlanProgress.Backlog || isNew ? "selected" : "")>@translator.Translate(userLanguage, "Planned")</!option>
<!option value="InProgress" @(Model.Progress == PlanProgress.InProgress ? "selected" : "")>Doing</!option> <!option value="InProgress" @(Model.Progress == PlanProgress.InProgress ? "selected" : "")>@translator.Translate(userLanguage, "Doing")</!option>
<!option value="Testing" @(Model.Progress == PlanProgress.Testing ? "selected" : "")>Testing</!option> <!option value = "Testing" @(Model.Progress == PlanProgress.Testing ? "selected" : "")>@translator.Translate(userLanguage, "Testing")</!option>
</select> </select>
@if (!isNew) @if (!isNew)
{ {
<label>Date Created: @Model.DateCreated</label> <label>@($"{translator.Translate(userLanguage, "Date Created")}: {Model.DateCreated}")</label>
<label>Last Modified: @Model.DateModified</label> <label>@($"{translator.Translate(userLanguage, "Last Modified")}: {Model.DateModified}")</label>
} }
</div> </div>
<div class="col-md-6 col-12"> <div class="col-md-6 col-12">
<label for="planRecordNotes">Notes(optional)<a class="link-underline link-underline-opacity-0" onclick="showLinks(this)"><i class="bi bi-markdown ms-2"></i></a></label> <label for="planRecordNotes">@translator.Translate(userLanguage, "Notes(optional)")<a class="link-underline link-underline-opacity-0" onclick="showLinks(this)"><i class="bi bi-markdown ms-2"></i></a></label>
<textarea id="planRecordNotes" class="form-control" rows="5">@Model.Notes</textarea> <textarea id="planRecordNotes" class="form-control" rows="5">@Model.Notes</textarea>
@if (Model.Files.Any()) @if (Model.Files.Any())
{ {
<div> <div>
@await Html.PartialAsync("_UploadedFiles", Model.Files) @await Html.PartialAsync("_UploadedFiles", Model.Files)
<label for="planRecordFiles">Upload more documents</label> <label for="planRecordFiles">@translator.Translate(userLanguage, "Upload more documents")</label>
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="planRecordFiles"> <input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="planRecordFiles">
<br /><small class="text-body-secondary">Max File Size: 28.6MB</small> <br /><small class="text-body-secondary">@translator.Translate(userLanguage, "Max File Size: 28.6MB")</small>
</div> </div>
} }
else else
{ {
<label for="planRecordFiles">Upload documents(optional)</label> <label for="planRecordFiles">@translator.Translate(userLanguage, "Upload documents(optional)")</label>
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="planRecordFiles"> <input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="planRecordFiles">
<br /><small class="text-body-secondary">Max File Size: 28.6MB</small> <br />
<small class="text-body-secondary">@translator.Translate(userLanguage, "Max File Size: 28.6MB")</small>
} }
</div> </div>
</div> </div>
@@ -70,16 +77,16 @@
<div class="modal-footer"> <div class="modal-footer">
@if (!isNew) @if (!isNew)
{ {
<button type="button" class="btn btn-danger" onclick="deletePlanRecord(@Model.Id)" style="margin-right:auto;">Delete</button> <button type="button" class="btn btn-danger" onclick="deletePlanRecord(@Model.Id)" style="margin-right:auto;">@translator.Translate(userLanguage, "Delete")</button>
} }
<button type="button" class="btn btn-secondary" onclick="hideAddPlanRecordModal()">Cancel</button> <button type="button" class="btn btn-secondary" onclick="hideAddPlanRecordModal()">@translator.Translate(userLanguage, "Cancel")</button>
@if (isNew) @if (isNew)
{ {
<button type="button" class="btn btn-primary" onclick="savePlanRecordToVehicle()">Add New Plan Record</button> <button type="button" class="btn btn-primary" onclick="savePlanRecordToVehicle()">@translator.Translate(userLanguage, "Add New Plan Record")</button>
} }
else if (!isNew) else if (!isNew)
{ {
<button type="button" class="btn btn-primary" onclick="savePlanRecordToVehicle(true)">Edit Plan Record</button> <button type="button" class="btn btn-primary" onclick="savePlanRecordToVehicle(true)">@translator.Translate(userLanguage, "Edit Plan Record")</button>
} }
</div> </div>
<script> <script>
@@ -91,7 +98,7 @@
{ {
@:uploadedFiles.push({ name: "@filesUploaded.Name", location: "@filesUploaded.Location" }); @:uploadedFiles.push({ name: "@filesUploaded.Name", location: "@filesUploaded.Location" });
} }
} }
function getPlanRecordModelData() { function getPlanRecordModelData() {
return { return {
id: @Model.Id, id: @Model.Id,

View File

@@ -1,8 +1,11 @@
@using CarCareTracker.Helper @using CarCareTracker.Helper
@inject IConfigHelper config @inject IConfigHelper config
@inject ITranslationHelper translator
@{ @{
var enableCsvImports = config.GetUserConfig(User).EnableCsvImports; var userConfig = config.GetUserConfig(User);
var hideZero = config.GetUserConfig(User).HideZero; var enableCsvImports = userConfig.EnableCsvImports;
var hideZero = userConfig.HideZero;
var userLanguage = userConfig.UserLanguage;
var backLogItems = Model.Where(x => x.Progress == PlanProgress.Backlog).OrderBy(x=>x.Priority); var backLogItems = Model.Where(x => x.Progress == PlanProgress.Backlog).OrderBy(x=>x.Priority);
var inProgressItems = Model.Where(x => x.Progress == PlanProgress.InProgress).OrderBy(x => x.Priority); var inProgressItems = Model.Where(x => x.Progress == PlanProgress.InProgress).OrderBy(x => x.Priority);
var testingItems = Model.Where(x => x.Progress == PlanProgress.Testing).OrderBy(x => x.Priority); var testingItems = Model.Where(x => x.Progress == PlanProgress.Testing).OrderBy(x => x.Priority);
@@ -12,25 +15,25 @@
<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">@($"# of Plan Records: {Model.Count()}")</span> <span class="ms-2 badge bg-success">@($"{translator.Translate(userLanguage,"# of Plan Records")}: {Model.Count()}")</span>
</div> </div>
<div> <div>
@if (enableCsvImports) @if (enableCsvImports)
{ {
<div class="btn-group"> <div class="btn-group">
<button onclick="showAddPlanRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>Add Plan Record</button> <button onclick="showAddPlanRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>@translator.Translate(userLanguage,"Add Plan Record")</button>
<button type="button" class="btn btn-md btn-primary btn-md mt-1 mb-1 dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false"> <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('PlanRecord')">Import via CSV</a></li> <li><a class="dropdown-item" href="#" onclick="showBulkImportModal('PlanRecord')">@translator.Translate(userLanguage,"Import via CSV")</a></li>
<li><a class="dropdown-item" href="#" onclick="exportVehicleData('PlanRecord')">Export to CSV</a></li> <li><a class="dropdown-item" href="#" onclick="exportVehicleData('PlanRecord')">@translator.Translate(userLanguage,"Export to CSV")</a></li>
</ul> </ul>
</div> </div>
} }
else else
{ {
<button onclick="showAddPlanRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>Add Plan Record</button> <button onclick="showAddPlanRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>@translator.Translate(userLanguage,"Add Plan Record")</button>
} }
</div> </div>
</div> </div>
@@ -46,7 +49,7 @@
<div class="col-3 d-flex flex-column swimlane mid" ondragover="dragOver(event)" ondrop="dropBox(event, 'Backlog')"> <div class="col-3 d-flex flex-column swimlane mid" ondragover="dragOver(event)" ondrop="dropBox(event, 'Backlog')">
<div class="row"> <div class="row">
<div class="col-12 d-flex justify-content-center" style="height:5vh;"> <div class="col-12 d-flex justify-content-center" style="height:5vh;">
<span class="display-7">Planned</span> <span class="display-7">@translator.Translate(userLanguage,"Planned")</span>
</div> </div>
</div> </div>
@foreach (PlanRecord planRecord in backLogItems) @foreach (PlanRecord planRecord in backLogItems)
@@ -57,7 +60,7 @@
<div class="col-3 d-flex flex-column swimlane mid" ondragover="dragOver(event)" ondrop="dropBox(event, 'InProgress')"> <div class="col-3 d-flex flex-column swimlane mid" ondragover="dragOver(event)" ondrop="dropBox(event, 'InProgress')">
<div class="row"> <div class="row">
<div class="col-12 d-flex justify-content-center" style="height:5vh;"> <div class="col-12 d-flex justify-content-center" style="height:5vh;">
<span class="display-7">Doing</span> <span class="display-7">@translator.Translate(userLanguage,"Doing")</span>
</div> </div>
</div> </div>
@foreach (PlanRecord planRecord in inProgressItems) @foreach (PlanRecord planRecord in inProgressItems)
@@ -68,7 +71,7 @@
<div class="col-3 d-flex flex-column swimlane" ondragover="dragOver(event)" ondrop="dropBox(event, 'Testing')"> <div class="col-3 d-flex flex-column swimlane" ondragover="dragOver(event)" ondrop="dropBox(event, 'Testing')">
<div class="row"> <div class="row">
<div class="col-12 d-flex justify-content-center" style="height:5vh;"> <div class="col-12 d-flex justify-content-center" style="height:5vh;">
<span class="display-7">Testing</span> <span class="display-7">@translator.Translate(userLanguage,"Testing")</span>
</div> </div>
</div> </div>
@foreach (PlanRecord planRecord in testingItems) @foreach (PlanRecord planRecord in testingItems)
@@ -79,7 +82,7 @@
<div class="col-3 d-flex flex-column swimlane end" ondragover="dragOver(event)" ondrop="dropBox(event, 'Done')"> <div class="col-3 d-flex flex-column swimlane end" ondragover="dragOver(event)" ondrop="dropBox(event, 'Done')">
<div class="row"> <div class="row">
<div class="col-12 d-flex justify-content-center" style="height:5vh;"> <div class="col-12 d-flex justify-content-center" style="height:5vh;">
<span class="display-7">Done</span> <span class="display-7">@translator.Translate(userLanguage,"Done")</span>
</div> </div>
</div> </div>
@foreach (PlanRecord planRecord in doneItems) @foreach (PlanRecord planRecord in doneItems)

View File

@@ -1,4 +1,11 @@
@model ReminderMakeUpForVehicle @using CarCareTracker.Helper
@inject IConfigHelper config
@inject ITranslationHelper translator
@{
var userConfig = config.GetUserConfig(User);
var userLanguage = userConfig.UserLanguage;
}
@model ReminderMakeUpForVehicle
@if (Model.UrgentCount + Model.VeryUrgentCount + Model.NotUrgentCount + Model.PastDueCount > 0) @if (Model.UrgentCount + Model.VeryUrgentCount + Model.NotUrgentCount + Model.PastDueCount > 0)
{ {
<canvas id="donut-chart"></canvas> <canvas id="donut-chart"></canvas>
@@ -9,10 +16,10 @@
new Chart($("#donut-chart"), { new Chart($("#donut-chart"), {
type: 'doughnut', type: 'doughnut',
data: { data: {
labels: ["Not Urgent", "Urgent", "Very Urgent", "Past Due"], labels: ['@translator.Translate(userLanguage,"Not Urgent")', '@translator.Translate(userLanguage,"Urgent")', '@translator.Translate(userLanguage,"Very Urgent")', '@translator.Translate(userLanguage,"Past Due")'],
datasets: [ datasets: [
{ {
label: "Reminders by Category", label: '@translator.Translate(userLanguage,"Reminders by Category")',
backgroundColor: ["#488f31", "#ffa600", "#de425b", "#cccccc"], backgroundColor: ["#488f31", "#ffa600", "#de425b", "#cccccc"],
data: [ data: [
@Model.NotUrgentCount, @Model.NotUrgentCount,
@@ -33,7 +40,7 @@
}, },
title: { title: {
display: true, display: true,
text: "Reminders by Urgency", text: '@translator.Translate(userLanguage,"Reminders by Urgency")',
color: useDarkMode ? "#fff" : "#000" color: useDarkMode ? "#fff" : "#000"
}, },
} }
@@ -45,6 +52,6 @@
else else
{ {
<div class="text-center"> <div class="text-center">
<h4>No data found, create reminders to see visualizations here.</h4> <h4>@translator.Translate(userLanguage,"No data found, create reminders to see visualizations here.")</h4>
</div> </div>
} }

View File

@@ -1,9 +1,14 @@
@model ReminderRecordInput @using CarCareTracker.Helper
@inject IConfigHelper config
@inject ITranslationHelper translator
@model ReminderRecordInput
@{ @{
var isNew = Model.Id == 0; var isNew = Model.Id == 0;
var userConfig = config.GetUserConfig(User);
var userLanguage = userConfig.UserLanguage;
} }
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title">@(isNew ? "Add New Reminder" : "Edit Reminder")</h5> <h5 class="modal-title">@(isNew ? translator.Translate(userLanguage, "Add New Reminder") : translator.Translate(userLanguage, "Edit Reminder"))</h5>
<button type="button" class="btn-close" onclick="hideAddReminderRecordModal()" aria-label="Close"></button> <button type="button" class="btn-close" onclick="hideAddReminderRecordModal()" aria-label="Close"></button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
@@ -12,42 +17,42 @@
<div class="row"> <div class="row">
<div class="col-md-6 col-12" id="reminderOptions"> <div class="col-md-6 col-12" id="reminderOptions">
<input type="text" id="workAroundInput" style="height:0px; width:0px; display:none;"> <input type="text" id="workAroundInput" style="height:0px; width:0px; display:none;">
<label for="reminderDescription">Description</label> <label for="reminderDescription">@translator.Translate(userLanguage,"Description")</label>
<input type="text" id="reminderDescription" class="form-control" placeholder="Reminder Description" value="@Model.Description"> <input type="text" id="reminderDescription" class="form-control" placeholder="@translator.Translate(userLanguage,"Reminder Description")" value="@Model.Description">
<label>Remind me on:</label> <label>@translator.Translate(userLanguage,"Remind me on")</label>
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="radio" name="reminderMetricOptions" id="reminderMetricDate" value="@(ReminderMetric.Date)" checked="@(Model.Metric == ReminderMetric.Date)"> <input class="form-check-input" type="radio" name="reminderMetricOptions" id="reminderMetricDate" value="@(ReminderMetric.Date)" checked="@(Model.Metric == ReminderMetric.Date)">
<label class="form-check-label" for="reminderMetricDate">Date</label> <label class="form-check-label" for="reminderMetricDate">@translator.Translate(userLanguage,"Date")</label>
</div> </div>
<div class="input-group"> <div class="input-group">
<input type="text" id="reminderDate" class="form-control" placeholder="Future Date" value="@Model.Date"> <input type="text" id="reminderDate" class="form-control" placeholder="@translator.Translate(userLanguage,"Future Date")" value="@Model.Date">
<span class="input-group-text"><i class="bi bi-calendar-event"></i></span> <span class="input-group-text"><i class="bi bi-calendar-event"></i></span>
</div> </div>
<div class="form-check form-check-inline"> <div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="reminderMetricOptions" id="reminderMetricOdometer" value="@(ReminderMetric.Odometer)" checked="@(Model.Metric == ReminderMetric.Odometer)"> <input class="form-check-input" type="radio" name="reminderMetricOptions" id="reminderMetricOdometer" value="@(ReminderMetric.Odometer)" checked="@(Model.Metric == ReminderMetric.Odometer)">
<label class="form-check-label" for="reminderMetricOdometer">Odometer</label> <label class="form-check-label" for="reminderMetricOdometer">@translator.Translate(userLanguage,"Odometer")</label>
</div> </div>
<div class="input-group"> <div class="input-group">
<input type="number" id="reminderMileage" class="form-control" placeholder="Future Odometer Reading" value="@(isNew ? "" : Model.Mileage)"> <input type="number" 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" onclick="appendMileageToOdometer(500)">+500</button>
</div> </div>
</div> </div>
<div class="form-check form-check-inline"> <div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="reminderMetricOptions" id="reminderMetricBoth" value="@(ReminderMetric.Both)" checked="@(Model.Metric == ReminderMetric.Both)"> <input class="form-check-input" type="radio" name="reminderMetricOptions" id="reminderMetricBoth" value="@(ReminderMetric.Both)" checked="@(Model.Metric == ReminderMetric.Both)">
<label class="form-check-label" for="reminderMetricBoth">Whichever comes first</label> <label class="form-check-label" for="reminderMetricBoth">@translator.Translate(userLanguage,"Whichever comes first")</label>
</div> </div>
</div> </div>
<div class="col-md-6 col-12"> <div class="col-md-6 col-12">
<label for="reminderNotes">Notes(optional)<a class="link-underline link-underline-opacity-0" onclick="showLinks(this)"><i class="bi bi-markdown ms-2"></i></a></label> <label for="reminderNotes">@translator.Translate(userLanguage,"Notes(optional)")<a class="link-underline link-underline-opacity-0" onclick="showLinks(this)"><i class="bi bi-markdown ms-2"></i></a></label>
<textarea id="reminderNotes" class="form-control" rows="5">@Model.Notes</textarea> <textarea id="reminderNotes" class="form-control" rows="5">@Model.Notes</textarea>
<div class="form-check form-switch"> <div class="form-check form-switch">
<input class="form-check-input" type="checkbox" onChange="enableRecurring()" role="switch" id="reminderIsRecurring" checked="@Model.IsRecurring"> <input class="form-check-input" type="checkbox" onChange="enableRecurring()" role="switch" id="reminderIsRecurring" checked="@Model.IsRecurring">
<label class="form-check-label" for="reminderIsRecurring">Is Recurring</label> <label class="form-check-label" for="reminderIsRecurring">@translator.Translate(userLanguage,"Is Recurring")</label>
</div> </div>
<label for="reminderRecurringMileage">Odometer</label> <label for="reminderRecurringMileage">@translator.Translate(userLanguage,"Odometer")</label>
<select class="form-select" onchange="checkCustomMileageInterval()" id="reminderRecurringMileage" @(Model.IsRecurring ? "" : "disabled")> <select class="form-select" onchange="checkCustomMileageInterval()" id="reminderRecurringMileage" @(Model.IsRecurring ? "" : "disabled")>
<!option value="Other" @(Model.ReminderMileageInterval == ReminderMileageInterval.Other ? "selected" : "")>@(Model.ReminderMileageInterval == ReminderMileageInterval.Other && Model.CustomMileageInterval > 0 ? $"Other: {Model.CustomMileageInterval}" : "Other")</!option> <!option value="Other" @(Model.ReminderMileageInterval == ReminderMileageInterval.Other ? "selected" : "")>@(Model.ReminderMileageInterval == ReminderMileageInterval.Other && Model.CustomMileageInterval > 0 ? $"{translator.Translate(userLanguage, "Other")}: {Model.CustomMileageInterval}" : $"{translator.Translate(userLanguage, "Other")}") </!option>
<!option value="FiftyMiles" @(Model.ReminderMileageInterval == ReminderMileageInterval.FiftyMiles ? "selected" : "")>50 mi. / Km</!option> <!option value="FiftyMiles" @(Model.ReminderMileageInterval == ReminderMileageInterval.FiftyMiles ? "selected" : "")>50 mi. / Km</!option>
<!option value="OneHundredMiles" @(Model.ReminderMileageInterval == ReminderMileageInterval.OneHundredMiles ? "selected" : "")>100 mi. / Km</!option> <!option value="OneHundredMiles" @(Model.ReminderMileageInterval == ReminderMileageInterval.OneHundredMiles ? "selected" : "")>100 mi. / Km</!option>
<!option value="FiveHundredMiles" @(Model.ReminderMileageInterval == ReminderMileageInterval.FiveHundredMiles ? "selected" : "")>500 mi. / Km</!option> <!option value="FiveHundredMiles" @(Model.ReminderMileageInterval == ReminderMileageInterval.FiveHundredMiles ? "selected" : "")>500 mi. / Km</!option>
@@ -68,12 +73,12 @@
</select> </select>
<label for="reminderRecurringMonth">Month</label> <label for="reminderRecurringMonth">Month</label>
<select class="form-select" id="reminderRecurringMonth" @(Model.IsRecurring ? "" : "disabled")> <select class="form-select" id="reminderRecurringMonth" @(Model.IsRecurring ? "" : "disabled")>
<!option value="ThreeMonths" @(Model.ReminderMonthInterval == ReminderMonthInterval.ThreeMonths || isNew ? "selected" : "")>3 Months</!option> <!option value="ThreeMonths" @(Model.ReminderMonthInterval == ReminderMonthInterval.ThreeMonths || isNew ? "selected" : "")>@translator.Translate(userLanguage,"3 Months")</!option>
<!option value="SixMonths" @(Model.ReminderMonthInterval == ReminderMonthInterval.SixMonths ? "selected" : "")>6 Months</!option> <!option value="SixMonths" @(Model.ReminderMonthInterval == ReminderMonthInterval.SixMonths ? "selected" : "")>@translator.Translate(userLanguage,"6 Months")</!option>
<!option value="OneYear" @(Model.ReminderMonthInterval == ReminderMonthInterval.OneYear ? "selected" : "")>1 Year</!option> <!option value="OneYear" @(Model.ReminderMonthInterval == ReminderMonthInterval.OneYear ? "selected" : "")>@translator.Translate(userLanguage, "1 Year")</!option>
<!option value="TwoYears" @(Model.ReminderMonthInterval == ReminderMonthInterval.TwoYears ? "selected" : "")>2 Years</!option> <!option value="TwoYears" @(Model.ReminderMonthInterval == ReminderMonthInterval.TwoYears ? "selected" : "")>@translator.Translate(userLanguage, "2 Years")</!option>
<!option value="ThreeYears" @(Model.ReminderMonthInterval == ReminderMonthInterval.ThreeYears ? "selected" : "")>3 Years</!option> <!option value="ThreeYears" @(Model.ReminderMonthInterval == ReminderMonthInterval.ThreeYears ? "selected" : "")>@translator.Translate(userLanguage, "3 Years")</!option>
<!option value="FiveYears" @(Model.ReminderMonthInterval == ReminderMonthInterval.FiveYears ? "selected" : "")>5 Years</!option> <!option value="FiveYears" @(Model.ReminderMonthInterval == ReminderMonthInterval.FiveYears ? "selected" : "")>@translator.Translate(userLanguage, "5 Years")</!option>
</select> </select>
</div> </div>
</div> </div>
@@ -83,16 +88,16 @@
<div class="modal-footer"> <div class="modal-footer">
@if (!isNew) @if (!isNew)
{ {
<button type="button" class="btn btn-danger" onclick="deleteReminderRecord(@Model.Id)" style="margin-right:auto;">Delete</button> <button type="button" class="btn btn-danger" onclick="deleteReminderRecord(@Model.Id)" style="margin-right:auto;">@translator.Translate(userLanguage, "Delete")</button>
} }
<button type="button" class="btn btn-secondary" onclick="hideAddReminderRecordModal()">Cancel</button> <button type="button" class="btn btn-secondary" onclick="hideAddReminderRecordModal()">@translator.Translate(userLanguage, "Cancel")</button>
@if (isNew) @if (isNew)
{ {
<button type="button" class="btn btn-primary" onclick="saveReminderRecordToVehicle()">Add New Reminder</button> <button type="button" class="btn btn-primary" onclick="saveReminderRecordToVehicle()">@translator.Translate(userLanguage, "Add New Reminder")</button>
} }
else if (!isNew) else if (!isNew)
{ {
<button type="button" class="btn btn-primary" onclick="saveReminderRecordToVehicle(true)">Edit Reminder</button> <button type="button" class="btn btn-primary" onclick="saveReminderRecordToVehicle(true)">@translator.Translate(userLanguage, "Edit Reminder")</button>
} }
</div> </div>
<script> <script>

View File

@@ -1,18 +1,23 @@
@model List<ReminderRecordViewModel> @using CarCareTracker.Helper
@inject IConfigHelper config
@inject ITranslationHelper translator
@model List<ReminderRecordViewModel>
@{ @{
var userConfig = config.GetUserConfig(User);
var userLanguage = userConfig.UserLanguage;
var hasRefresh = Model.Where(x => (x.Urgency == ReminderUrgency.VeryUrgent || x.Urgency == ReminderUrgency.PastDue) && x.IsRecurring).Any(); var hasRefresh = Model.Where(x => (x.Urgency == ReminderUrgency.VeryUrgent || x.Urgency == ReminderUrgency.PastDue) && x.IsRecurring).Any();
} }
<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">@($"# of Reminders: {Model.Count()}")</span> <span class="ms-2 badge bg-success">@($"{translator.Translate(userLanguage, "# of Reminders")}: {Model.Count()}")</span>
<span class="ms-2 badge bg-secondary">@($"Past Due: {Model.Where(x => x.Urgency == ReminderUrgency.PastDue).Count()}")</span> <span class="ms-2 badge bg-secondary">@($"{translator.Translate(userLanguage, "Past Due")}: {Model.Where(x => x.Urgency == ReminderUrgency.PastDue).Count()}")</span>
<span class="ms-2 badge bg-danger">@($"Very Urgent: {Model.Where(x=>x.Urgency == ReminderUrgency.VeryUrgent).Count()}")</span> <span class="ms-2 badge bg-danger">@($"{translator.Translate(userLanguage, "Very Urgent")}: {Model.Where(x=>x.Urgency == ReminderUrgency.VeryUrgent).Count()}")</span>
<span class="ms-2 badge bg-warning">@($"Urgent: {Model.Where(x => x.Urgency == ReminderUrgency.Urgent).Count()}")</span> <span class="ms-2 badge bg-warning">@($"{translator.Translate(userLanguage, "Urgent")}: {Model.Where(x => x.Urgency == ReminderUrgency.Urgent).Count()}")</span>
<span class="ms-2 badge bg-success">@($"Not Urgent: {Model.Where(x => x.Urgency == ReminderUrgency.NotUrgent).Count()}")</span> <span class="ms-2 badge bg-success">@($"{translator.Translate(userLanguage, "Not Urgent")}: {Model.Where(x => x.Urgency == ReminderUrgency.NotUrgent).Count()}")</span>
</div> </div>
<div> <div>
<button onclick="showAddReminderModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>Add Reminder</button> <button onclick="showAddReminderModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>@translator.Translate(userLanguage, "Add Reminder")</button>
</div> </div>
</div> </div>
</div> </div>
@@ -26,15 +31,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-1">Urgency</th> <th scope="col" class="col-1">@translator.Translate(userLanguage, "Urgency")</th>
<th scope="col" class="col-2">Metric</th> <th scope="col" class="col-2">@translator.Translate(userLanguage, "Metric")</th>
<th scope="col" class="@(hasRefresh ? "col-4" : "col-5")">Description</th> <th scope="col" class="@(hasRefresh ? "col-4" : "col-5")">@translator.Translate(userLanguage, "Description")</th>
<th scope="col" class="col-3">Notes</th> <th scope="col" class="col-3">@translator.Translate(userLanguage, "Notes")</th>
@if (hasRefresh) @if (hasRefresh)
{ {
<th scope="col" class="col-1">Done</th> <th scope="col" class="col-1">@translator.Translate(userLanguage, "Done")</th>
} }
<th scope="col" class="col-1">Delete</th> <th scope="col" class="col-1">@translator.Translate(userLanguage, "Delete")</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@@ -43,19 +48,19 @@
<tr class="d-flex" style="cursor:pointer;" onclick="showEditReminderRecordModal(@reminderRecord.Id)"> <tr class="d-flex" style="cursor:pointer;" onclick="showEditReminderRecordModal(@reminderRecord.Id)">
@if (reminderRecord.Urgency == ReminderUrgency.VeryUrgent) @if (reminderRecord.Urgency == ReminderUrgency.VeryUrgent)
{ {
<td class="col-1"><span class="badge text-bg-danger">Very Urgent</span></td> <td class="col-1"><span class="badge text-bg-danger">@translator.Translate(userLanguage, "Very Urgent")</span></td>
} }
else if (reminderRecord.Urgency == ReminderUrgency.Urgent) else if (reminderRecord.Urgency == ReminderUrgency.Urgent)
{ {
<td class="col-1"><span class="badge text-bg-warning">Urgent</span></td> <td class="col-1"><span class="badge text-bg-warning">@translator.Translate(userLanguage, "Urgent")</span></td>
} }
else if (reminderRecord.Urgency == ReminderUrgency.PastDue) else if (reminderRecord.Urgency == ReminderUrgency.PastDue)
{ {
<td class="col-1"><span class="badge text-bg-secondary">Past Due</span></td> <td class="col-1"><span class="badge text-bg-secondary">@translator.Translate(userLanguage, "Past Due")</span></td>
} }
else else
{ {
<td class="col-1"><span class="badge text-bg-success">Not Urgent</span></td> <td class="col-1"><span class="badge text-bg-success">@translator.Translate(userLanguage, "Not Urgent")</span></td>
} }
@if (reminderRecord.Metric == ReminderMetric.Date) @if (reminderRecord.Metric == ReminderMetric.Date)
{ {

View File

@@ -1,4 +1,11 @@
@model ReportViewModel @using CarCareTracker.Helper
@inject IConfigHelper config
@inject ITranslationHelper translator
@{
var userConfig = config.GetUserConfig(User);
var userLanguage = userConfig.UserLanguage;
}
@model ReportViewModel
<div class="container reportTabContainer"> <div class="container reportTabContainer">
<div class="row hideOnPrint"> <div class="row hideOnPrint">
<div class="col-md-3 col-12 mt-2"> <div class="col-md-3 col-12 mt-2">
@@ -25,23 +32,23 @@
<div class="col-12 col-md-10 reportsCheckBoxContainer"> <div class="col-12 col-md-10 reportsCheckBoxContainer">
<div class="form-check form-check-inline"> <div class="form-check form-check-inline">
<input class="form-check-input" onChange="updateCheck()" type="checkbox" id="serviceExpenseCheck" value="1" checked> <input class="form-check-input" onChange="updateCheck()" type="checkbox" id="serviceExpenseCheck" value="1" checked>
<label class="form-check-label" for="serviceExpenseCheck">Service</label> <label class="form-check-label" for="serviceExpenseCheck">@translator.Translate(userLanguage,"Service")</label>
</div> </div>
<div class="form-check form-check-inline"> <div class="form-check form-check-inline">
<input class="form-check-input" onChange="updateCheck()" type="checkbox" id="repairExpenseCheck" value="2" checked> <input class="form-check-input" onChange="updateCheck()" type="checkbox" id="repairExpenseCheck" value="2" checked>
<label class="form-check-label" for="repairExpenseCheck">Repairs</label> <label class="form-check-label" for="repairExpenseCheck">@translator.Translate(userLanguage, "Repairs")</label>
</div> </div>
<div class="form-check form-check-inline"> <div class="form-check form-check-inline">
<input class="form-check-input" onChange="updateCheck()" type="checkbox" id="upgradeExpenseCheck" value="3" checked> <input class="form-check-input" onChange="updateCheck()" type="checkbox" id="upgradeExpenseCheck" value="3" checked>
<label class="form-check-label" for="upgradeExpenseCheck">Upgrades</label> <label class="form-check-label" for="upgradeExpenseCheck">@translator.Translate(userLanguage, "Upgrades")</label>
</div> </div>
<div class="form-check form-check-inline"> <div class="form-check form-check-inline">
<input class="form-check-input" onChange="updateCheck()" type="checkbox" id="gasExpenseCheck" value="4" checked> <input class="form-check-input" onChange="updateCheck()" type="checkbox" id="gasExpenseCheck" value="4" checked>
<label class="form-check-label" for="gasExpenseCheck">Fuel</label> <label class="form-check-label" for="gasExpenseCheck">@translator.Translate(userLanguage, "Fuel")</label>
</div> </div>
<div class="form-check form-check-inline"> <div class="form-check form-check-inline">
<input class="form-check-input" onChange="updateCheck()" type="checkbox" id="taxExpenseCheck" value="5" checked> <input class="form-check-input" onChange="updateCheck()" type="checkbox" id="taxExpenseCheck" value="5" checked>
<label class="form-check-label" for="taxExpenseCheck">Taxes</label> <label class="form-check-label" for="taxExpenseCheck">@translator.Translate(userLanguage, "Taxes")</label>
</div> </div>
</div> </div>
<div class="col-md-1 d-sm-none d-md-block"></div> <div class="col-md-1 d-sm-none d-md-block"></div>
@@ -56,10 +63,10 @@
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<select class="form-select" onchange="updateReminderPie()" id="reminderOption"> <select class="form-select" onchange="updateReminderPie()" id="reminderOption">
<option value="0">As of Today</option> <option value="0">@translator.Translate(userLanguage, "As of Today")</option>
<option value="30">+30 Days</option> <option value="30">@translator.Translate(userLanguage, "+30 Days")</option>
<option value="60">+60 Days</option> <option value="60">@translator.Translate(userLanguage, "+60 Days")</option>
<option value="90">+90 Days</option> <option value="90">@translator.Translate(userLanguage, "+90 Days")</option>
</select> </select>
</div> </div>
</div> </div>
@@ -82,10 +89,10 @@
</div> </div>
<div class="col-md-3 col-12 chartContainer"> <div class="col-md-3 col-12 chartContainer">
<div class="d-grid"> <div class="d-grid">
<button onclick="generateVehicleHistoryReport()" class="btn btn-secondary btn-md mt-1 mb-1">Vehicle Maintenance Report<i class="bi ms-2 bi-box-arrow-in-up-right"></i></button> <button onclick="generateVehicleHistoryReport()" class="btn btn-secondary btn-md mt-1 mb-1">@translator.Translate(userLanguage, "Vehicle Maintenance Report")<i class="bi ms-2 bi-box-arrow-in-up-right"></i></button>
</div> </div>
<div class="d-grid"> <div class="d-grid">
<button onclick="exportAttachments()" class="btn btn-secondary btn-md mt-1 mb-1">Export Attachments<i class="bi ms-2 bi-box-arrow-in-up-right"></i></button> <button onclick="exportAttachments()" class="btn btn-secondary btn-md mt-1 mb-1">@translator.Translate(userLanguage, "Export Attachments")<i class="bi ms-2 bi-box-arrow-in-up-right"></i></button>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,9 +1,14 @@
@model ServiceRecordInput @using CarCareTracker.Helper
@inject IConfigHelper config
@inject ITranslationHelper translator
@model ServiceRecordInput
@{ @{
var isNew = Model.Id == 0; var isNew = Model.Id == 0;
var userConfig = config.GetUserConfig(User);
var userLanguage = userConfig.UserLanguage;
} }
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title">@(isNew ? "Add New Service Record" : "Edit Service Record")</h5> <h5 class="modal-title">@(isNew ? translator.Translate(userLanguage,"Add New Service Record") : translator.Translate(userLanguage,"Edit Service Record"))</h5>
<button type="button" class="btn-close" onclick="hideAddServiceRecordModal()" aria-label="Close"></button> <button type="button" class="btn-close" onclick="hideAddServiceRecordModal()" aria-label="Close"></button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
@@ -12,22 +17,22 @@
<div class="row"> <div class="row">
<div class="col-md-6 col-12"> <div class="col-md-6 col-12">
<input type="text" id="workAroundInput" style="height:0px; width:0px; display:none;"> <input type="text" id="workAroundInput" style="height:0px; width:0px; display:none;">
<label for="serviceRecordDate">Date</label> <label for="serviceRecordDate">@translator.Translate(userLanguage,"Date")</label>
<div class="input-group"> <div class="input-group">
<input type="text" id="serviceRecordDate" class="form-control" placeholder="Date service was performed" value="@Model.Date"> <input type="text" id="serviceRecordDate" class="form-control" placeholder="@translator.Translate(userLanguage,"Date service was performed")" value="@Model.Date">
<span class="input-group-text"><i class="bi bi-calendar-event"></i></span> <span class="input-group-text"><i class="bi bi-calendar-event"></i></span>
</div> </div>
<label for="serviceRecordMileage">Odometer</label> <label for="serviceRecordMileage">@translator.Translate(userLanguage,"Odometer")</label>
<input type="number" id="serviceRecordMileage" class="form-control" placeholder="Odometer reading when serviced" value="@(isNew ? "" : Model.Mileage)"> <input type="number" id="serviceRecordMileage" class="form-control" placeholder="@translator.Translate(userLanguage,"Odometer reading when serviced")" value="@(isNew ? "" : Model.Mileage)">
<label for="serviceRecordDescription">Description</label> <label for="serviceRecordDescription">@translator.Translate(userLanguage,"Description")</label>
<input type="text" id="serviceRecordDescription" class="form-control" placeholder="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">
<label for="serviceRecordCost">Cost</label> <label for="serviceRecordCost">@translator.Translate(userLanguage,"Cost")</label>
<input type="text" id="serviceRecordCost" class="form-control" placeholder="Cost of the service" value="@(isNew ? "" : Model.Cost)"> <input type="text" id="serviceRecordCost" class="form-control" placeholder="@translator.Translate(userLanguage,"Cost of the service")" value="@(isNew ? "" : Model.Cost)">
@if (isNew) @if (isNew)
{ {
@await Html.PartialAsync("_SupplyStore", "ServiceRecord") @await Html.PartialAsync("_SupplyStore", "ServiceRecord")
} }
<label for="serviceRecordTag">Tags(optional)</label> <label for="serviceRecordTag">@translator.Translate(userLanguage,"Tags(optional)")</label>
<select multiple class="form-select" id="serviceRecordTag"> <select multiple class="form-select" id="serviceRecordTag">
@foreach(string tag in Model.Tags) @foreach(string tag in Model.Tags)
{ {
@@ -36,15 +41,15 @@
</select> </select>
</div> </div>
<div class="col-md-6 col-12"> <div class="col-md-6 col-12">
<label for="serviceRecordNotes">Notes(optional)<a class="link-underline link-underline-opacity-0" onclick="showLinks(this)"><i class="bi bi-markdown ms-2"></i></a></label> <label for="serviceRecordNotes">@translator.Translate(userLanguage,"Notes(optional)")<a class="link-underline link-underline-opacity-0" onclick="showLinks(this)"><i class="bi bi-markdown ms-2"></i></a></label>
<textarea id="serviceRecordNotes" class="form-control" rows="5">@Model.Notes</textarea> <textarea id="serviceRecordNotes" class="form-control" rows="5">@Model.Notes</textarea>
@if (Model.Files.Any()) @if (Model.Files.Any())
{ {
<div> <div>
@await Html.PartialAsync("_UploadedFiles", Model.Files) @await Html.PartialAsync("_UploadedFiles", Model.Files)
<label for="serviceRecordFiles">Upload more documents</label> <label for="serviceRecordFiles">@translator.Translate(userLanguage,"Upload more documents")</label>
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="serviceRecordFiles"> <input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="serviceRecordFiles">
<br /><small class="text-body-secondary">Max File Size: 28.6MB</small> <br /><small class="text-body-secondary">@translator.Translate(userLanguage,"Max File Size: 28.6MB")</small>
</div> </div>
} }
else else
@@ -54,13 +59,13 @@
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="addReminderCheck"> <input class="form-check-input" type="checkbox" value="" id="addReminderCheck">
<label class="form-check-label" for="addReminderCheck"> <label class="form-check-label" for="addReminderCheck">
Add Reminder @translator.Translate(userLanguage,"Add Reminder")
</label> </label>
</div> </div>
} }
<label for="serviceRecordFiles">Upload documents(optional)</label> <label for="serviceRecordFiles">@translator.Translate(userLanguage,"Upload documents(optional)")</label>
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="serviceRecordFiles"> <input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="serviceRecordFiles">
<br /><small class="text-body-secondary">Max File Size: 28.6MB</small> <br /><small class="text-body-secondary">@translator.Translate(userLanguage,"Max File Size: 28.6MB")</small>
} }
</div> </div>
</div> </div>
@@ -71,25 +76,25 @@
@if (!isNew) @if (!isNew)
{ {
<div class="btn-group" style="margin-right:auto;"> <div class="btn-group" style="margin-right:auto;">
<button type="button" class="btn btn-md mt-1 mb-1 btn-danger" onclick="deleteServiceRecord(@Model.Id)" >Delete</button> <button type="button" class="btn btn-md mt-1 mb-1 btn-danger" onclick="deleteServiceRecord(@Model.Id)">@translator.Translate(userLanguage,"Delete")</button>
<button type="button" class="btn btn-md btn-danger 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-danger 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><h6 class="dropdown-header">Move To</h6></li> <li><h6 class="dropdown-header">@translator.Translate(userLanguage,"Move To")</h6></li>
<li><a class="dropdown-item" href="#" onclick="moveRecord(@Model.Id, 'ServiceRecord', 'RepairRecord')">Repairs</a></li> <li><a class="dropdown-item" href="#" onclick="moveRecord(@Model.Id, 'ServiceRecord', 'RepairRecord')">@translator.Translate(userLanguage,"Repairs")</a></li>
<li><a class="dropdown-item" href="#" onclick="moveRecord(@Model.Id, 'ServiceRecord', 'UpgradeRecord')">Upgrades</a></li> <li><a class="dropdown-item" href="#" onclick="moveRecord(@Model.Id, 'ServiceRecord', 'UpgradeRecord')">@translator.Translate(userLanguage,"Upgrades")</a></li>
</ul> </ul>
</div> </div>
} }
<button type="button" class="btn btn-secondary" onclick="hideAddServiceRecordModal()">Cancel</button> <button type="button" class="btn btn-secondary" onclick="hideAddServiceRecordModal()">@translator.Translate(userLanguage,"Cancel")</button>
@if (isNew) @if (isNew)
{ {
<button type="button" class="btn btn-primary" onclick="saveServiceRecordToVehicle()">Add New Service Record</button> <button type="button" class="btn btn-primary" onclick="saveServiceRecordToVehicle()">@translator.Translate(userLanguage,"Add New Service Record")</button>
} }
else if (!isNew) else if (!isNew)
{ {
<button type="button" class="btn btn-primary" onclick="saveServiceRecordToVehicle(true)">Edit Service Record</button> <button type="button" class="btn btn-primary" onclick="saveServiceRecordToVehicle(true)">@translator.Translate(userLanguage,"Edit Service Record")</button>
} }
</div> </div>
<script> <script>

View File

@@ -1,16 +1,19 @@
@using CarCareTracker.Helper @using CarCareTracker.Helper
@inject IConfigHelper config @inject IConfigHelper config
@inject ITranslationHelper translator
@{ @{
var enableCsvImports = config.GetUserConfig(User).EnableCsvImports; var userConfig = config.GetUserConfig(User);
var hideZero = config.GetUserConfig(User).HideZero; var enableCsvImports = userConfig.EnableCsvImports;
var hideZero = userConfig.HideZero;
var userLanguage = userConfig.UserLanguage;
var recordTags = Model.SelectMany(x => x.Tags).Distinct(); var recordTags = Model.SelectMany(x => x.Tags).Distinct();
} }
@model List<ServiceRecord> @model List<ServiceRecord>
<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">@($"# of Service Records: {Model.Count()}")</span> <span class="ms-2 badge bg-success" data-aggregate-type="count">@($"{translator.Translate(userLanguage,"# of Service Records")}: {Model.Count()}")</span>
<span class="ms-2 badge bg-primary" data-aggregate-type="sum">@($"Total: {Model.Sum(x => x.Cost).ToString("C")}")</span> <span class="ms-2 badge bg-primary" data-aggregate-type="sum">@($"{translator.Translate(userLanguage,"Total")}: {Model.Sum(x => x.Cost).ToString("C")}")</span>
@foreach(string recordTag in recordTags) @foreach(string recordTag in recordTags)
{ {
<span onclick="filterTable('servicerecord-tab-pane', this)" class="user-select-none ms-2 rounded-pill badge bg-secondary tagfilter" style="cursor:pointer;">@recordTag</span> <span onclick="filterTable('servicerecord-tab-pane', this)" class="user-select-none ms-2 rounded-pill badge bg-secondary tagfilter" style="cursor:pointer;">@recordTag</span>
@@ -26,21 +29,21 @@
@if (enableCsvImports) @if (enableCsvImports)
{ {
<div class="btn-group"> <div class="btn-group">
<button onclick="showAddServiceRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>Add Service Record</button> <button onclick="showAddServiceRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>@translator.Translate(userLanguage,"Add Service 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('ServiceRecord')">Import via CSV</a></li> <li><a class="dropdown-item" href="#" onclick="showBulkImportModal('ServiceRecord')">@translator.Translate(userLanguage,"Import via CSV")</a></li>
<li><a class="dropdown-item" href="#" onclick="exportVehicleData('ServiceRecord')">Export to CSV</a></li> <li><a class="dropdown-item" href="#" onclick="exportVehicleData('ServiceRecord')">@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()">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="showAddServiceRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>Add Service Record</button> <button onclick="showAddServiceRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>@translator.Translate(userLanguage,"Add Service Record")</button>
} }
</div> </div>
</div> </div>
@@ -55,11 +58,11 @@
<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">Date</th> <th scope="col" class="col-2 col-xl-1">@translator.Translate(userLanguage,"Date")</th>
<th scope="col" class="col-2">Odometer</th> <th scope="col" class="col-2">@translator.Translate(userLanguage, "Odometer")</th>
<th scope="col" class="col-3 col-xl-4">Description</th> <th scope="col" class="col-3 col-xl-4">@translator.Translate(userLanguage, "Description")</th>
<th scope="col" class="col-2" onclick="toggleSort('servicerecord-tab-pane', this)" style="cursor:pointer;">Cost</th> <th scope="col" class="col-2" onclick="toggleSort('servicerecord-tab-pane', this)" style="cursor:pointer;">@translator.Translate(userLanguage, "Cost")</th>
<th scope="col" class="col-3">Notes</th> <th scope="col" class="col-3">@translator.Translate(userLanguage, "Notes")</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>

View File

@@ -1,9 +1,14 @@
@model SupplyRecordInput @using CarCareTracker.Helper
@inject IConfigHelper config
@inject ITranslationHelper translator
@model SupplyRecordInput
@{ @{
var isNew = Model.Id == 0; var isNew = Model.Id == 0;
var userConfig = config.GetUserConfig(User);
var userLanguage = userConfig.UserLanguage;
} }
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title">@(isNew ? "Add New Supply Record" : "Edit Supply Record")</h5> <h5 class="modal-title">@(isNew ? translator.Translate(userLanguage,"Add New Supply Record") : translator.Translate(userLanguage,"Edit Supply Record"))</h5>
<button type="button" class="btn-close" onclick="hideAddSupplyRecordModal()" aria-label="Close"></button> <button type="button" class="btn-close" onclick="hideAddSupplyRecordModal()" aria-label="Close"></button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
@@ -12,45 +17,45 @@
<div class="row"> <div class="row">
<div class="col-md-6 col-12"> <div class="col-md-6 col-12">
<input type="text" id="workAroundInput" style="height:0px; width:0px; display:none;"> <input type="text" id="workAroundInput" style="height:0px; width:0px; display:none;">
<label for="supplyRecordDate">Date</label> <label for="supplyRecordDate">@translator.Translate(userLanguage,"Date")</label>
<div class="input-group"> <div class="input-group">
<input type="text" id="supplyRecordDate" class="form-control" placeholder="Date purchased" value="@Model.Date"> <input type="text" id="supplyRecordDate" class="form-control" placeholder="@translator.Translate(userLanguage,"Date purchased")" value="@Model.Date">
<span class="input-group-text"><i class="bi bi-calendar-event"></i></span> <span class="input-group-text"><i class="bi bi-calendar-event"></i></span>
</div> </div>
<label for="supplyRecordPartNumber">Part Number</label> <label for="supplyRecordPartNumber">@translator.Translate(userLanguage,"Part Number")</label>
<input type="text" id="supplyRecordPartNumber" class="form-control" placeholder="Part #/Model #/SKU #" value="@(isNew ? "" : Model.PartNumber)"> <input type="text" id="supplyRecordPartNumber" class="form-control" placeholder="@translator.Translate(userLanguage,"Part #/Model #/SKU #")" value="@(isNew ? "" : Model.PartNumber)">
<label for="supplyRecordDescription">Description</label> <label for="supplyRecordDescription">@translator.Translate(userLanguage,"Description")</label>
<input type="text" id="supplyRecordDescription" class="form-control" placeholder="Description of the Part/Supplies" value="@Model.Description"> <input type="text" id="supplyRecordDescription" class="form-control" placeholder="@translator.Translate(userLanguage,"Description of the Part/Supplies")" value="@Model.Description">
<label for="supplyRecordSupplier">Supplier/Vendor</label> <label for="supplyRecordSupplier">@translator.Translate(userLanguage,"Supplier/Vendor")</label>
<input type="text" id="supplyRecordSupplier" class="form-control" placeholder="Part Supplier" value="@Model.PartSupplier"> <input type="text" id="supplyRecordSupplier" class="form-control" placeholder="@translator.Translate(userLanguage,"Part Supplier")" value="@Model.PartSupplier">
<div class="row"> <div class="row">
<div class="col-md-6 col-12"> <div class="col-md-6 col-12">
<label for="supplyRecordQuantity">Quantity</label> <label for="supplyRecordQuantity">@translator.Translate(userLanguage,"Quantity")</label>
<input type="text" id="supplyRecordQuantity" class="form-control" placeholder="Quantity" value="@(isNew ? "1" : Model.Quantity)"> <input type="text" id="supplyRecordQuantity" class="form-control" placeholder="@translator.Translate(userLanguage,"Quantity")" value="@(isNew ? "1" : Model.Quantity)">
</div> </div>
<div class="col-md-6 col-12"> <div class="col-md-6 col-12">
<label for="supplyRecordCost">Cost</label> <label for="supplyRecordCost">@translator.Translate(userLanguage,"Cost")</label>
<input type="text" id="supplyRecordCost" class="form-control" placeholder="Cost" value="@(isNew ? "" : Model.Cost)"> <input type="text" id="supplyRecordCost" class="form-control" placeholder="@translator.Translate(userLanguage,"Cost")" value="@(isNew ? "" : Model.Cost)">
</div> </div>
</div> </div>
</div> </div>
<div class="col-md-6 col-12"> <div class="col-md-6 col-12">
<label for="supplyRecordNotes">Notes(optional)<a class="link-underline link-underline-opacity-0" onclick="showLinks(this)"><i class="bi bi-markdown ms-2"></i></a></label> <label for="supplyRecordNotes">@translator.Translate(userLanguage,"Notes(optional)")<a class="link-underline link-underline-opacity-0" onclick="showLinks(this)"><i class="bi bi-markdown ms-2"></i></a></label>
<textarea id="supplyRecordNotes" class="form-control" rows="5">@Model.Notes</textarea> <textarea id="supplyRecordNotes" class="form-control" rows="5">@Model.Notes</textarea>
@if (Model.Files.Any()) @if (Model.Files.Any())
{ {
<div> <div>
@await Html.PartialAsync("_UploadedFiles", Model.Files) @await Html.PartialAsync("_UploadedFiles", Model.Files)
<label for="supplyRecordFiles">Upload more documents</label> <label for="supplyRecordFiles">@translator.Translate(userLanguage,"Upload more documents")</label>
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="supplyRecordFiles"> <input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="supplyRecordFiles">
<br /><small class="text-body-secondary">Max File Size: 28.6MB</small> <br /><small class="text-body-secondary">@translator.Translate(userLanguage,"Max File Size: 28.6MB")</small>
</div> </div>
} }
else else
{ {
<label for="supplyRecordFiles">Upload documents(optional)</label> <label for="supplyRecordFiles">@translator.Translate(userLanguage,"Upload documents(optional)")</label>
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="supplyRecordFiles"> <input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="supplyRecordFiles">
<br /><small class="text-body-secondary">Max File Size: 28.6MB</small> <br /><small class="text-body-secondary">@translator.Translate(userLanguage,"Max File Size: 28.6MB")</small>
} }
</div> </div>
</div> </div>
@@ -60,16 +65,16 @@
<div class="modal-footer"> <div class="modal-footer">
@if (!isNew) @if (!isNew)
{ {
<button type="button" class="btn btn-danger" onclick="deleteSupplyRecord(@Model.Id)" style="margin-right:auto;">Delete</button> <button type="button" class="btn btn-danger" onclick="deleteSupplyRecord(@Model.Id)" style="margin-right:auto;">@translator.Translate(userLanguage,"Delete")</button>
} }
<button type="button" class="btn btn-secondary" onclick="hideAddSupplyRecordModal()">Cancel</button> <button type="button" class="btn btn-secondary" onclick="hideAddSupplyRecordModal()">@translator.Translate(userLanguage,"Cancel")</button>
@if (isNew) @if (isNew)
{ {
<button type="button" class="btn btn-primary" onclick="saveSupplyRecordToVehicle()">Add New Supply Record</button> <button type="button" class="btn btn-primary" onclick="saveSupplyRecordToVehicle()">@translator.Translate(userLanguage,"Add New Supply Record")</button>
} }
else if (!isNew) else if (!isNew)
{ {
<button type="button" class="btn btn-primary" onclick="saveSupplyRecordToVehicle(true)">Edit Supply Record</button> <button type="button" class="btn btn-primary" onclick="saveSupplyRecordToVehicle(true)">@translator.Translate(userLanguage,"Edit Supply Record")</button>
} }
</div> </div>
<script> <script>

View File

@@ -1,35 +1,38 @@
@using CarCareTracker.Helper @using CarCareTracker.Helper
@inject IConfigHelper config @inject IConfigHelper config
@inject ITranslationHelper translator
@{ @{
var enableCsvImports = config.GetUserConfig(User).EnableCsvImports; var userConfig = config.GetUserConfig(User);
var hideZero = config.GetUserConfig(User).HideZero; var userLanguage = userConfig.UserLanguage;
var enableCsvImports = userConfig.EnableCsvImports;
var hideZero = userConfig.HideZero;
} }
@model List<SupplyRecord> @model List<SupplyRecord>
<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">@($"# of Supply Records: {Model.Count()}")</span> <span class="ms-2 badge bg-success">@($"{translator.Translate(userLanguage,"# of Supply Records")}: {Model.Count()}")</span>
<span class="ms-2 badge bg-primary">@($"Total: {Model.Sum(x => x.Cost).ToString("C")}")</span> <span class="ms-2 badge bg-primary">@($"{translator.Translate(userLanguage,"Total")}: {Model.Sum(x => x.Cost).ToString("C")}")</span>
</div> </div>
<div> <div>
@if (enableCsvImports) @if (enableCsvImports)
{ {
<div class="btn-group"> <div class="btn-group">
<button onclick="showAddSupplyRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>Add Supply Record</button> <button onclick="showAddSupplyRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>@translator.Translate(userLanguage,"Add Supply 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('SupplyRecord')">Import via CSV</a></li> <li><a class="dropdown-item" href="#" onclick="showBulkImportModal('SupplyRecord')">@translator.Translate(userLanguage,"Import via CSV")</a></li>
<li><a class="dropdown-item" href="#" onclick="exportVehicleData('SupplyRecord')">Export to CSV</a></li> <li><a class="dropdown-item" href="#" onclick="exportVehicleData('SupplyRecord')">@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()">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="showAddSupplyRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>Add Supply Record</button> <button onclick="showAddSupplyRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>@translator.Translate(userLanguage,"Add Supply Record")</button>
} }
</div> </div>
</div> </div>
@@ -44,13 +47,13 @@
<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">Date</th> <th scope="col" class="col-2 col-xl-1">@translator.Translate(userLanguage,"Date")</th>
<th scope="col" class="col-2">Part #</th> <th scope="col" class="col-2">@translator.Translate(userLanguage, "Part #")</th>
<th scope="col" class="col-2">Supplier</th> <th scope="col" class="col-2">@translator.Translate(userLanguage, "Supplier")</th>
<th scope="col" class="col-2 col-xl-3">Description</th> <th scope="col" class="col-2 col-xl-3">@translator.Translate(userLanguage, "Description")</th>
<th scope="col" class="col-1" onclick="toggleSort('supply-tab-pane', this)" style="cursor:pointer;">Quantity</th> <th scope="col" class="col-1" onclick="toggleSort('supply-tab-pane', this)" style="cursor:pointer;">@translator.Translate(userLanguage, "Quantity")</th>
<th scope="col" class="col-1" onclick="toggleSort('supply-tab-pane', this)" style="cursor:pointer;">Cost</th> <th scope="col" class="col-1" onclick="toggleSort('supply-tab-pane', this)" style="cursor:pointer;">@translator.Translate(userLanguage, "Cost")</th>
<th scope="col" class="col-2">Notes</th> <th scope="col" class="col-2">@translator.Translate(userLanguage, "Notes")</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>

View File

@@ -1,7 +1,14 @@
@model string @using CarCareTracker.Helper
@inject IConfigHelper config
@inject ITranslationHelper translator
@{
var userConfig = config.GetUserConfig(User);
var userLanguage = userConfig.UserLanguage;
}
@model string
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<a onclick="showSuppliesModal()" class="btn btn-link">Choose Supplies</a> <a onclick="showSuppliesModal()" class="btn btn-link">@translator.Translate(userLanguage,"Choose Supplies")</a>
</div> </div>
</div> </div>
<script> <script>

View File

@@ -1,6 +1,13 @@
@model List<SupplyRecord> @using CarCareTracker.Helper
@inject IConfigHelper config
@inject ITranslationHelper translator
@{
var userConfig = config.GetUserConfig(User);
var userLanguage = userConfig.UserLanguage;
}
@model List<SupplyRecord>
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title">Select Supplies</h5> <h5 class="modal-title">@translator.Translate(userLanguage,"Select Supplies")</h5>
<button type="button" class="btn-close" onclick="hideSuppliesModal()" aria-label="Close"></button> <button type="button" class="btn-close" onclick="hideSuppliesModal()" aria-label="Close"></button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
@@ -9,17 +16,16 @@
<div class="row"> <div class="row">
<div class="col-12" style="max-height:50vh; overflow-y:auto;"> <div class="col-12" style="max-height:50vh; overflow-y:auto;">
<div class="alert alert-warning" role="alert"> <div class="alert alert-warning" role="alert">
Supplies are requisitioned immediately after the record is created and cannot be modified. @translator.Translate(userLanguage,"Supplies are requisitioned immediately after the record is created and cannot be modified. If you have incorrectly entered the amount you needed you will need to correct it in the Supplies tab.")
If you have incorrectly entered the amount you needed you will need to correct it in the Supplies tab.
</div> </div>
<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-1"></th> <th scope="col" class="col-1"></th>
<th scope="col" class="col-2">Quantity.</th> <th scope="col" class="col-2">@translator.Translate(userLanguage,"Quantity")</th>
<th scope="col" class="col-2">In Stock</th> <th scope="col" class="col-2">@translator.Translate(userLanguage, "In Stock")</th>
<th scope="col" class="col-5">Description</th> <th scope="col" class="col-5">@translator.Translate(userLanguage, "Description")</th>
<th scope="col" class="col-2">Unit Cost</th> <th scope="col" class="col-2">@translator.Translate(userLanguage, "Unit Cost")</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@@ -43,7 +49,7 @@
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<div class="text-center"> <div class="text-center">
<h4>No supplies with quantities greater than 0 is found.</h4> <h4>@translator.Translate(userLanguage, "No supplies with quantities greater than 0 is found.")</h4>
</div> </div>
</div> </div>
</div> </div>
@@ -51,8 +57,8 @@
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<span id="supplySumLabel" style="margin-right:auto;">Total: 0.00</span> <span id="supplySumLabel" style="margin-right:auto;">Total: 0.00</span>
<button type="button" class="btn btn-secondary" onclick="hideSuppliesModal()">Cancel</button> <button type="button" class="btn btn-secondary" onclick="hideSuppliesModal()">@translator.Translate(userLanguage, "Cancel")</button>
<button type="button" class="btn btn-primary" disabled id="selectSuppliesButton" onclick="selectSupplies()">Select</button> <button type="button" class="btn btn-primary" disabled id="selectSuppliesButton" onclick="selectSupplies()">@translator.Translate(userLanguage, "Select")</button>
</div> </div>
<script> <script>
function recalculateTotal() { function recalculateTotal() {

View File

@@ -1,9 +1,14 @@
@model TaxRecordInput @using CarCareTracker.Helper
@inject IConfigHelper config
@inject ITranslationHelper translator
@model TaxRecordInput
@{ @{
var isNew = Model.Id == 0; var isNew = Model.Id == 0;
var userConfig = config.GetUserConfig(User);
var userLanguage = userConfig.UserLanguage;
} }
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title">@(isNew ? "Add New Tax Record" : "Edit Tax Record")</h5> <h5 class="modal-title">@(isNew ? translator.Translate(userLanguage,"Add New Tax Record") : translator.Translate(userLanguage,"Edit Tax Record"))</h5>
<button type="button" class="btn-close" onclick="hideAddTaxRecordModal()" aria-label="Close"></button> <button type="button" class="btn-close" onclick="hideAddTaxRecordModal()" aria-label="Close"></button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
@@ -12,16 +17,16 @@
<div class="row"> <div class="row">
<div class="col-md-6 col-12"> <div class="col-md-6 col-12">
<input type="text" id="workAroundInput" style="height:0px; width:0px; display:none;"> <input type="text" id="workAroundInput" style="height:0px; width:0px; display:none;">
<label for="taxRecordDate">Date</label> <label for="taxRecordDate">@translator.Translate(userLanguage,"Date")</label>
<div class="input-group"> <div class="input-group">
<input type="text" id="taxRecordDate" class="form-control" placeholder="Date tax was paid" value="@Model.Date"> <input type="text" id="taxRecordDate" class="form-control" placeholder="@translator.Translate(userLanguage,"Date tax was paid")" value="@Model.Date">
<span class="input-group-text"><i class="bi bi-calendar-event"></i></span> <span class="input-group-text"><i class="bi bi-calendar-event"></i></span>
</div> </div>
<label for="taxRecordDescription">Description</label> <label for="taxRecordDescription">@translator.Translate(userLanguage,"Description")</label>
<input type="text" id="taxRecordDescription" class="form-control" placeholder="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">
<label for="taxRecordCost">Cost</label> <label for="taxRecordCost">@translator.Translate(userLanguage,"Cost")</label>
<input type="text" id="taxRecordCost" class="form-control" placeholder="Cost of tax paid" value="@(isNew? "" : Model.Cost)"> <input type="text" id="taxRecordCost" class="form-control" placeholder="@translator.Translate(userLanguage,"Cost of tax paid")" value="@(isNew? "" : Model.Cost)">
<label for="taxRecordTag">Tags(optional)</label> <label for="taxRecordTag">@translator.Translate(userLanguage,"Tags(optional)")</label>
<select multiple class="form-select" id="taxRecordTag"> <select multiple class="form-select" id="taxRecordTag">
@foreach (string tag in Model.Tags) @foreach (string tag in Model.Tags)
{ {
@@ -30,29 +35,29 @@
</select> </select>
</div> </div>
<div class="col-md-6 col-12"> <div class="col-md-6 col-12">
<label for="taxRecordNotes">Notes(optional)<a class="link-underline link-underline-opacity-0" onclick="showLinks(this)"><i class="bi bi-markdown ms-2"></i></a></label> <label for="taxRecordNotes">@translator.Translate(userLanguage,"Notes(optional)")<a class="link-underline link-underline-opacity-0" onclick="showLinks(this)"><i class="bi bi-markdown ms-2"></i></a></label>
<textarea id="taxRecordNotes" class="form-control" rows="5">@Model.Notes</textarea> <textarea id="taxRecordNotes" class="form-control" rows="5">@Model.Notes</textarea>
<div class="form-check form-switch"> <div class="form-check form-switch">
<input class="form-check-input" type="checkbox" onChange="enableTaxRecurring()" role="switch" id="taxIsRecurring" checked="@Model.IsRecurring"> <input class="form-check-input" type="checkbox" onChange="enableTaxRecurring()" role="switch" id="taxIsRecurring" checked="@Model.IsRecurring">
<label class="form-check-label" for="taxIsRecurring">Is Recurring</label> <label class="form-check-label" for="taxIsRecurring">@translator.Translate(userLanguage,"Is Recurring")</label>
</div> </div>
<label for="taxRecurringMonth">Month</label> <label for="taxRecurringMonth">@translator.Translate(userLanguage,"Month")</label>
<select class="form-select" id="taxRecurringMonth" @(Model.IsRecurring ? "" : "disabled")> <select class="form-select" id="taxRecurringMonth" @(Model.IsRecurring ? "" : "disabled")>
<!option value="OneMonth" @(Model.RecurringInterval == ReminderMonthInterval.OneMonth ? "selected" : "")>1 Month</!option> <!option value="OneMonth" @(Model.RecurringInterval == ReminderMonthInterval.OneMonth ? "selected" : "")>@translator.Translate(userLanguage,"1 Month")</!option>
<!option value="ThreeMonths" @(Model.RecurringInterval == ReminderMonthInterval.ThreeMonths || isNew ? "selected" : "")>3 Months</!option> <!option value="ThreeMonths" @(Model.RecurringInterval == ReminderMonthInterval.ThreeMonths || isNew ? "selected" : "")>@translator.Translate(userLanguage, "3 Months")</!option>
<!option value="SixMonths" @(Model.RecurringInterval == ReminderMonthInterval.SixMonths ? "selected" : "")>6 Months</!option> <!option value="SixMonths" @(Model.RecurringInterval == ReminderMonthInterval.SixMonths ? "selected" : "")>@translator.Translate(userLanguage, "6 Months")</!option>
<!option value="OneYear" @(Model.RecurringInterval == ReminderMonthInterval.OneYear ? "selected" : "")>1 Year</!option> <!option value="OneYear" @(Model.RecurringInterval == ReminderMonthInterval.OneYear ? "selected" : "")>@translator.Translate(userLanguage, "1 Year")</!option>
<!option value="TwoYears" @(Model.RecurringInterval == ReminderMonthInterval.TwoYears ? "selected" : "")>2 Years</!option> <!option value="TwoYears" @(Model.RecurringInterval == ReminderMonthInterval.TwoYears ? "selected" : "")>@translator.Translate(userLanguage, "2 Years")</!option>
<!option value="ThreeYears" @(Model.RecurringInterval == ReminderMonthInterval.ThreeYears ? "selected" : "")>3 Years</!option> <!option value="ThreeYears" @(Model.RecurringInterval == ReminderMonthInterval.ThreeYears ? "selected" : "")>@translator.Translate(userLanguage, "3 Years")</!option>
<!option value="FiveYears" @(Model.RecurringInterval == ReminderMonthInterval.FiveYears ? "selected" : "")>5 Years</!option> <!option value="FiveYears" @(Model.RecurringInterval == ReminderMonthInterval.FiveYears ? "selected" : "")>@translator.Translate(userLanguage, "5 Years")</!option>
</select> </select>
@if (Model.Files.Any()) @if (Model.Files.Any())
{ {
<div> <div>
@await Html.PartialAsync("_UploadedFiles", Model.Files) @await Html.PartialAsync("_UploadedFiles", Model.Files)
<label for="taxRecordFiles">Upload more documents</label> <label for="taxRecordFiles">@translator.Translate(userLanguage,"Upload more documents")</label>
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="taxRecordFiles"> <input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="taxRecordFiles">
<br /><small class="text-body-secondary">Max File Size: 28.6MB</small> <br /><small class="text-body-secondary">@translator.Translate(userLanguage,"Max File Size: 28.6MB")</small>
</div> </div>
} }
else else
@@ -62,13 +67,13 @@
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="addReminderCheck"> <input class="form-check-input" type="checkbox" value="" id="addReminderCheck">
<label class="form-check-label" for="addReminderCheck"> <label class="form-check-label" for="addReminderCheck">
Add Reminder @translator.Translate(userLanguage,"Add Reminder")
</label> </label>
</div> </div>
} }
<label for="taxRecordFiles">Upload documents(optional)</label> <label for="taxRecordFiles">@translator.Translate(userLanguage,"Upload documents(optional)")</label>
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="taxRecordFiles"> <input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="taxRecordFiles">
<br /><small class="text-body-secondary">Max File Size: 28.6MB</small> <br /><small class="text-body-secondary">@translator.Translate(userLanguage,"Max File Size: 28.6MB")</small>
} }
</div> </div>
</div> </div>
@@ -78,16 +83,16 @@
<div class="modal-footer"> <div class="modal-footer">
@if (!isNew) @if (!isNew)
{ {
<button type="button" class="btn btn-danger" onclick="deleteTaxRecord(@Model.Id)" style="margin-right:auto;">Delete</button> <button type="button" class="btn btn-danger" onclick="deleteTaxRecord(@Model.Id)" style="margin-right:auto;">@translator.Translate(userLanguage,"Delete")</button>
} }
<button type="button" class="btn btn-secondary" onclick="hideAddTaxRecordModal()">Cancel</button> <button type="button" class="btn btn-secondary" onclick="hideAddTaxRecordModal()">@translator.Translate(userLanguage,"Cancel")</button>
@if (isNew) @if (isNew)
{ {
<button type="button" class="btn btn-primary" onclick="saveTaxRecordToVehicle()">Add New Tax Record</button> <button type="button" class="btn btn-primary" onclick="saveTaxRecordToVehicle()">@translator.Translate(userLanguage,"Add New Tax Record")</button>
} }
else if (!isNew) else if (!isNew)
{ {
<button type="button" class="btn btn-primary" onclick="saveTaxRecordToVehicle(true)">Edit Tax Record</button> <button type="button" class="btn btn-primary" onclick="saveTaxRecordToVehicle(true)">@translator.Translate(userLanguage,"Edit Tax Record")</button>
} }
</div> </div>
<script> <script>

View File

@@ -1,16 +1,19 @@
@using CarCareTracker.Helper @using CarCareTracker.Helper
@inject IConfigHelper config @inject IConfigHelper config
@inject ITranslationHelper translator
@{ @{
var enableCsvImports = config.GetUserConfig(User).EnableCsvImports; var userConfig = config.GetUserConfig(User);
var hideZero = config.GetUserConfig(User).HideZero; var userLanguage = userConfig.UserLanguage;
var enableCsvImports = userConfig.EnableCsvImports;
var hideZero = userConfig.HideZero;
var recordTags = Model.SelectMany(x => x.Tags).Distinct(); var recordTags = Model.SelectMany(x => x.Tags).Distinct();
} }
@model List<TaxRecord> @model List<TaxRecord>
<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">@($"# of Tax Records: {Model.Count()}")</span> <span class="ms-2 badge bg-success" data-aggregate-type="count">@($"{translator.Translate(userLanguage,"# of Tax Records")}: {Model.Count()}")</span>
<span class="ms-2 badge bg-primary" data-aggregate-type="sum">@($"Total: {Model.Sum(x => x.Cost).ToString("C")}")</span> <span class="ms-2 badge bg-primary" data-aggregate-type="sum">@($"{translator.Translate(userLanguage,"Total")}: {Model.Sum(x => x.Cost).ToString("C")}")</span>
@foreach (string recordTag in recordTags) @foreach (string recordTag in recordTags)
{ {
<span onclick="filterTable('tax-tab-pane', this)" class="user-select-none ms-2 rounded-pill badge bg-secondary tagfilter" style="cursor:pointer;">@recordTag</span> <span onclick="filterTable('tax-tab-pane', this)" class="user-select-none ms-2 rounded-pill badge bg-secondary tagfilter" style="cursor:pointer;">@recordTag</span>
@@ -26,21 +29,21 @@
@if (enableCsvImports) @if (enableCsvImports)
{ {
<div class="btn-group"> <div class="btn-group">
<button onclick="showAddTaxRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>Add Tax Record</button> <button onclick="showAddTaxRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>@translator.Translate(userLanguage, "Add Tax 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('TaxRecord')">Import via CSV</a></li> <li><a class="dropdown-item" href="#" onclick="showBulkImportModal('TaxRecord')">@translator.Translate(userLanguage, "Import via CSV")</a></li>
<li><a class="dropdown-item" href="#" onclick="exportVehicleData('TaxRecord')">Export to CSV</a></li> <li><a class="dropdown-item" href="#" onclick="exportVehicleData('TaxRecord')">@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()">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="showAddTaxRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>Add Tax Record</button> <button onclick="showAddTaxRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>@translator.Translate(userLanguage, "Add Tax Record")</button>
} }
</div> </div>
</div> </div>
@@ -55,10 +58,10 @@
<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-3 col-xl-1">Date</th> <th scope="col" class="col-3 col-xl-1">@translator.Translate(userLanguage, "Date")</th>
<th scope="col" class="col-4 col-xl-6">Description</th> <th scope="col" class="col-4 col-xl-6">@translator.Translate(userLanguage, "Description")</th>
<th scope="col" class="col-2" onclick="toggleSort('tax-tab-pane', this)" style="cursor:pointer;">Cost</th> <th scope="col" class="col-2" onclick="toggleSort('tax-tab-pane', this)" style="cursor:pointer;">@translator.Translate(userLanguage, "Cost")</th>
<th scope="col" class="col-3">Notes</th> <th scope="col" class="col-3">@translator.Translate(userLanguage, "Notes")</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>

View File

@@ -1,9 +1,14 @@
@model UpgradeRecordInput @using CarCareTracker.Helper
@inject IConfigHelper config
@inject ITranslationHelper translator
@model UpgradeRecordInput
@{ @{
var isNew = Model.Id == 0; var isNew = Model.Id == 0;
var userConfig = config.GetUserConfig(User);
var userLanguage = userConfig.UserLanguage;
} }
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title">@(isNew ? "Add New Upgrade Record" : "Edit Upgrade Record")</h5> <h5 class="modal-title">@(isNew ? translator.Translate(userLanguage,"Add New Upgrade Record") : translator.Translate(userLanguage,"Edit Upgrade Record"))</h5>
<button type="button" class="btn-close" onclick="hideAddUpgradeRecordModal()" aria-label="Close"></button> <button type="button" class="btn-close" onclick="hideAddUpgradeRecordModal()" aria-label="Close"></button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
@@ -12,22 +17,22 @@
<div class="row"> <div class="row">
<div class="col-md-6 col-12"> <div class="col-md-6 col-12">
<input type="text" id="workAroundInput" style="height:0px; width:0px; display:none;"> <input type="text" id="workAroundInput" style="height:0px; width:0px; display:none;">
<label for="upgradeRecordDate">Date</label> <label for="upgradeRecordDate">@translator.Translate(userLanguage,"Date")</label>
<div class="input-group"> <div class="input-group">
<input type="text" id="upgradeRecordDate" class="form-control" placeholder="Date upgrade/mods was installed" value="@Model.Date"> <input type="text" id="upgradeRecordDate" class="form-control" placeholder="@translator.Translate(userLanguage,"Date upgrade/mods was installed")" value="@Model.Date">
<span class="input-group-text"><i class="bi bi-calendar-event"></i></span> <span class="input-group-text"><i class="bi bi-calendar-event"></i></span>
</div> </div>
<label for="upgradeRecordMileage">Odometer</label> <label for="upgradeRecordMileage">@translator.Translate(userLanguage,"Odometer")</label>
<input type="number" id="upgradeRecordMileage" class="form-control" placeholder="Odometer reading when upgraded/modded" value="@(isNew ? "" : Model.Mileage)"> <input type="number" id="upgradeRecordMileage" class="form-control" placeholder="@translator.Translate(userLanguage,"Odometer reading when upgraded/modded")" value="@(isNew ? "" : Model.Mileage)">
<label for="upgradeRecordDescription">Description</label> <label for="upgradeRecordDescription">@translator.Translate(userLanguage,"Description")</label>
<input type="text" id="upgradeRecordDescription" class="form-control" placeholder="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">
<label for="upgradeRecordCost">Cost</label> <label for="upgradeRecordCost">@translator.Translate(userLanguage,"Cost")</label>
<input type="text" id="upgradeRecordCost" class="form-control" placeholder="Cost of the upgrade/mods" value="@(isNew ? "" : Model.Cost)"> <input type="text" id="upgradeRecordCost" class="form-control" placeholder="@translator.Translate(userLanguage,"Cost of the upgrade/mods")" value="@(isNew ? "" : Model.Cost)">
@if (isNew) @if (isNew)
{ {
@await Html.PartialAsync("_SupplyStore", "UpgradeRecord") @await Html.PartialAsync("_SupplyStore", "UpgradeRecord")
} }
<label for="upgradeRecordTag">Tags(optional)</label> <label for="upgradeRecordTag">@translator.Translate(userLanguage,"Tags(optional)")</label>
<select multiple class="form-select" id="upgradeRecordTag"> <select multiple class="form-select" id="upgradeRecordTag">
@foreach (string tag in Model.Tags) @foreach (string tag in Model.Tags)
{ {
@@ -36,15 +41,15 @@
</select> </select>
</div> </div>
<div class="col-md-6 col-12"> <div class="col-md-6 col-12">
<label for="upgradeRecordNotes">Notes(optional)<a class="link-underline link-underline-opacity-0" onclick="showLinks(this)"><i class="bi bi-markdown ms-2"></i></a></label> <label for="upgradeRecordNotes">@translator.Translate(userLanguage,"Notes(optional)")<a class="link-underline link-underline-opacity-0" onclick="showLinks(this)"><i class="bi bi-markdown ms-2"></i></a></label>
<textarea id="upgradeRecordNotes" class="form-control" rows="5">@Model.Notes</textarea> <textarea id="upgradeRecordNotes" class="form-control" rows="5">@Model.Notes</textarea>
@if (Model.Files.Any()) @if (Model.Files.Any())
{ {
<div> <div>
@await Html.PartialAsync("_UploadedFiles", Model.Files) @await Html.PartialAsync("_UploadedFiles", Model.Files)
<label for="upgradeRecordFiles">Upload more documents</label> <label for="upgradeRecordFiles">@translator.Translate(userLanguage,"Upload more documents")</label>
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="upgradeRecordFiles"> <input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="upgradeRecordFiles">
<br /><small class="text-body-secondary">Max File Size: 28.6MB</small> <br /><small class="text-body-secondary">@translator.Translate(userLanguage,"Max File Size: 28.6MB")</small>
</div> </div>
} }
else else
@@ -54,13 +59,13 @@
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="addReminderCheck"> <input class="form-check-input" type="checkbox" value="" id="addReminderCheck">
<label class="form-check-label" for="addReminderCheck"> <label class="form-check-label" for="addReminderCheck">
Add Reminder @translator.Translate(userLanguage,"Add Reminder")
</label> </label>
</div> </div>
} }
<label for="upgradeRecordFiles">Upload documents(optional)</label> <label for="upgradeRecordFiles">Upload documents(optional)</label>
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="upgradeRecordFiles"> <input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="upgradeRecordFiles">
<br /><small class="text-body-secondary">Max File Size: 28.6MB</small> <br /><small class="text-body-secondary">@translator.Translate(userLanguage,"Max File Size: 28.6MB")</small>
} }
</div> </div>
</div> </div>
@@ -71,25 +76,25 @@
@if (!isNew) @if (!isNew)
{ {
<div class="btn-group" style="margin-right:auto;"> <div class="btn-group" style="margin-right:auto;">
<button type="button" class="btn btn-md mt-1 mb-1 btn-danger" onclick="deleteUpgradeRecord(@Model.Id)">Delete</button> <button type="button" class="btn btn-md mt-1 mb-1 btn-danger" onclick="deleteUpgradeRecord(@Model.Id)">@translator.Translate(userLanguage,"Delete")</button>
<button type="button" class="btn btn-md btn-danger 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-danger 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><h6 class="dropdown-header">Move To</h6></li> <li><h6 class="dropdown-header">@translator.Translate(userLanguage,"Move To")</h6></li>
<li><a class="dropdown-item" href="#" onclick="moveRecord(@Model.Id, 'UpgradeRecord', 'ServiceRecord')">Service Records</a></li> <li><a class="dropdown-item" href="#" onclick="moveRecord(@Model.Id, 'UpgradeRecord', 'ServiceRecord')">@translator.Translate(userLanguage,"Service Records")</a></li>
<li><a class="dropdown-item" href="#" onclick="moveRecord(@Model.Id, 'UpgradeRecord', 'RepairRecord')">Repairs</a></li> <li><a class="dropdown-item" href="#" onclick="moveRecord(@Model.Id, 'UpgradeRecord', 'RepairRecord')">@translator.Translate(userLanguage,"Repairs")</a></li>
</ul> </ul>
</div> </div>
} }
<button type="button" class="btn btn-secondary" onclick="hideAddUpgradeRecordModal()">Cancel</button> <button type="button" class="btn btn-secondary" onclick="hideAddUpgradeRecordModal()">@translator.Translate(userLanguage,"Cancel")</button>
@if (isNew) @if (isNew)
{ {
<button type="button" class="btn btn-primary" onclick="saveUpgradeRecordToVehicle()">Add New Upgrade Record</button> <button type="button" class="btn btn-primary" onclick="saveUpgradeRecordToVehicle()">@translator.Translate(userLanguage,"Add New Upgrade Record")</button>
} }
else if (!isNew) else if (!isNew)
{ {
<button type="button" class="btn btn-primary" onclick="saveUpgradeRecordToVehicle(true)">Edit Upgrade Record</button> <button type="button" class="btn btn-primary" onclick="saveUpgradeRecordToVehicle(true)">@translator.Translate(userLanguage,"Edit Upgrade Record")</button>
} }
</div> </div>
<script> <script>

View File

@@ -1,16 +1,19 @@
@using CarCareTracker.Helper @using CarCareTracker.Helper
@inject IConfigHelper config @inject IConfigHelper config
@inject ITranslationHelper translator
@{ @{
var enableCsvImports = config.GetUserConfig(User).EnableCsvImports; var userConfig = config.GetUserConfig(User);
var hideZero = config.GetUserConfig(User).HideZero; var userLanguage = userConfig.UserLanguage;
var enableCsvImports = userConfig.EnableCsvImports;
var hideZero = userConfig.HideZero;
var recordTags = Model.SelectMany(x => x.Tags).Distinct(); var recordTags = Model.SelectMany(x => x.Tags).Distinct();
} }
@model List<UpgradeRecord> @model List<UpgradeRecord>
<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">@($"# of Upgrade Records: {Model.Count()}")</span> <span class="ms-2 badge bg-success" data-aggregate-type="count">@($"{translator.Translate(userLanguage,"# of Upgrade Records")}: {Model.Count()}")</span>
<span class="ms-2 badge bg-primary" data-aggregate-type="sum">@($"Total: {Model.Sum(x => x.Cost).ToString("C")}")</span> <span class="ms-2 badge bg-primary" data-aggregate-type="sum">@($"{translator.Translate(userLanguage,"Total")}: {Model.Sum(x => x.Cost).ToString("C")}")</span>
@foreach (string recordTag in recordTags) @foreach (string recordTag in recordTags)
{ {
<span onclick="filterTable('upgrade-tab-pane', this)" class="user-select-none ms-2 rounded-pill badge bg-secondary tagfilter" style="cursor:pointer;">@recordTag</span> <span onclick="filterTable('upgrade-tab-pane', this)" class="user-select-none ms-2 rounded-pill badge bg-secondary tagfilter" style="cursor:pointer;">@recordTag</span>
@@ -26,21 +29,21 @@
@if (enableCsvImports) @if (enableCsvImports)
{ {
<div class="btn-group"> <div class="btn-group">
<button onclick="showAddUpgradeRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>Add Upgrade Record</button> <button onclick="showAddUpgradeRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>@translator.Translate(userLanguage, "Add Upgrade Record")</button>
<button type="button" class="btn btn-md btn-primary btn-md mt-1 mb-1 dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false"> <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('UpgradeRecord')">Import via CSV</a></li> <li><a class="dropdown-item" href="#" onclick="showBulkImportModal('UpgradeRecord')">@translator.Translate(userLanguage, "Import via CSV")</a></li>
<li><a class="dropdown-item" href="#" onclick="exportVehicleData('UpgradeRecord')">Export to CSV</a></li> <li><a class="dropdown-item" href="#" onclick="exportVehicleData('UpgradeRecord')">@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()">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="showAddUpgradeRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>Add Upgrade Record</button> <button onclick="showAddUpgradeRecordModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>@translator.Translate(userLanguage, "Add Upgrade Record")</button>
} }
</div> </div>
</div> </div>
@@ -55,11 +58,11 @@
<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">Date</th> <th scope="col" class="col-2 col-xl-1">@translator.Translate(userLanguage, "Date")</th>
<th scope="col" class="col-2">Odometer</th> <th scope="col" class="col-2">@translator.Translate(userLanguage, "Odometer")</th>
<th scope="col" class="col-3 col-xl-4">Description</th> <th scope="col" class="col-3 col-xl-4">@translator.Translate(userLanguage, "Description")</th>
<th scope="col" class="col-2" onclick="toggleSort('upgrade-tab-pane', this)" style="cursor:pointer;">Cost</th> <th scope="col" class="col-2" onclick="toggleSort('upgrade-tab-pane', this)" style="cursor:pointer;">@translator.Translate(userLanguage, "Cost")</th>
<th scope="col" class="col-3">Notes</th> <th scope="col" class="col-3">@translator.Translate(userLanguage, "Notes")</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>

View File

@@ -1,5 +1,12 @@
@model List<UploadedFiles> @using CarCareTracker.Helper
<label>Uploaded Documents</label> @inject IConfigHelper config
@inject ITranslationHelper translator
@{
var userConfig = config.GetUserConfig(User);
var userLanguage = userConfig.UserLanguage;
}
@model List<UploadedFiles>
<label>@translator.Translate(userLanguage, "Uploaded Documents")</label>
<ul class="list-group"> <ul class="list-group">
@foreach (UploadedFiles filesUploaded in Model) @foreach (UploadedFiles filesUploaded in Model)
{ {

View File

@@ -1,14 +1,17 @@
@using CarCareTracker.Helper @using CarCareTracker.Helper
@inject IConfigHelper config @inject IConfigHelper config
@inject ITranslationHelper translator
@{ @{
var hideZero = config.GetUserConfig(User).HideZero; var userConfig = config.GetUserConfig(User);
var hideZero = userConfig.HideZero;
var userLanguage = userConfig.UserLanguage;
} }
@model VehicleHistoryViewModel @model VehicleHistoryViewModel
<div class="vehicleDetailTabContainer"> <div class="vehicleDetailTabContainer">
<div class="row mt-2"> <div class="row mt-2">
<div class="d-flex"> <div class="d-flex">
<img src="/defaults/lubelogger_logo.png" /> <img src="/defaults/lubelogger_logo.png" />
<span class="display-6 ms-5">Vehicle Maintenance Report</span> <span class="display-6 ms-5">@translator.Translate(userLanguage, "Vehicle Maintenance Report")</span>
</div> </div>
</div> </div>
<hr /> <hr />
@@ -24,21 +27,21 @@
<li class="list-group-item"> <li class="list-group-item">
@if (Model.VehicleData.IsElectric) @if (Model.VehicleData.IsElectric)
{ {
<span><i class="bi bi-ev-station"></i> Electric</span> <span><i class="bi bi-ev-station me-2"></i>@translator.Translate(userLanguage, "Electric")</span>
} }
else else
{ {
<span><i class="bi bi-fuel-pump"></i> Gasoline</span> <span><i class="bi bi-fuel-pump me-2"></i>@translator.Translate(userLanguage, "Gasoline")</span>
} }
</li> </li>
</ul> </ul>
</div> </div>
<div class="col-6"> <div class="col-6">
<ul class="list-group"> <ul class="list-group">
<li class="list-group-item">Last Reported Odometer Reading: @Model.Odometer</li> <li class="list-group-item">@($"{translator.Translate(userLanguage, "Last Reported Odometer Reading")}: {Model.Odometer}") </li>
<li class="list-group-item">Average Fuel Economy: @($"{Model.MPG}")</li> <li class="list-group-item">@($"{translator.Translate(userLanguage, "Average Fuel Economy")}: {Model.MPG}") </li>
<li class="list-group-item">Total Spent(excl. fuel): @Model.TotalCost.ToString("C")</li> <li class="list-group-item">@($"{translator.Translate(userLanguage, "Total Spent(excl. fuel)")}: {Model.TotalCost.ToString("C")}") </li>
<li class="list-group-item">Total Spent on Fuel: @Model.TotalGasCost.ToString("C")</li> <li class="list-group-item">@($"{translator.Translate(userLanguage, "Total Spent on Fuel")}: {Model.TotalGasCost.ToString("C")}") </li>
</ul> </ul>
</div> </div>
</div> </div>
@@ -48,12 +51,12 @@
<table class="table table-hover"> <table class="table table-hover">
<thead> <thead>
<tr class="d-flex"> <tr class="d-flex">
<th scope="col" class="col-2 servicehistorytype">Type</th> <th scope="col" class="col-2 servicehistorytype">@translator.Translate(userLanguage, "Type")</th>
<th scope="col" class="col-1 servicehistorydate">Date</th> <th scope="col" class="col-1 servicehistorydate">@translator.Translate(userLanguage, "Date")</th>
<th scope="col" class="col-1">Odometer</th> <th scope="col" class="col-1">@translator.Translate(userLanguage, "Odometer")</th>
<th scope="col" class="col-3">Description</th> <th scope="col" class="col-3">@translator.Translate(userLanguage, "Description")</th>
<th scope="col" class="col-1">Cost</th> <th scope="col" class="col-1">@translator.Translate(userLanguage, "Cost")</th>
<th scope="col" class="col-4">Notes</th> <th scope="col" class="col-4">@translator.Translate(userLanguage, "Notes")</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@@ -61,18 +64,21 @@
{ {
<tr class="d-flex"> <tr class="d-flex">
<td class="col-2 servicehistorytype"> <td class="col-2 servicehistorytype">
@if(reportData.DataType == ImportMode.ServiceRecord) @if (reportData.DataType == ImportMode.ServiceRecord)
{ {
<span><i class="bi bi-card-checklist me-2"></i>Service</span> <span><i class="bi bi-card-checklist me-2"></i>@translator.Translate(userLanguage, "Service")</span>
} else if (reportData.DataType == ImportMode.RepairRecord) }
else if (reportData.DataType == ImportMode.RepairRecord)
{ {
<span><i class="bi bi-exclamation-octagon me-2"></i>Repair</span> <span><i class="bi bi-exclamation-octagon me-2"></i>@translator.Translate(userLanguage, "Repair")</span>
} else if (reportData.DataType == ImportMode.UpgradeRecord) }
else if (reportData.DataType == ImportMode.UpgradeRecord)
{ {
<span><i class="bi bi-wrench-adjustable me-2"></i>Upgrade</span> <span><i class="bi bi-wrench-adjustable me-2"></i>@translator.Translate(userLanguage, "Upgrade")</span>
} else if (reportData.DataType == ImportMode.TaxRecord) }
else if (reportData.DataType == ImportMode.TaxRecord)
{ {
<span><i class="bi bi-currency-dollar me-2"></i>Tax</span> <span><i class="bi bi-currency-dollar me-2"></i>@translator.Translate(userLanguage, "Tax")</span>
} }
</td> </td>
<td class="col-1 servicehistorydate">@reportData.Date.ToShortDateString()</td> <td class="col-1 servicehistorydate">@reportData.Date.ToShortDateString()</td>

View File

@@ -1,5 +1,10 @@
@model Vehicle @using CarCareTracker.Helper
@inject IConfigHelper config
@inject ITranslationHelper translator
@model Vehicle
@{ @{
var userConfig = config.GetUserConfig(User);
var userLanguage = userConfig.UserLanguage;
var isNew = Model.Id == 0; var isNew = Model.Id == 0;
if (Model.ImageLocation == "/defaults/noimage.png") if (Model.ImageLocation == "/defaults/noimage.png")
{ {
@@ -7,7 +12,7 @@
} }
} }
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title" id="addVehicleModalLabel">@(isNew ? "Add New Vehicle" : "Edit Vehicle")</h5> <h5 class="modal-title" id="addVehicleModalLabel">@(isNew ? translator.Translate(userLanguage, "Add New Vehicle") : translator.Translate(userLanguage, "Edit Vehicle"))</h5>
@if (isNew) @if (isNew)
{ {
<button type="button" class="btn-close" onclick="hideAddVehicleModal()" aria-label="Close"></button> <button type="button" class="btn-close" onclick="hideAddVehicleModal()" aria-label="Close"></button>
@@ -21,23 +26,23 @@
<div class="modal-body"> <div class="modal-body">
<form class="form-inline"> <form class="form-inline">
<div class="form-group"> <div class="form-group">
<label for="inputYear">Year</label> <label for="inputYear">@translator.Translate(userLanguage, "Year")</label>
<input type="number" id="inputYear" class="form-control" placeholder="Year(must be after 1900)" value="@(isNew ? "" : Model.Year)"> <input type="number" id="inputYear" class="form-control" placeholder="@translator.Translate(userLanguage, "Year(must be after 1900)")" value="@(isNew ? "" : Model.Year)">
<label for="inputMake">Make</label> <label for="inputMake">@translator.Translate(userLanguage, "Make")</label>
<input type="text" id="inputMake" class="form-control" placeholder="Make" value="@Model.Make"> <input type="text" id="inputMake" class="form-control" placeholder="@translator.Translate(userLanguage, "Make")" value="@Model.Make">
<label for="inputModel">Model</label> <label for="inputModel">@translator.Translate(userLanguage, "Model")</label>
<input type="text" id="inputModel" class="form-control" placeholder="Model" value="@Model.Model"> <input type="text" id="inputModel" class="form-control" placeholder="@translator.Translate(userLanguage, "Model")" value="@Model.Model">
<label for="inputLicensePlate">License Plate</label> <label for="inputLicensePlate">@translator.Translate(userLanguage, "License Plate")</label>
<input type="text" id="inputLicensePlate" class="form-control" placeholder="License Plate" value="@Model.LicensePlate"> <input type="text" id="inputLicensePlate" class="form-control" placeholder="@translator.Translate(userLanguage, "License Plate")" value="@Model.LicensePlate">
<div class="form-check form-switch"> <div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="inputIsElectric" checked="@Model.IsElectric"> <input class="form-check-input" type="checkbox" role="switch" id="inputIsElectric" checked="@Model.IsElectric">
<label class="form-check-label" for="inputIsElectric">Electric Vehicle</label> <label class="form-check-label" for="inputIsElectric">@translator.Translate(userLanguage, "Electric Vehicle")</label>
</div> </div>
<div class="form-check form-switch"> <div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="inputUseHours" checked="@Model.UseHours"> <input class="form-check-input" type="checkbox" role="switch" id="inputUseHours" checked="@Model.UseHours">
<label class="form-check-label" for="inputUseHours">Use Engine Hours</label> <label class="form-check-label" for="inputUseHours">@translator.Translate(userLanguage, "Use Engine Hours")</label>
</div> </div>
<label for="inputTag">Tags(optional)</label> <label for="inputTag">@translator.Translate(userLanguage, "Tags(optional)")</label>
<select multiple class="form-select" id="inputTag"> <select multiple class="form-select" id="inputTag">
@foreach (string tag in Model.Tags) @foreach (string tag in Model.Tags)
{ {
@@ -46,11 +51,11 @@
</select> </select>
@if (!string.IsNullOrWhiteSpace(Model.ImageLocation)) @if (!string.IsNullOrWhiteSpace(Model.ImageLocation))
{ {
<label for="inputImage">Replace picture(optional)</label> <label for="inputImage">@translator.Translate(userLanguage, "Replace picture(optional)")</label>
<input onChange="uploadFileAsync(this)" type="file" accept=".png,.jpg,.jpeg" class="form-control-file" id="inputImage"> <input onChange="uploadFileAsync(this)" type="file" accept=".png,.jpg,.jpeg" class="form-control-file" id="inputImage">
} else } else
{ {
<label for="inputImage">Upload a picture(optional)</label> <label for="inputImage">@translator.Translate(userLanguage, "Upload a picture(optional)")</label>
<input onChange="uploadFileAsync(this)" type="file" accept=".png,.jpg,.jpeg" class="form-control-file" id="inputImage"> <input onChange="uploadFileAsync(this)" type="file" accept=".png,.jpg,.jpeg" class="form-control-file" id="inputImage">
} }
</div> </div>
@@ -59,12 +64,12 @@
<div class="modal-footer"> <div class="modal-footer">
@if (isNew) @if (isNew)
{ {
<button type="button" class="btn btn-secondary" onclick="hideAddVehicleModal()">Cancel</button> <button type="button" class="btn btn-secondary" onclick="hideAddVehicleModal()">@translator.Translate(userLanguage, "Cancel")</button>
<button type="button" onclick="saveVehicle(false)" class="btn btn-primary">Add New Vehicle</button> <button type="button" onclick="saveVehicle(false)" class="btn btn-primary">@translator.Translate(userLanguage, "Add New Vehicle")</button>
} else if (!isNew) } else if (!isNew)
{ {
<button type="button" class="btn btn-secondary" onclick="hideEditVehicleModal()">Cancel</button> <button type="button" class="btn btn-secondary" onclick="hideEditVehicleModal()">@translator.Translate(userLanguage, "Cancel")</button>
<button type="button" onclick="saveVehicle(true)" class="btn btn-primary">Save Vehicle</button> <button type="button" onclick="saveVehicle(true)" class="btn btn-primary">@translator.Translate(userLanguage, "Save Vehicle")</button>
} }
</div> </div>
<script> <script>

View File

@@ -19,6 +19,7 @@
"UseMarkDownOnSavedNotes": false, "UseMarkDownOnSavedNotes": false,
"PreferredGasMileageUnit": "", "PreferredGasMileageUnit": "",
"PreferredGasUnit": "", "PreferredGasUnit": "",
"UserLanguage": "en_US",
"VisibleTabs": [ 0, 1, 4, 2, 3, 6, 5, 8 ], "VisibleTabs": [ 0, 1, 4, 2, 3, 6, 5, 8 ],
"DefaultTab": 8, "DefaultTab": 8,
"UserNameHash": "", "UserNameHash": "",

View File

@@ -10,6 +10,7 @@ services:
volumes: volumes:
- config:/App/config - config:/App/config
- data:/App/data - data:/App/data
- translations:/App/wwwroot/translations
- documents:/App/wwwroot/documents - documents:/App/wwwroot/documents
- images:/App/wwwroot/images - images:/App/wwwroot/images
- temp:/App/wwwroot/temp - temp:/App/wwwroot/temp
@@ -41,6 +42,7 @@ services:
volumes: volumes:
config: config:
data: data:
translations:
documents: documents:
images: images:
temp: temp:

View File

@@ -10,6 +10,7 @@ services:
volumes: volumes:
- config:/App/config - config:/App/config
- data:/App/data - data:/App/data
- translations:/App/wwwroot/translations
- documents:/App/wwwroot/documents - documents:/App/wwwroot/documents
- images:/App/wwwroot/images - images:/App/wwwroot/images
- temp:/App/wwwroot/temp - temp:/App/wwwroot/temp
@@ -24,6 +25,7 @@ services:
volumes: volumes:
config: config:
data: data:
translations:
documents: documents:
images: images:
temp: temp:

File diff suppressed because one or more lines are too long

View File

@@ -258,19 +258,19 @@ function convertFuelMileageUnits(currentUnit, destinationUnit, save) {
elem.innerText = convertedAmount.toFixed(2); elem.innerText = convertedAmount.toFixed(2);
} }
//update labels up top. //update labels up top.
var newAverage = globalParseFloat($("#averageFuelMileageLabel").text().replace("Average Fuel Economy: ", "")); var newAverage = globalParseFloat($("#averageFuelMileageLabel").text().split(":")[1].trim());
if (newAverage > 0) { if (newAverage > 0) {
newAverage = 100 / newAverage; newAverage = 100 / newAverage;
var averageLabel = $("#averageFuelMileageLabel"); var averageLabel = $("#averageFuelMileageLabel");
averageLabel.text(`${averageLabel.text().split(':')[0]}: ${newAverage.toFixed(2)}`); averageLabel.text(`${averageLabel.text().split(':')[0]}: ${newAverage.toFixed(2)}`);
} }
var newMin = globalParseFloat($("#minFuelMileageLabel").text().replace("Min Fuel Economy: ", "")); var newMin = globalParseFloat($("#minFuelMileageLabel").text().split(":")[1].trim());
if (newMin > 0) { if (newMin > 0) {
newMin = 100 / newMin; newMin = 100 / newMin;
var minLabel = $("#minFuelMileageLabel"); var minLabel = $("#minFuelMileageLabel");
minLabel.text(`${minLabel.text().split(':')[0]}: ${newMin.toFixed(2)}`); minLabel.text(`${minLabel.text().split(':')[0]}: ${newMin.toFixed(2)}`);
} }
var newMax = globalParseFloat($("#maxFuelMileageLabel").text().replace("Max Fuel Economy: ", "")); var newMax = globalParseFloat($("#maxFuelMileageLabel").text().split(":")[1].trim());
if (newMax > 0) { if (newMax > 0) {
newMax = 100 / newMax; newMax = 100 / newMax;
var maxLabel = $("#maxFuelMileageLabel"); var maxLabel = $("#maxFuelMileageLabel");
@@ -291,19 +291,19 @@ function convertFuelMileageUnits(currentUnit, destinationUnit, save) {
convertedAmount = 100 / convertedAmount; convertedAmount = 100 / convertedAmount;
elem.innerText = convertedAmount.toFixed(2); elem.innerText = convertedAmount.toFixed(2);
} }
var newAverage = globalParseFloat($("#averageFuelMileageLabel").text().replace("Average Fuel Economy: ", "")); var newAverage = globalParseFloat($("#averageFuelMileageLabel").text().split(":")[1].trim());
if (newAverage > 0) { if (newAverage > 0) {
newAverage = 100 / newAverage; newAverage = 100 / newAverage;
var averageLabel = $("#averageFuelMileageLabel"); var averageLabel = $("#averageFuelMileageLabel");
averageLabel.text(`${averageLabel.text().split(':')[0]}: ${newAverage.toFixed(2)}`); averageLabel.text(`${averageLabel.text().split(':')[0]}: ${newAverage.toFixed(2)}`);
} }
var newMin = globalParseFloat($("#minFuelMileageLabel").text().replace("Min Fuel Economy: ", "")); var newMin = globalParseFloat($("#minFuelMileageLabel").text().split(":")[1].trim());
if (newMin > 0) { if (newMin > 0) {
newMin = 100 / newMin; newMin = 100 / newMin;
var minLabel = $("#minFuelMileageLabel"); var minLabel = $("#minFuelMileageLabel");
minLabel.text(`${minLabel.text().split(':')[0]}: ${newMin.toFixed(2)}`); minLabel.text(`${minLabel.text().split(':')[0]}: ${newMin.toFixed(2)}`);
} }
var newMax = globalParseFloat($("#maxFuelMileageLabel").text().replace("Max Fuel Economy: ", "")); var newMax = globalParseFloat($("#maxFuelMileageLabel").text().split(":")[1].trim());
if (newMax > 0) { if (newMax > 0) {
newMax = 100 / newMax; newMax = 100 / newMax;
var maxLabel = $("#maxFuelMileageLabel"); var maxLabel = $("#maxFuelMileageLabel");