Merge branch 'hargata:main' into main

This commit is contained in:
snpaul22
2024-07-06 18:54:14 -04:00
committed by GitHub
38 changed files with 295 additions and 10467 deletions

View File

@@ -105,7 +105,7 @@ namespace CarCareTracker.Controllers
var reminderUrgency = _reminderHelper.GetReminderRecordViewModels(new List<ReminderRecord> { reminder }, 0, DateTime.Now).FirstOrDefault(); var reminderUrgency = _reminderHelper.GetReminderRecordViewModels(new List<ReminderRecord> { reminder }, 0, DateTime.Now).FirstOrDefault();
return PartialView("_ReminderRecordCalendarModal", reminderUrgency); return PartialView("_ReminderRecordCalendarModal", reminderUrgency);
} }
public IActionResult Settings() public async Task<IActionResult> Settings()
{ {
var userConfig = _config.GetUserConfig(User); var userConfig = _config.GetUserConfig(User);
var languages = _fileHelper.GetLanguages(); var languages = _fileHelper.GetLanguages();
@@ -114,6 +114,16 @@ namespace CarCareTracker.Controllers
UserConfig = userConfig, UserConfig = userConfig,
UILanguages = languages UILanguages = languages
}; };
try
{
var httpClient = new HttpClient();
var sponsorsData = await httpClient.GetFromJsonAsync<Sponsors>(StaticHelper.SponsorsPath) ?? new Sponsors();
viewModel.Sponsors = sponsorsData;
}
catch (Exception ex)
{
_logger.LogError($"Unable to retrieve sponsors: {ex.Message}");
}
return PartialView("_Settings", viewModel); return PartialView("_Settings", viewModel);
} }
[HttpPost] [HttpPost]
@@ -209,6 +219,13 @@ namespace CarCareTracker.Controllers
var userName = User.Identity.Name; var userName = User.Identity.Name;
return PartialView("_AccountModal", new UserData() { EmailAddress = emailAddress, UserName = userName }); return PartialView("_AccountModal", new UserData() { EmailAddress = emailAddress, UserName = userName });
} }
[Authorize(Roles = nameof(UserData.IsRootUser))]
[HttpGet]
public IActionResult GetRootAccountInformationModal()
{
var userName = User.Identity.Name;
return PartialView("_RootAccountModal", new UserData() { UserName = userName });
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error() public IActionResult Error()
{ {

View File

@@ -220,7 +220,7 @@ namespace CarCareTracker.Controllers
var result = _loginLogic.ResetPasswordByUser(credentials); var result = _loginLogic.ResetPasswordByUser(credentials);
return Json(result); return Json(result);
} }
[Authorize] //User must already be logged in to do this. [Authorize(Roles = nameof(UserData.IsRootUser))] //User must already be logged in as root user to do this.
[HttpPost] [HttpPost]
public IActionResult CreateLoginCreds(LoginModel credentials) public IActionResult CreateLoginCreds(LoginModel credentials)
{ {
@@ -235,7 +235,7 @@ namespace CarCareTracker.Controllers
} }
return Json(false); return Json(false);
} }
[Authorize] [Authorize(Roles = nameof(UserData.IsRootUser))]
[HttpPost] [HttpPost]
public IActionResult DestroyLoginCreds() public IActionResult DestroyLoginCreds()
{ {

View File

@@ -146,7 +146,11 @@ namespace CarCareTracker.Helper
using (var client = new SmtpClient()) using (var client = new SmtpClient())
{ {
client.Connect(server, mailConfig.Port, MailKit.Security.SecureSocketOptions.Auto); client.Connect(server, mailConfig.Port, MailKit.Security.SecureSocketOptions.Auto);
client.Authenticate(mailConfig.Username, mailConfig.Password); //perform authentication if either username or password is provided.
//do not perform authentication if neither are provided.
if (!string.IsNullOrWhiteSpace(mailConfig.Username) || !string.IsNullOrWhiteSpace(mailConfig.Password)) {
client.Authenticate(mailConfig.Username, mailConfig.Password);
}
try try
{ {
client.Send(message); client.Send(message);

View File

@@ -8,13 +8,13 @@ namespace CarCareTracker.Helper
/// </summary> /// </summary>
public static class StaticHelper public static class StaticHelper
{ {
public static string VersionNumber = "1.3.2"; public static string VersionNumber = "1.3.5";
public static string DbName = "data/cartracker.db"; public static string DbName = "data/cartracker.db";
public static string UserConfigPath = "config/userConfig.json"; public static string UserConfigPath = "config/userConfig.json";
public static string GenericErrorMessage = "An error occurred, please try again later"; public static string GenericErrorMessage = "An error occurred, please try again later";
public static string ReminderEmailTemplate = "defaults/reminderemailtemplate.txt"; public static string ReminderEmailTemplate = "defaults/reminderemailtemplate.txt";
public static string DefaultAllowedFileExtensions = ".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx"; public static string DefaultAllowedFileExtensions = ".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx";
public static string SponsorsPath = "https://hargata.github.io/hargata/sponsors.json";
public static string GetTitleCaseReminderUrgency(ReminderUrgency input) public static string GetTitleCaseReminderUrgency(ReminderUrgency input)
{ {
switch (input) switch (input)

View File

@@ -1,11 +1,6 @@
LubeLogger by Hargata Softworks is licensed under the MIT License for individual
and personal use. Commercial users and/or corporate entities are required
to maintain an active subscription in order to continue using LubeLogger.
For pricing information please contact us at hargatasoftworks@gmail.com
MIT License MIT License
Copyright (c) 2023 Hargata Softworks Copyright (c) 2024 Hargata Softworks
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@@ -4,5 +4,6 @@ namespace CarCareTracker.Models
{ {
public UserConfig UserConfig { get; set; } public UserConfig UserConfig { get; set; }
public List<string> UILanguages { get; set; } public List<string> UILanguages { get; set; }
public Sponsors Sponsors { get; set; } = new Sponsors();
} }
} }

10
Models/Sponsors.cs Normal file
View File

@@ -0,0 +1,10 @@
namespace CarCareTracker.Models
{
public class Sponsors
{
public List<string> LifeTime { get; set; } = new List<string>();
public List<string> Bronze { get; set; } = new List<string>();
public List<string> Silver { get; set; } = new List<string>();
public List<string> Gold { get; set; } = new List<string>();
}
}

View File

@@ -41,9 +41,7 @@ Read this [Getting Started Guide](https://docs.lubelogger.com/Getting%20Started)
- [MailKit](https://github.com/jstedfast/MailKit) - [MailKit](https://github.com/jstedfast/MailKit)
## License ## License
LubeLogger utilizes a dual-licensing model, see [License](/LICENSE) for more information MIT
## Support ## Support
Support this project by [Subscribing on Patreon](https://patreon.com/LubeLogger) or [Making a Donation](https://buy.stripe.com/aEU9Egc8DdMc9bO144) Support this project by [Subscribing on Patreon](https://patreon.com/LubeLogger) or [Making a Donation](https://buy.stripe.com/aEU9Egc8DdMc9bO144)
Note: Commercial users are required to maintain an active Patreon subscripton to be compliant with our licensing model.

View File

@@ -41,7 +41,12 @@
<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> <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>
} }
@if (!User.IsInRole(nameof(UserData.IsRootUser))) @if (User.IsInRole(nameof(UserData.IsRootUser)))
{
<li>
<button class="nav-link" onclick="showRootAccountInformationModal()"><span class="display-3 ms-2"><i class="bi bi-person-gear me-2"></i>@translator.Translate(userLanguage, "Profile")</span></button>
</li>
} else
{ {
<li> <li>
<button class="nav-link" onclick="showAccountInformationModal()"><span class="display-3 ms-2"><i class="bi bi-person-gear me-2"></i>@translator.Translate(userLanguage, "Profile")</span></button> <button class="nav-link" onclick="showAccountInformationModal()"><span class="display-3 ms-2"><i class="bi bi-person-gear me-2"></i>@translator.Translate(userLanguage, "Profile")</span></button>
@@ -90,7 +95,12 @@
<a class="dropdown-item" href="/Admin"><i class="bi bi-people me-2"></i>@translator.Translate(userLanguage,"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>
} }
@if (!User.IsInRole(nameof(UserData.IsRootUser))) @if (User.IsInRole(nameof(UserData.IsRootUser)))
{
<li>
<button class="dropdown-item" onclick="showRootAccountInformationModal()"><i class="bi bi-person-gear me-2"></i>@translator.Translate(userLanguage, "Profile")</button>
</li>
} else
{ {
<li> <li>
<button class="dropdown-item" onclick="showAccountInformationModal()"><i class="bi bi-person-gear me-2"></i>@translator.Translate(userLanguage, "Profile")</button> <button class="dropdown-item" onclick="showAccountInformationModal()"><i class="bi bi-person-gear me-2"></i>@translator.Translate(userLanguage, "Profile")</button>

View File

@@ -7,7 +7,7 @@
var userLanguage = userConfig.UserLanguage; var userLanguage = userConfig.UserLanguage;
} }
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title" id="addVehicleModalLabel">@translator.Translate(userLanguage, "Update Profile")</h5> <h5 class="modal-title" id="updateAccountModalLabel">@translator.Translate(userLanguage, "Update Profile")</h5>
<button type="button" class="btn-close" onclick="hideAccountInformationModal()" aria-label="Close"></button> <button type="button" class="btn-close" onclick="hideAccountInformationModal()" aria-label="Close"></button>
</div> </div>
<div class="modal-body"> <div class="modal-body">

View File

@@ -0,0 +1,26 @@
@using CarCareTracker.Helper
@inject IConfigHelper config
@inject ITranslationHelper translator
@model UserData
@{
var userConfig = config.GetUserConfig(User);
var userLanguage = userConfig.UserLanguage;
}
<div class="modal-header">
<h5 class="modal-title" id="updateRootAccountModalLabel">@translator.Translate(userLanguage, "Update Profile")</h5>
<button type="button" class="btn-close" onclick="hideAccountInformationModal()" aria-label="Close"></button>
</div>
<div class="modal-body">
<form class="form-inline">
<div class="form-group">
<label for="inputUsername">@translator.Translate(userLanguage, "Username")</label>
<input type="text" id="inputUsername" class="form-control" placeholder="@translator.Translate(userLanguage, "Account Username")" value="@Model.UserName">
<label for="inputPassword">@translator.Translate(userLanguage, "Password")</label>
<input type="password" id="inputPassword" class="form-control" placeholder="@translator.Translate(userLanguage, "Password")" value="">
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" onclick="hideAccountInformationModal()">@translator.Translate(userLanguage, "Cancel")</button>
<button type="button" onclick="validateAndSaveRootUserAccount()" class="btn btn-primary">@translator.Translate(userLanguage, "Update")</button>
</div>

View File

@@ -219,7 +219,7 @@
</p> </p>
<p class="lead"> <p class="lead">
If you enjoyed using this app, please consider spreading the good word.<br /> If you enjoyed using this app, please consider spreading the good word.<br />
If you are a commercial user, or if you just want to support the development of this project, consider subscribing to <a class="link-body-emphasis link-offset-2 link-underline-opacity-25 link-underline-opacity-100-hover" href="https://www.patreon.com/LubeLogger" target="_blank">our Patreon</a> or make a <a class="link-body-emphasis link-offset-2 link-underline-opacity-25 link-underline-opacity-100-hover" href="https://buy.stripe.com/aEU9Egc8DdMc9bO144" target="_blank">donation</a> If you want to support the development of this project, consider subscribing to <a class="link-body-emphasis link-offset-2 link-underline-opacity-25 link-underline-opacity-100-hover" href="https://www.patreon.com/LubeLogger" target="_blank">our Patreon</a> or make a <a class="link-body-emphasis link-offset-2 link-underline-opacity-25 link-underline-opacity-100-hover" href="https://buy.stripe.com/aEU9Egc8DdMc9bO144" target="_blank">donation</a>
</p> </p>
<div class="d-flex justify-content-center"> <div class="d-flex justify-content-center">
<h6 class="display-7 mt-2">Hometown Shoutout</h6> <h6 class="display-7 mt-2">Hometown Shoutout</h6>
@@ -251,6 +251,7 @@
</ul> </ul>
</div> </div>
</div> </div>
@await Html.PartialAsync("_Sponsors", Model.Sponsors)
<div class="modal fade" data-bs-focus="false" id="extraFieldModal" tabindex="-1" role="dialog" aria-hidden="true"> <div class="modal fade" data-bs-focus="false" id="extraFieldModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document"> <div class="modal-dialog modal-lg" role="document">
<div class="modal-content" id="extraFieldModalContent"> <div class="modal-content" id="extraFieldModalContent">

View File

@@ -0,0 +1,73 @@
@using CarCareTracker.Helper
@model Sponsors
@inject ITranslationHelper translator
@inject IConfigHelper config
@{
var userConfig = config.GetUserConfig(User);
var enableAuth = userConfig.EnableAuth;
var userLanguage = userConfig.UserLanguage;
}
<div class="row">
<div class="d-flex justify-content-center">
<h6 class="display-6 mt-2">@translator.Translate(userLanguage, "Sponsors")</h6>
</div>
<hr />
<div class="col-12">
<div class="d-flex justify-content-center">
<p><a class="link-body-emphasis link-offset-2 link-underline-opacity-25 link-underline-opacity-100-hover" href="https://docs.lubelogger.com/Funding" target="_blank">Become a Sponsor</a></p>
</div>
</div>
@if (Model.LifeTime.Any())
{
<div class="col-12">
<div class="d-flex justify-content-center">
<h6 class="display-7 mt-2">Lifetime</h6>
</div>
<div class="d-flex justify-content-center">
<p class="lead">
@string.Join(", ", Model.LifeTime)
</p>
</div>
</div>
}
@if (Model.Gold.Any())
{
<div class="col-12">
<div class="d-flex justify-content-center">
<h6 class="display-7 mt-2">Gold</h6>
</div>
<div class="d-flex justify-content-center">
<p class="lead">
@string.Join(", ", Model.Gold)
</p>
</div>
</div>
}
@if (Model.Silver.Any())
{
<div class="col-12">
<div class="d-flex justify-content-center">
<h6 class="display-7 mt-2">Silver</h6>
</div>
<div class="d-flex justify-content-center">
<p class="lead">
@string.Join(", ", Model.Silver)
</p>
</div>
</div>
}
@if (Model.Bronze.Any())
{
<div class="col-12">
<div class="d-flex justify-content-center">
<h6 class="display-7 mt-2">Bronze</h6>
</div>
<div class="d-flex justify-content-center">
<p class="lead">
@string.Join(", ", Model.Bronze)
</p>
</div>
</div>
}
</div>

View File

@@ -70,8 +70,8 @@
} }
function globalParseFloat(input){ function globalParseFloat(input){
//remove thousands separator. //remove thousands separator.
var thousandSeparator = "@numberFormat.NumberGroupSeparator"; var thousandSeparator = decodeHTMLEntities("@numberFormat.NumberGroupSeparator");
var decimalSeparator = "@numberFormat.NumberDecimalSeparator"; var decimalSeparator = decodeHTMLEntities("@numberFormat.NumberDecimalSeparator");
var currencySymbol = decodeHTMLEntities("@numberFormat.CurrencySymbol"); var currencySymbol = decodeHTMLEntities("@numberFormat.CurrencySymbol");
if (input == "---") { if (input == "---") {
input = "0"; input = "0";
@@ -85,13 +85,32 @@
return parseFloat(input); return parseFloat(input);
} }
function globalFloatToString(input) { function globalFloatToString(input) {
var decimalSeparator = "@numberFormat.NumberDecimalSeparator"; var decimalSeparator = decodeHTMLEntities("@numberFormat.NumberDecimalSeparator");
input = input.replace(".", decimalSeparator); input = input.replace(".", decimalSeparator);
return input; return input;
} }
function genericErrorMessage(){ function genericErrorMessage(){
return decodeHTMLEntities('@translator.Translate(userLanguage, "An error has occurred, please try again later")'); return decodeHTMLEntities('@translator.Translate(userLanguage, "An error has occurred, please try again later")');
} }
function globalAppendCurrency(input){
//check currency symbol position
var currencySymbolPosition = "@numberFormat.CurrencyPositivePattern";
var currencySymbol = decodeHTMLEntities("@numberFormat.CurrencySymbol");
switch (currencySymbolPosition) {
case "0":
return `${currencySymbol}${input}`;
break;
case "1":
return `${input}${currencySymbol}`;
break;
case "2":
return `${currencySymbol} ${input}`;
break;
case "3":
return `${input} ${currencySymbol}`;
break;
}
}
</script> </script>
@await RenderSectionAsync("Scripts", required: false) @await RenderSectionAsync("Scripts", required: false)
</head> </head>

View File

@@ -28,7 +28,7 @@
@if (isNew) @if (isNew)
{ {
<div class="input-group-text"> <div class="input-group-text">
<button type="button" class="btn btn-sm btn-primary zero-y-padding" onclick="getLastOdometerReadingAndIncrement('collisionRecordMileage')">+</button> <button type="button" class="btn btn-sm btn-primary zero-y-padding" onclick="getLastOdometerReadingAndIncrement('collisionRecordMileage')"><i class="bi bi-plus"></i></button>
</div> </div>
} }
</div> </div>

View File

@@ -17,23 +17,23 @@
consumptionUnit = "kWh"; consumptionUnit = "kWh";
} else if (useUKMPG) } else if (useUKMPG)
{ {
consumptionUnit = "liters"; consumptionUnit = @translator.Translate(userLanguage, "liters");
} }
else else
{ {
consumptionUnit = useMPG ? "gallons" : "liters"; consumptionUnit = useMPG ? @translator.Translate(userLanguage, "gallons") : @translator.Translate(userLanguage, "liters");
} }
if (useHours) if (useHours)
{ {
distanceUnit = "hours"; distanceUnit = @translator.Translate(userLanguage, "hours");
} }
else if (useUKMPG) else if (useUKMPG)
{ {
distanceUnit = "miles"; distanceUnit = @translator.Translate(userLanguage, "miles");
} }
else else
{ {
distanceUnit = useMPG ? "miles" : "kilometers"; distanceUnit = useMPG ? @translator.Translate(userLanguage, "miles") : @translator.Translate(userLanguage, "kilometers");
} }
} }
<div class="modal-header"> <div class="modal-header">
@@ -57,7 +57,7 @@
@if (isNew) @if (isNew)
{ {
<div class="input-group-text"> <div class="input-group-text">
<button type="button" class="btn btn-sm btn-primary zero-y-padding" onclick="getLastOdometerReadingAndIncrement('gasRecordMileage')">+</button> <button type="button" class="btn btn-sm btn-primary zero-y-padding" onclick="getLastOdometerReadingAndIncrement('gasRecordMileage')"><i class="bi bi-plus"></i></button>
</div> </div>
} }
</div> </div>

View File

@@ -23,14 +23,22 @@
<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="initialOdometerRecordMileage">@translator.Translate(userLanguage, "Initial Odometer")</label> <label for="initialOdometerRecordMileage">@translator.Translate(userLanguage, "Initial Odometer")</label>
<input type="number" inputmode="numeric" id="initialOdometerRecordMileage" class="form-control" placeholder="@translator.Translate(userLanguage,"Initial Odometer reading")" value="@(Model.InitialMileage)"> <div class="input-group">
<input type="number" inputmode="numeric" id="initialOdometerRecordMileage" @(Model.InitialMileage != default ? "disabled" : "") class="form-control" placeholder="@translator.Translate(userLanguage,"Initial Odometer reading")" value="@(Model.InitialMileage)">
@if (Model.InitialMileage != default)
{
<div class="input-group-text">
<button type="button" class="btn btn-sm btn-secondary zero-y-padding" onclick="toggleInitialOdometerEnabled()"><i class="bi bi-pencil"></i></button>
</div>
}
</div>
<label for="odometerRecordMileage">@translator.Translate(userLanguage,"Odometer")</label> <label for="odometerRecordMileage">@translator.Translate(userLanguage,"Odometer")</label>
<div class="input-group"> <div class="input-group">
<input type="number" inputmode="numeric" id="odometerRecordMileage" class="form-control" placeholder="@translator.Translate(userLanguage,"Odometer reading")" value="@(isNew ? "" : Model.Mileage)"> <input type="number" inputmode="numeric" id="odometerRecordMileage" class="form-control" placeholder="@translator.Translate(userLanguage,"Odometer reading")" value="@(isNew ? "" : Model.Mileage)">
@if (isNew) @if (isNew)
{ {
<div class="input-group-text"> <div class="input-group-text">
<button type="button" class="btn btn-sm btn-primary zero-y-padding" onclick="getLastOdometerReadingAndIncrement('odometerRecordMileage')">+</button> <button type="button" class="btn btn-sm btn-primary zero-y-padding" onclick="getLastOdometerReadingAndIncrement('odometerRecordMileage')"><i class="bi bi-plus"></i></button>
</div> </div>
} }
</div> </div>

View File

@@ -37,7 +37,7 @@
@if (isNew) @if (isNew)
{ {
<div class="input-group-text"> <div class="input-group-text">
<button type="button" class="btn btn-sm btn-primary zero-y-padding" onclick="getLastOdometerReadingAndIncrement('reminderMileage')">+</button> <button type="button" class="btn btn-sm btn-primary zero-y-padding" onclick="getLastOdometerReadingAndIncrement('reminderMileage')"><i class="bi bi-plus"></i></button>
</div> </div>
} }
</div> </div>

View File

@@ -12,7 +12,7 @@
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<select class="form-select" id="yearOption" onchange="yearUpdated()"> <select class="form-select" id="yearOption" onchange="yearUpdated()">
<option value="0">All Time</option> <option value="0">@translator.Translate(userLanguage, "All Time")</option>
@foreach (int year in Model.Years) @foreach (int year in Model.Years)
{ {
<option value="@year">@year</option> <option value="@year">@year</option>
@@ -32,7 +32,7 @@
<div class="col-12 col-md-10"> <div class="col-12 col-md-10">
<div class="dropdown d-grid dropdown-center"> <div class="dropdown d-grid dropdown-center">
<button class="btn btn-outline-warning dropdown-toggle" type="button" data-bs-toggle="dropdown" data-bs-auto-close="outside" aria-expanded="false"> <button class="btn btn-outline-warning dropdown-toggle" type="button" data-bs-toggle="dropdown" data-bs-auto-close="outside" aria-expanded="false">
Metrics @translator.Translate(userLanguage, "Metrics")
</button> </button>
<ul class="dropdown-menu" style="width:100%;"> <ul class="dropdown-menu" style="width:100%;">
<li class="dropdown-item"> <li class="dropdown-item">

View File

@@ -28,7 +28,7 @@
@if (isNew) @if (isNew)
{ {
<div class="input-group-text"> <div class="input-group-text">
<button type="button" class="btn btn-sm btn-primary zero-y-padding" onclick="getLastOdometerReadingAndIncrement('serviceRecordMileage')">+</button> <button type="button" class="btn btn-sm btn-primary zero-y-padding" onclick="getLastOdometerReadingAndIncrement('serviceRecordMileage')"><i class="bi bi-plus"></i></button>
</div> </div>
} }
</div> </div>

View File

@@ -34,7 +34,7 @@
<div class="input-group"> <div class="input-group">
<input type="text" inputmode="decimal" id="supplyRecordQuantity" class="form-control" placeholder="@translator.Translate(userLanguage,"Quantity")" value="@(isNew ? "1" : Model.Quantity)"> <input type="text" inputmode="decimal" id="supplyRecordQuantity" class="form-control" placeholder="@translator.Translate(userLanguage,"Quantity")" value="@(isNew ? "1" : Model.Quantity)">
<div class="input-group-text"> <div class="input-group-text">
<button type="button" class="btn btn-sm zero-y-padding btn-primary" onclick="replenishSupplies()">+</button> <button type="button" class="btn btn-sm zero-y-padding btn-primary" onclick="replenishSupplies()"><i class="bi bi-plus"></i></button>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -110,7 +110,7 @@
var inStockQuantity = globalParseFloat(inStock.text()); var inStockQuantity = globalParseFloat(inStock.text());
var unitPrice = globalParseFloat(priceField.text()); var unitPrice = globalParseFloat(priceField.text());
//validation //validation
if (isNaN(requestedQuantity) || requestedQuantity > inStockQuantity) { if (isNaN(requestedQuantity) || requestedQuantity > inStockQuantity || requestedQuantity <= 0) {
textField.addClass("is-invalid"); textField.addClass("is-invalid");
hasError = true; hasError = true;
} else { } else {
@@ -131,7 +131,7 @@
var parsedFloat = globalFloatToString(totalSum); var parsedFloat = globalFloatToString(totalSum);
$("#supplySumLabel").text(`Total: ${parsedFloat}`); $("#supplySumLabel").text(`Total: ${parsedFloat}`);
} }
$("#selectSuppliesButton").attr('disabled', (hasError || totalSum == 0)); $("#selectSuppliesButton").attr('disabled', (hasError || selectedSupplies.toArray().length == 0));
if (!hasError) { if (!hasError) {
return { return {
totalSum: globalFloatToString(totalSum), totalSum: globalFloatToString(totalSum),

View File

@@ -28,7 +28,7 @@
@if (isNew) @if (isNew)
{ {
<div class="input-group-text"> <div class="input-group-text">
<button type="button" class="btn btn-sm btn-primary zero-y-padding" onclick="getLastOdometerReadingAndIncrement('upgradeRecordMileage')">+</button> <button type="button" class="btn btn-sm btn-primary zero-y-padding" onclick="getLastOdometerReadingAndIncrement('upgradeRecordMileage')"><i class="bi bi-plus"></i></button>
</div> </div>
} }
</div> </div>

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@@ -341,6 +341,47 @@ function showAccountInformationModal() {
$('#accountInformationModal').modal('show'); $('#accountInformationModal').modal('show');
}) })
} }
function showRootAccountInformationModal() {
$.get('/Home/GetRootAccountInformationModal', function (data) {
$('#accountInformationModalContent').html(data);
$('#accountInformationModal').modal('show');
})
}
function validateAndSaveRootUserAccount() {
var hasError = false;
if ($('#inputUsername').val().trim() == '') {
$('#inputUsername').addClass("is-invalid");
hasError = true;
} else {
$('#inputUsername').removeClass("is-invalid");
}
if ($('#inputPassword').val().trim() == '') {
$('#inputPassword').addClass("is-invalid");
hasError = true;
} else {
$('#inputPassword').removeClass("is-invalid");
}
if (hasError) {
errorToast("Please check the form data");
return;
}
var userAccountInfo = {
userName: $('#inputUsername').val(),
password: $('#inputPassword').val()
}
$.post('/Login/CreateLoginCreds', { credentials: userAccountInfo }, function (data) {
if (data) {
//hide modal
hideAccountInformationModal();
successToast('Root Account Updated');
performLogOut();
} else {
errorToast(data.message);
}
});
}
function hideAccountInformationModal() { function hideAccountInformationModal() {
$('#accountInformationModal').modal('hide'); $('#accountInformationModal').modal('hide');
} }

View File

@@ -182,7 +182,7 @@ function convertGasConsumptionUnits(currentUnit, destinationUnit, save) {
$("[data-gas-type='unitcost']").map((index, elem) => { $("[data-gas-type='unitcost']").map((index, elem) => {
var convertedAmount = globalParseFloat(elem.innerText) / 3.785; var convertedAmount = globalParseFloat(elem.innerText) / 3.785;
var decimalPoints = getGlobalConfig().useThreeDecimals ? 3 : 2; var decimalPoints = getGlobalConfig().useThreeDecimals ? 3 : 2;
elem.innerText = `${getGlobalConfig().currencySymbol}${globalFloatToString(convertedAmount.toFixed(decimalPoints))}`; elem.innerText = `${globalAppendCurrency(globalFloatToString(convertedAmount.toFixed(decimalPoints)))}`;
}); });
if (save) { setDebounce(saveUserGasTabPreferences); } if (save) { setDebounce(saveUserGasTabPreferences); }
break; break;
@@ -196,7 +196,7 @@ function convertGasConsumptionUnits(currentUnit, destinationUnit, save) {
$("[data-gas-type='unitcost']").map((index, elem) => { $("[data-gas-type='unitcost']").map((index, elem) => {
var convertedAmount = globalParseFloat(elem.innerText) * 1.201; var convertedAmount = globalParseFloat(elem.innerText) * 1.201;
var decimalPoints = getGlobalConfig().useThreeDecimals ? 3 : 2; var decimalPoints = getGlobalConfig().useThreeDecimals ? 3 : 2;
elem.innerText = `${getGlobalConfig().currencySymbol}${globalFloatToString(convertedAmount.toFixed(decimalPoints))}`; elem.innerText = `${globalAppendCurrency(globalFloatToString(convertedAmount.toFixed(decimalPoints)))}`;
}); });
if (save) { setDebounce(saveUserGasTabPreferences); } if (save) { setDebounce(saveUserGasTabPreferences); }
break; break;
@@ -213,7 +213,7 @@ function convertGasConsumptionUnits(currentUnit, destinationUnit, save) {
$("[data-gas-type='unitcost']").map((index, elem) => { $("[data-gas-type='unitcost']").map((index, elem) => {
var convertedAmount = globalParseFloat(elem.innerText) * 3.785; var convertedAmount = globalParseFloat(elem.innerText) * 3.785;
var decimalPoints = getGlobalConfig().useThreeDecimals ? 3 : 2; var decimalPoints = getGlobalConfig().useThreeDecimals ? 3 : 2;
elem.innerText = `${getGlobalConfig().currencySymbol}${globalFloatToString(convertedAmount.toFixed(decimalPoints))}`; elem.innerText = `${globalAppendCurrency(globalFloatToString(convertedAmount.toFixed(decimalPoints)))}`;
}); });
if (save) { setDebounce(saveUserGasTabPreferences); } if (save) { setDebounce(saveUserGasTabPreferences); }
break; break;
@@ -227,7 +227,7 @@ function convertGasConsumptionUnits(currentUnit, destinationUnit, save) {
$("[data-gas-type='unitcost']").map((index, elem) => { $("[data-gas-type='unitcost']").map((index, elem) => {
var convertedAmount = globalParseFloat(elem.innerText) * 4.546; var convertedAmount = globalParseFloat(elem.innerText) * 4.546;
var decimalPoints = getGlobalConfig().useThreeDecimals ? 3 : 2; var decimalPoints = getGlobalConfig().useThreeDecimals ? 3 : 2;
elem.innerText = `${getGlobalConfig().currencySymbol}${globalFloatToString(convertedAmount.toFixed(decimalPoints))}`; elem.innerText = `${globalAppendCurrency(globalFloatToString(convertedAmount.toFixed(decimalPoints)))}`;
}); });
if (save) { setDebounce(saveUserGasTabPreferences); } if (save) { setDebounce(saveUserGasTabPreferences); }
break; break;
@@ -244,7 +244,7 @@ function convertGasConsumptionUnits(currentUnit, destinationUnit, save) {
$("[data-gas-type='unitcost']").map((index, elem) => { $("[data-gas-type='unitcost']").map((index, elem) => {
var convertedAmount = globalParseFloat(elem.innerText) / 1.201; var convertedAmount = globalParseFloat(elem.innerText) / 1.201;
var decimalPoints = getGlobalConfig().useThreeDecimals ? 3 : 2; var decimalPoints = getGlobalConfig().useThreeDecimals ? 3 : 2;
elem.innerText = `${getGlobalConfig().currencySymbol}${globalFloatToString(convertedAmount.toFixed(decimalPoints))}`; elem.innerText = `${globalAppendCurrency(globalFloatToString(convertedAmount.toFixed(decimalPoints)))}`;
}); });
if (save) { setDebounce(saveUserGasTabPreferences); } if (save) { setDebounce(saveUserGasTabPreferences); }
break; break;
@@ -258,7 +258,7 @@ function convertGasConsumptionUnits(currentUnit, destinationUnit, save) {
$("[data-gas-type='unitcost']").map((index, elem) => { $("[data-gas-type='unitcost']").map((index, elem) => {
var convertedAmount = globalParseFloat(elem.innerText) / 4.546; var convertedAmount = globalParseFloat(elem.innerText) / 4.546;
var decimalPoints = getGlobalConfig().useThreeDecimals ? 3 : 2; var decimalPoints = getGlobalConfig().useThreeDecimals ? 3 : 2;
elem.innerText = `${getGlobalConfig().currencySymbol}${globalFloatToString(convertedAmount.toFixed(decimalPoints))}`; elem.innerText = `${globalAppendCurrency(globalFloatToString(convertedAmount.toFixed(decimalPoints)))}`;
}); });
if (save) { setDebounce(saveUserGasTabPreferences); } if (save) { setDebounce(saveUserGasTabPreferences); }
break; break;

View File

@@ -208,4 +208,12 @@ function saveMultipleOdometerRecordsToVehicle() {
errorToast(genericErrorMessage()); errorToast(genericErrorMessage());
} }
}) })
}
function toggleInitialOdometerEnabled() {
if ($("#initialOdometerRecordMileage").prop("disabled")) {
$("#initialOdometerRecordMileage").prop("disabled", false);
} else {
$("#initialOdometerRecordMileage").prop("disabled", true);
}
} }

View File

@@ -178,8 +178,8 @@ function uploadFileAsync(event) {
}); });
} }
function isValidMoney(input) { function isValidMoney(input) {
const euRegex = /^\$?(?=\(.*\)|[^()]*$)\(?\d{1,3}(\.?\d{3})?(,\d{1,3}?)?\)?$/; const euRegex = /^\$?(?=\(.*\)|[^()]*$)\(?\d{1,3}((\.\d{3}){0,8}|(\d{3}){0,8})(,\d{1,3}?)?\)?$/;
const usRegex = /^\$?(?=\(.*\)|[^()]*$)\(?\d{1,3}(,?\d{3})?(\.\d{1,3}?)?\)?$/; const usRegex = /^\$?(?=\(.*\)|[^()]*$)\(?\d{1,3}((,\d{3}){0,8}|(\d{3}){0,8})(\.\d{1,3}?)?\)?$/;
return (euRegex.test(input) || usRegex.test(input)); return (euRegex.test(input) || usRegex.test(input));
} }
function initDatePicker(input, futureOnly) { function initDatePicker(input, futureOnly) {
@@ -339,7 +339,7 @@ function updateAggregateLabels() {
if (labelsToSum.length > 0) { if (labelsToSum.length > 0) {
newSum = labelsToSum.map(x => globalParseFloat(x.textContent)).reduce((a, b,) => a + b).toFixed(2); newSum = labelsToSum.map(x => globalParseFloat(x.textContent)).reduce((a, b,) => a + b).toFixed(2);
} }
sumLabel.text(`${sumLabel.text().split(':')[0]}: ${getGlobalConfig().currencySymbol}${newSum}`) sumLabel.text(`${sumLabel.text().split(':')[0]}: ${globalAppendCurrency(globalFloatToString(newSum))}`)
} }
//Sum Distance //Sum Distance
var sumDistanceLabel = $("[data-aggregate-type='sum-distance']"); var sumDistanceLabel = $("[data-aggregate-type='sum-distance']");
@@ -1053,4 +1053,4 @@ function bindModalInputChanges(modalName) {
$(`#${modalName} select, #${modalName} input[type='checkbox']`).off('input').on('input', function (e) { $(`#${modalName} select, #${modalName} input[type='checkbox']`).off('input').on('input', function (e) {
$(e.currentTarget).attr('data-changed', true); $(e.currentTarget).attr('data-changed', true);
}); });
} }

View File

@@ -480,9 +480,9 @@ function getRecordsDeltaStats(recordIds) {
var diffOdo = maxOdo - minOdo; var diffOdo = maxOdo - minOdo;
var diffDate = maxDate - minDate; var diffDate = maxDate - minDate;
var divisibleCount = recordIds.length - 1; var divisibleCount = recordIds.length - 1;
var averageOdo = diffOdo > 0 ? (diffOdo / divisibleCount).toFixed(2) : 0; var averageOdo = diffOdo > 0 ? (diffOdo / divisibleCount).toFixed(2) : '0';
var averageDays = diffDate > 0 ? Math.floor((diffDate / divisibleCount) / 8.64e7) : 0; var averageDays = diffDate > 0 ? Math.floor((diffDate / divisibleCount) / 8.64e7) : '0';
var averageSum = costSum > 0 ? (costSum / recordIds.length).toFixed(2) : 0; var averageSum = costSum > 0 ? (costSum / recordIds.length).toFixed(2) : '0';
costSum = costSum.toFixed(2); costSum = costSum.toFixed(2);
Swal.fire({ Swal.fire({
title: "Record Statistics", title: "Record Statistics",
@@ -490,9 +490,9 @@ function getRecordsDeltaStats(recordIds) {
<br /> <br />
<p>Average Days between Records: ${averageDays}</p> <p>Average Days between Records: ${averageDays}</p>
<br /> <br />
<p>Total Cost: ${getGlobalConfig().currencySymbol} ${globalFloatToString(costSum)}</p> <p>Total Cost: ${globalAppendCurrency(globalFloatToString(costSum))}</p>
<br /> <br />
<p>Average Cost: ${getGlobalConfig().currencySymbol} ${globalFloatToString(averageSum)}</p>` <p>Average Cost: ${globalAppendCurrency(globalFloatToString(averageSum))}</p>`
, ,
icon: "info" icon: "info"
}); });

View File

@@ -6,22 +6,44 @@
{ {
"src": "/defaults/lubelogger_icon_72.png", "src": "/defaults/lubelogger_icon_72.png",
"sizes": "72x72", "sizes": "72x72",
"type": "image/png" "type": "image/png",
"purpose": "any"
},
{
"src": "/defaults/lubelogger_maskable_icon_72.png",
"sizes": "72x72",
"type": "image/png",
"purpose": "maskable"
}, },
{ {
"src": "/defaults/lubelogger_icon_128.png", "src": "/defaults/lubelogger_icon_128.png",
"sizes": "128x128", "sizes": "128x128",
"type": "image/png" "type": "image/png",
"purpose": "any"
},
{
"src": "/defaults/lubelogger_maskable_icon_128.png",
"sizes": "128x128",
"type": "image/png",
"purpose": "maskable"
}, },
{ {
"src": "/defaults/lubelogger_icon_144.png", "src": "/defaults/lubelogger_icon_144.png",
"sizes": "144x144", "sizes": "144x144",
"type": "image/png" "type": "image/png",
"purpose": "any"
}, },
{ {
"src": "/defaults/lubelogger_icon_192.png", "src": "/defaults/lubelogger_icon_192.png",
"sizes": "192x192", "sizes": "192x192",
"type": "image/png" "type": "image/png",
"purpose": "any"
},
{
"src": "/defaults/lubelogger_maskable_icon_192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
} }
], ],
"screenshots": [ "screenshots": [

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long