Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
64ea0e2eee | ||
|
|
7ab476a88f | ||
|
|
de41ca911d | ||
|
|
dde9688f96 | ||
|
|
c1ca63edc0 | ||
|
|
cbc430499f | ||
|
|
4da9fa4802 | ||
|
|
42586d9556 | ||
|
|
ea4387d4ab | ||
|
|
0707b515ab | ||
|
|
78ae71fc46 | ||
|
|
3f62cd40e7 | ||
|
|
47657c0093 | ||
|
|
a5b0fde4b6 | ||
|
|
78cc0b34b1 | ||
|
|
e3017e986b | ||
|
|
e12cd876db | ||
|
|
5292e4b814 | ||
|
|
dbdd16ab89 |
@@ -105,7 +105,7 @@ namespace CarCareTracker.Controllers
|
||||
var reminderUrgency = _reminderHelper.GetReminderRecordViewModels(new List<ReminderRecord> { reminder }, 0, DateTime.Now).FirstOrDefault();
|
||||
return PartialView("_ReminderRecordCalendarModal", reminderUrgency);
|
||||
}
|
||||
public IActionResult Settings()
|
||||
public async Task<IActionResult> Settings()
|
||||
{
|
||||
var userConfig = _config.GetUserConfig(User);
|
||||
var languages = _fileHelper.GetLanguages();
|
||||
@@ -114,6 +114,16 @@ namespace CarCareTracker.Controllers
|
||||
UserConfig = userConfig,
|
||||
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);
|
||||
}
|
||||
[HttpPost]
|
||||
|
||||
@@ -146,7 +146,11 @@ namespace CarCareTracker.Helper
|
||||
using (var client = new SmtpClient())
|
||||
{
|
||||
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
|
||||
{
|
||||
client.Send(message);
|
||||
|
||||
@@ -8,13 +8,13 @@ namespace CarCareTracker.Helper
|
||||
/// </summary>
|
||||
public static class StaticHelper
|
||||
{
|
||||
public static string VersionNumber = "1.3.2";
|
||||
public static string VersionNumber = "1.3.4";
|
||||
public static string DbName = "data/cartracker.db";
|
||||
public static string UserConfigPath = "config/userConfig.json";
|
||||
public static string GenericErrorMessage = "An error occurred, please try again later";
|
||||
public static string ReminderEmailTemplate = "defaults/reminderemailtemplate.txt";
|
||||
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)
|
||||
{
|
||||
switch (input)
|
||||
|
||||
7
LICENSE
7
LICENSE
@@ -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
|
||||
|
||||
Copyright (c) 2023 Hargata Softworks
|
||||
Copyright (c) 2024 Hargata Softworks
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -4,5 +4,6 @@ namespace CarCareTracker.Models
|
||||
{
|
||||
public UserConfig UserConfig { get; set; }
|
||||
public List<string> UILanguages { get; set; }
|
||||
public Sponsors Sponsors { get; set; } = new Sponsors();
|
||||
}
|
||||
}
|
||||
|
||||
10
Models/Sponsors.cs
Normal file
10
Models/Sponsors.cs
Normal 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>();
|
||||
}
|
||||
}
|
||||
@@ -41,9 +41,7 @@ Read this [Getting Started Guide](https://docs.lubelogger.com/Getting%20Started)
|
||||
- [MailKit](https://github.com/jstedfast/MailKit)
|
||||
|
||||
## License
|
||||
LubeLogger utilizes a dual-licensing model, see [License](/LICENSE) for more information
|
||||
MIT
|
||||
|
||||
## Support
|
||||
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.
|
||||
Support this project by [Subscribing on Patreon](https://patreon.com/LubeLogger) or [Making a Donation](https://buy.stripe.com/aEU9Egc8DdMc9bO144)
|
||||
@@ -219,7 +219,7 @@
|
||||
</p>
|
||||
<p class="lead">
|
||||
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>
|
||||
<div class="d-flex justify-content-center">
|
||||
<h6 class="display-7 mt-2">Hometown Shoutout</h6>
|
||||
@@ -251,6 +251,7 @@
|
||||
</ul>
|
||||
</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-dialog modal-lg" role="document">
|
||||
<div class="modal-content" id="extraFieldModalContent">
|
||||
|
||||
73
Views/Home/_Sponsors.cshtml
Normal file
73
Views/Home/_Sponsors.cshtml
Normal 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>
|
||||
|
||||
@@ -70,8 +70,8 @@
|
||||
}
|
||||
function globalParseFloat(input){
|
||||
//remove thousands separator.
|
||||
var thousandSeparator = "@numberFormat.NumberGroupSeparator";
|
||||
var decimalSeparator = "@numberFormat.NumberDecimalSeparator";
|
||||
var thousandSeparator = decodeHTMLEntities("@numberFormat.NumberGroupSeparator");
|
||||
var decimalSeparator = decodeHTMLEntities("@numberFormat.NumberDecimalSeparator");
|
||||
var currencySymbol = decodeHTMLEntities("@numberFormat.CurrencySymbol");
|
||||
if (input == "---") {
|
||||
input = "0";
|
||||
@@ -85,13 +85,32 @@
|
||||
return parseFloat(input);
|
||||
}
|
||||
function globalFloatToString(input) {
|
||||
var decimalSeparator = "@numberFormat.NumberDecimalSeparator";
|
||||
var decimalSeparator = decodeHTMLEntities("@numberFormat.NumberDecimalSeparator");
|
||||
input = input.replace(".", decimalSeparator);
|
||||
return input;
|
||||
}
|
||||
function genericErrorMessage(){
|
||||
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>
|
||||
@await RenderSectionAsync("Scripts", required: false)
|
||||
</head>
|
||||
|
||||
@@ -17,23 +17,23 @@
|
||||
consumptionUnit = "kWh";
|
||||
} else if (useUKMPG)
|
||||
{
|
||||
consumptionUnit = "liters";
|
||||
consumptionUnit = @translator.Translate(userLanguage, "liters");
|
||||
}
|
||||
else
|
||||
{
|
||||
consumptionUnit = useMPG ? "gallons" : "liters";
|
||||
consumptionUnit = useMPG ? @translator.Translate(userLanguage, "gallons") : @translator.Translate(userLanguage, "liters");
|
||||
}
|
||||
if (useHours)
|
||||
{
|
||||
distanceUnit = "hours";
|
||||
distanceUnit = @translator.Translate(userLanguage, "hours");
|
||||
}
|
||||
else if (useUKMPG)
|
||||
{
|
||||
distanceUnit = "miles";
|
||||
distanceUnit = @translator.Translate(userLanguage, "miles");
|
||||
}
|
||||
else
|
||||
{
|
||||
distanceUnit = useMPG ? "miles" : "kilometers";
|
||||
distanceUnit = useMPG ? @translator.Translate(userLanguage, "miles") : @translator.Translate(userLanguage, "kilometers");
|
||||
}
|
||||
}
|
||||
<div class="modal-header">
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<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)
|
||||
{
|
||||
<option value="@year">@year</option>
|
||||
@@ -32,7 +32,7 @@
|
||||
<div class="col-12 col-md-10">
|
||||
<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">
|
||||
Metrics
|
||||
@translator.Translate(userLanguage, "Metrics")
|
||||
</button>
|
||||
<ul class="dropdown-menu" style="width:100%;">
|
||||
<li class="dropdown-item">
|
||||
|
||||
@@ -110,7 +110,7 @@
|
||||
var inStockQuantity = globalParseFloat(inStock.text());
|
||||
var unitPrice = globalParseFloat(priceField.text());
|
||||
//validation
|
||||
if (isNaN(requestedQuantity) || requestedQuantity > inStockQuantity) {
|
||||
if (isNaN(requestedQuantity) || requestedQuantity > inStockQuantity || requestedQuantity <= 0) {
|
||||
textField.addClass("is-invalid");
|
||||
hasError = true;
|
||||
} else {
|
||||
@@ -131,7 +131,7 @@
|
||||
var parsedFloat = globalFloatToString(totalSum);
|
||||
$("#supplySumLabel").text(`Total: ${parsedFloat}`);
|
||||
}
|
||||
$("#selectSuppliesButton").attr('disabled', (hasError || totalSum == 0));
|
||||
$("#selectSuppliesButton").attr('disabled', (hasError || selectedSupplies.toArray().length == 0));
|
||||
if (!hasError) {
|
||||
return {
|
||||
totalSum: globalFloatToString(totalSum),
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -182,7 +182,7 @@ function convertGasConsumptionUnits(currentUnit, destinationUnit, save) {
|
||||
$("[data-gas-type='unitcost']").map((index, elem) => {
|
||||
var convertedAmount = globalParseFloat(elem.innerText) / 3.785;
|
||||
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); }
|
||||
break;
|
||||
@@ -196,7 +196,7 @@ function convertGasConsumptionUnits(currentUnit, destinationUnit, save) {
|
||||
$("[data-gas-type='unitcost']").map((index, elem) => {
|
||||
var convertedAmount = globalParseFloat(elem.innerText) * 1.201;
|
||||
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); }
|
||||
break;
|
||||
@@ -213,7 +213,7 @@ function convertGasConsumptionUnits(currentUnit, destinationUnit, save) {
|
||||
$("[data-gas-type='unitcost']").map((index, elem) => {
|
||||
var convertedAmount = globalParseFloat(elem.innerText) * 3.785;
|
||||
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); }
|
||||
break;
|
||||
@@ -227,7 +227,7 @@ function convertGasConsumptionUnits(currentUnit, destinationUnit, save) {
|
||||
$("[data-gas-type='unitcost']").map((index, elem) => {
|
||||
var convertedAmount = globalParseFloat(elem.innerText) * 4.546;
|
||||
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); }
|
||||
break;
|
||||
@@ -244,7 +244,7 @@ function convertGasConsumptionUnits(currentUnit, destinationUnit, save) {
|
||||
$("[data-gas-type='unitcost']").map((index, elem) => {
|
||||
var convertedAmount = globalParseFloat(elem.innerText) / 1.201;
|
||||
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); }
|
||||
break;
|
||||
@@ -258,7 +258,7 @@ function convertGasConsumptionUnits(currentUnit, destinationUnit, save) {
|
||||
$("[data-gas-type='unitcost']").map((index, elem) => {
|
||||
var convertedAmount = globalParseFloat(elem.innerText) / 4.546;
|
||||
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); }
|
||||
break;
|
||||
|
||||
@@ -339,7 +339,7 @@ function updateAggregateLabels() {
|
||||
if (labelsToSum.length > 0) {
|
||||
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
|
||||
var sumDistanceLabel = $("[data-aggregate-type='sum-distance']");
|
||||
|
||||
@@ -480,9 +480,9 @@ function getRecordsDeltaStats(recordIds) {
|
||||
var diffOdo = maxOdo - minOdo;
|
||||
var diffDate = maxDate - minDate;
|
||||
var divisibleCount = recordIds.length - 1;
|
||||
var averageOdo = diffOdo > 0 ? (diffOdo / divisibleCount).toFixed(2) : 0;
|
||||
var averageDays = diffDate > 0 ? Math.floor((diffDate / divisibleCount) / 8.64e7) : 0;
|
||||
var averageSum = costSum > 0 ? (costSum / recordIds.length).toFixed(2) : 0;
|
||||
var averageOdo = diffOdo > 0 ? (diffOdo / divisibleCount).toFixed(2) : '0';
|
||||
var averageDays = diffDate > 0 ? Math.floor((diffDate / divisibleCount) / 8.64e7) : '0';
|
||||
var averageSum = costSum > 0 ? (costSum / recordIds.length).toFixed(2) : '0';
|
||||
costSum = costSum.toFixed(2);
|
||||
Swal.fire({
|
||||
title: "Record Statistics",
|
||||
@@ -490,9 +490,9 @@ function getRecordsDeltaStats(recordIds) {
|
||||
<br />
|
||||
<p>Average Days between Records: ${averageDays}</p>
|
||||
<br />
|
||||
<p>Total Cost: ${getGlobalConfig().currencySymbol} ${globalFloatToString(costSum)}</p>
|
||||
<p>Total Cost: ${globalAppendCurrency(globalFloatToString(costSum))}</p>
|
||||
<br />
|
||||
<p>Average Cost: ${getGlobalConfig().currencySymbol} ${globalFloatToString(averageSum)}</p>`
|
||||
<p>Average Cost: ${globalAppendCurrency(globalFloatToString(averageSum))}</p>`
|
||||
,
|
||||
icon: "info"
|
||||
});
|
||||
|
||||
File diff suppressed because one or more lines are too long
4
wwwroot/sweetalert/sweetalert2.all.min.js
vendored
4
wwwroot/sweetalert/sweetalert2.all.min.js
vendored
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
5
wwwroot/sweetalert/sweetalert2.min.js
vendored
5
wwwroot/sweetalert/sweetalert2.min.js
vendored
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user