Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
64ea0e2eee | ||
|
|
7ab476a88f | ||
|
|
de41ca911d | ||
|
|
dde9688f96 | ||
|
|
c1ca63edc0 | ||
|
|
cbc430499f | ||
|
|
4da9fa4802 | ||
|
|
42586d9556 | ||
|
|
ea4387d4ab | ||
|
|
0707b515ab | ||
|
|
78ae71fc46 | ||
|
|
3f62cd40e7 | ||
|
|
47657c0093 | ||
|
|
a5b0fde4b6 | ||
|
|
78cc0b34b1 | ||
|
|
e3017e986b | ||
|
|
e12cd876db | ||
|
|
5292e4b814 | ||
|
|
dbdd16ab89 | ||
|
|
ddc3c2e1b5 | ||
|
|
49184b287b | ||
|
|
f6139bda0d | ||
|
|
a6471b823b | ||
|
|
7c34003647 | ||
|
|
1aa21f9980 | ||
|
|
ce4ca50939 | ||
|
|
fb28260c4a | ||
|
|
626a904747 | ||
|
|
893cdafdc5 |
@@ -13,6 +13,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CsvHelper" Version="30.0.1" />
|
<PackageReference Include="CsvHelper" Version="30.0.1" />
|
||||||
<PackageReference Include="LiteDB" Version="5.0.17" />
|
<PackageReference Include="LiteDB" Version="5.0.17" />
|
||||||
|
<PackageReference Include="MailKit" Version="4.5.0" />
|
||||||
<PackageReference Include="Npgsql" Version="8.0.2" />
|
<PackageReference Include="Npgsql" Version="8.0.2" />
|
||||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.3.1" />
|
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.3.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -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]
|
||||||
|
|||||||
@@ -1153,6 +1153,10 @@ namespace CarCareTracker.Controllers
|
|||||||
{
|
{
|
||||||
numbersArray.Add(upgradeRecords.Min(x => x.Date.Year));
|
numbersArray.Add(upgradeRecords.Min(x => x.Date.Year));
|
||||||
}
|
}
|
||||||
|
if (odometerRecords.Any())
|
||||||
|
{
|
||||||
|
numbersArray.Add(odometerRecords.Min(x => x.Date.Year));
|
||||||
|
}
|
||||||
var minYear = numbersArray.Any() ? numbersArray.Min() : DateTime.Now.AddYears(-5).Year;
|
var minYear = numbersArray.Any() ? numbersArray.Min() : DateTime.Now.AddYears(-5).Year;
|
||||||
var yearDifference = DateTime.Now.Year - minYear + 1;
|
var yearDifference = DateTime.Now.Year - minYear + 1;
|
||||||
for (int i = 0; i < yearDifference; i++)
|
for (int i = 0; i < yearDifference; i++)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using CarCareTracker.Models;
|
using CarCareTracker.Models;
|
||||||
using System.Net.Mail;
|
using MimeKit;
|
||||||
using System.Net;
|
using MailKit.Net.Smtp;
|
||||||
|
|
||||||
namespace CarCareTracker.Helper
|
namespace CarCareTracker.Helper
|
||||||
{
|
{
|
||||||
@@ -15,13 +15,16 @@ namespace CarCareTracker.Helper
|
|||||||
{
|
{
|
||||||
private readonly MailConfig mailConfig;
|
private readonly MailConfig mailConfig;
|
||||||
private readonly IFileHelper _fileHelper;
|
private readonly IFileHelper _fileHelper;
|
||||||
|
private readonly ILogger<MailHelper> _logger;
|
||||||
public MailHelper(
|
public MailHelper(
|
||||||
IConfiguration config,
|
IConfiguration config,
|
||||||
IFileHelper fileHelper
|
IFileHelper fileHelper,
|
||||||
|
ILogger<MailHelper> logger
|
||||||
) {
|
) {
|
||||||
//load mailConfig from Configuration
|
//load mailConfig from Configuration
|
||||||
mailConfig = config.GetSection("MailConfig").Get<MailConfig>();
|
mailConfig = config.GetSection("MailConfig").Get<MailConfig>() ?? new MailConfig();
|
||||||
_fileHelper = fileHelper;
|
_fileHelper = fileHelper;
|
||||||
|
_logger = logger;
|
||||||
}
|
}
|
||||||
public OperationResponse NotifyUserForRegistration(string emailAddress, string token)
|
public OperationResponse NotifyUserForRegistration(string emailAddress, string token)
|
||||||
{
|
{
|
||||||
@@ -34,7 +37,7 @@ namespace CarCareTracker.Helper
|
|||||||
}
|
}
|
||||||
string emailSubject = "Your Registration Token for LubeLogger";
|
string emailSubject = "Your Registration Token for LubeLogger";
|
||||||
string emailBody = $"A token has been generated on your behalf, please complete your registration for LubeLogger using the token: {token}";
|
string emailBody = $"A token has been generated on your behalf, please complete your registration for LubeLogger using the token: {token}";
|
||||||
var result = SendEmail(emailAddress, emailSubject, emailBody);
|
var result = SendEmail(new List<string> { emailAddress }, emailSubject, emailBody);
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
return new OperationResponse { Success = true, Message = "Email Sent!" };
|
return new OperationResponse { Success = true, Message = "Email Sent!" };
|
||||||
@@ -55,7 +58,7 @@ namespace CarCareTracker.Helper
|
|||||||
}
|
}
|
||||||
string emailSubject = "Your Password Reset Token for LubeLogger";
|
string emailSubject = "Your Password Reset Token for LubeLogger";
|
||||||
string emailBody = $"A token has been generated on your behalf, please reset your password for LubeLogger using the token: {token}";
|
string emailBody = $"A token has been generated on your behalf, please reset your password for LubeLogger using the token: {token}";
|
||||||
var result = SendEmail(emailAddress, emailSubject, emailBody);
|
var result = SendEmail(new List<string> { emailAddress }, emailSubject, emailBody);
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
return new OperationResponse { Success = true, Message = "Email Sent!" };
|
return new OperationResponse { Success = true, Message = "Email Sent!" };
|
||||||
@@ -77,7 +80,7 @@ namespace CarCareTracker.Helper
|
|||||||
}
|
}
|
||||||
string emailSubject = "Your User Account Update Token for LubeLogger";
|
string emailSubject = "Your User Account Update Token for LubeLogger";
|
||||||
string emailBody = $"A token has been generated on your behalf, please update your account for LubeLogger using the token: {token}";
|
string emailBody = $"A token has been generated on your behalf, please update your account for LubeLogger using the token: {token}";
|
||||||
var result = SendEmail(emailAddress, emailSubject, emailBody);
|
var result = SendEmail(new List<string> { emailAddress}, emailSubject, emailBody);
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
return new OperationResponse { Success = true, Message = "Email Sent!" };
|
return new OperationResponse { Success = true, Message = "Email Sent!" };
|
||||||
@@ -116,43 +119,48 @@ namespace CarCareTracker.Helper
|
|||||||
emailBody = emailBody.Replace("{TableBody}", tableBody);
|
emailBody = emailBody.Replace("{TableBody}", tableBody);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
foreach (string emailAddress in emailAddresses)
|
SendEmail(emailAddresses, emailSubject, emailBody);
|
||||||
{
|
|
||||||
SendEmail(emailAddress, emailSubject, emailBody, true, true);
|
|
||||||
}
|
|
||||||
return new OperationResponse { Success = true, Message = "Email Sent!" };
|
return new OperationResponse { Success = true, Message = "Email Sent!" };
|
||||||
} catch (Exception ex)
|
} catch (Exception ex)
|
||||||
{
|
{
|
||||||
return new OperationResponse { Success = false, Message = ex.Message };
|
return new OperationResponse { Success = false, Message = ex.Message };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private bool SendEmail(string emailTo, string emailSubject, string emailBody, bool isBodyHtml = false, bool useAsync = false) {
|
private bool SendEmail(List<string> emailTo, string emailSubject, string emailBody) {
|
||||||
string to = emailTo;
|
|
||||||
string from = mailConfig.EmailFrom;
|
string from = mailConfig.EmailFrom;
|
||||||
var server = mailConfig.EmailServer;
|
var server = mailConfig.EmailServer;
|
||||||
MailMessage message = new MailMessage(from, to);
|
var message = new MimeMessage();
|
||||||
message.Subject = emailSubject;
|
message.From.Add(new MailboxAddress(from, from));
|
||||||
message.Body = emailBody;
|
foreach(string emailRecipient in emailTo)
|
||||||
message.IsBodyHtml = isBodyHtml;
|
|
||||||
SmtpClient client = new SmtpClient(server);
|
|
||||||
client.EnableSsl = mailConfig.UseSSL;
|
|
||||||
client.Port = mailConfig.Port;
|
|
||||||
client.Credentials = new NetworkCredential(mailConfig.Username, mailConfig.Password);
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
if (useAsync)
|
message.To.Add(new MailboxAddress(emailRecipient, emailRecipient));
|
||||||
{
|
}
|
||||||
client.SendMailAsync(message, new CancellationToken());
|
message.Subject = emailSubject;
|
||||||
|
|
||||||
|
var builder = new BodyBuilder();
|
||||||
|
|
||||||
|
builder.HtmlBody = emailBody;
|
||||||
|
|
||||||
|
message.Body = builder.ToMessageBody();
|
||||||
|
|
||||||
|
using (var client = new SmtpClient())
|
||||||
|
{
|
||||||
|
client.Connect(server, mailConfig.Port, MailKit.Security.SecureSocketOptions.Auto);
|
||||||
|
//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);
|
||||||
}
|
}
|
||||||
else
|
try
|
||||||
{
|
{
|
||||||
client.Send(message);
|
client.Send(message);
|
||||||
|
client.Disconnect(true);
|
||||||
|
return true;
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,13 +8,13 @@ namespace CarCareTracker.Helper
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static class StaticHelper
|
public static class StaticHelper
|
||||||
{
|
{
|
||||||
public static string VersionNumber = "1.3.1";
|
public static string VersionNumber = "1.3.4";
|
||||||
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)
|
||||||
|
|||||||
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
|
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
|
||||||
|
|||||||
@@ -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
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>();
|
||||||
|
}
|
||||||
|
}
|
||||||
23
README.md
23
README.md
@@ -30,19 +30,18 @@ Read this [Getting Started Guide](https://docs.lubelogger.com/Getting%20Started)
|
|||||||
[Search Existing Issues](https://github.com/hargata/lubelog/issues)
|
[Search Existing Issues](https://github.com/hargata/lubelog/issues)
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
- Bootstrap
|
- [Bootstrap](https://github.com/twbs/bootstrap)
|
||||||
- LiteDB
|
- [LiteDB](https://github.com/mbdavid/litedb)
|
||||||
- Npgsql
|
- [Npgsql](https://github.com/npgsql/npgsql)
|
||||||
- Bootstrap-DatePicker
|
- [Bootstrap-DatePicker](https://github.com/uxsolutions/bootstrap-datepicker)
|
||||||
- SweetAlert2
|
- [SweetAlert2](https://github.com/sweetalert2/sweetalert2)
|
||||||
- CsvHelper
|
- [CsvHelper](https://github.com/JoshClose/CsvHelper)
|
||||||
- Chart.js
|
- [Chart.js](https://github.com/chartjs/Chart.js)
|
||||||
- Drawdown
|
- [Drawdown](https://github.com/adamvleggett/drawdown)
|
||||||
|
- [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.
|
|
||||||
@@ -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>
|
||||||
@@ -247,9 +247,11 @@
|
|||||||
<li class="list-group-item">CsvHelper</li>
|
<li class="list-group-item">CsvHelper</li>
|
||||||
<li class="list-group-item">Chart.js</li>
|
<li class="list-group-item">Chart.js</li>
|
||||||
<li class="list-group-item">Drawdown</li>
|
<li class="list-group-item">Drawdown</li>
|
||||||
|
<li class="list-group-item">MailKit</li>
|
||||||
</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">
|
||||||
|
|||||||
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){
|
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>
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
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) => {
|
$("[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;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
function getYear() {
|
function getYear() {
|
||||||
return $("#yearOption").val();
|
return $("#yearOption").val() ?? '0';
|
||||||
}
|
}
|
||||||
function generateVehicleHistoryReport() {
|
function generateVehicleHistoryReport() {
|
||||||
var vehicleId = GetVehicleId().vehicleId;
|
var vehicleId = GetVehicleId().vehicleId;
|
||||||
@@ -54,7 +54,10 @@ function getSelectedMetrics() {
|
|||||||
if (selectedMetricCheckBoxes.length == 6) {
|
if (selectedMetricCheckBoxes.length == 6) {
|
||||||
$("#selectAllExpenseCheck").prop("checked", true);
|
$("#selectAllExpenseCheck").prop("checked", true);
|
||||||
}
|
}
|
||||||
$('#yearOption').val(yearMetric);
|
//check if option is available
|
||||||
|
if ($("#yearOption").has(`option[value=${yearMetric}]`).length > 0) {
|
||||||
|
$('#yearOption').val(yearMetric);
|
||||||
|
}
|
||||||
$("#reminderOption").val(reminderMetric);
|
$("#reminderOption").val(reminderMetric);
|
||||||
//retrieve data.
|
//retrieve data.
|
||||||
yearUpdated();
|
yearUpdated();
|
||||||
|
|||||||
@@ -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']");
|
||||||
|
|||||||
@@ -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"
|
||||||
});
|
});
|
||||||
|
|||||||
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