Merge pull request #1079 from hargata/Hargata/nav.overhaul

Add navigatable tabs.
This commit is contained in:
Hargata Softworks 2025-09-25 12:52:51 -06:00 committed by GitHub
commit 92b5840073
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 158 additions and 126 deletions

View File

@ -55,9 +55,9 @@ namespace CarCareTracker.Controllers
{ {
return int.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)); return int.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier));
} }
public IActionResult Index(string tab = "garage") public IActionResult Index()
{ {
return View(model: tab); return View();
} }
[Route("/kiosk")] [Route("/kiosk")]
public IActionResult Kiosk(string exclusions, KioskMode kioskMode = KioskMode.Vehicle) public IActionResult Kiosk(string exclusions, KioskMode kioskMode = KioskMode.Vehicle)

View File

@ -123,27 +123,13 @@ namespace CarCareTracker.Helper
} }
public static string DefaultActiveTab(UserConfig userConfig, ImportMode tab) public static string DefaultActiveTab(UserConfig userConfig, ImportMode tab)
{ {
var defaultTab = userConfig.DefaultTab;
var visibleTabs = userConfig.VisibleTabs; var visibleTabs = userConfig.VisibleTabs;
if (visibleTabs.Contains(tab) && tab == defaultTab) if (!visibleTabs.Contains(tab))
{
return "active";
}
else if (!visibleTabs.Contains(tab))
{ {
return "d-none"; return "d-none";
} }
return ""; return "";
} }
public static string DefaultActiveTabContent(UserConfig userConfig, ImportMode tab)
{
var defaultTab = userConfig.DefaultTab;
if (tab == defaultTab)
{
return "show active";
}
return "";
}
public static string DefaultTabSelected(UserConfig userConfig, ImportMode tab) public static string DefaultTabSelected(UserConfig userConfig, ImportMode tab)
{ {
var defaultTab = userConfig.DefaultTab; var defaultTab = userConfig.DefaultTab;

View File

@ -5,7 +5,6 @@
var userConfig = config.GetUserConfig(User); var userConfig = config.GetUserConfig(User);
var userLanguage = userConfig.UserLanguage; var userLanguage = userConfig.UserLanguage;
} }
@model string
@{ @{
ViewData["Title"] = "Garage"; ViewData["Title"] = "Garage";
} }
@ -25,7 +24,7 @@
</div> </div>
<ul class="nav nav-tabs lubelogger-tab flex-grow-1" id="homeTab" role="tablist"> <ul class="nav nav-tabs lubelogger-tab flex-grow-1" id="homeTab" role="tablist">
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link resizable-nav-link @(Model == "garage" ? "active" : "")" oncontextmenu="sortGarage(this)" id="garage-tab" data-bs-toggle="tab" data-bs-target="#garage-tab-pane" type="button" role="tab"><i class="bi bi-car-front"></i><span class="ms-2">@translator.Translate(userLanguage, "Garage")</span></button> <button class="nav-link resizable-nav-link" id="garage-tab" data-bs-toggle="tab" data-bs-target="#garage-tab-pane" type="button" role="tab"><i class="bi bi-car-front"></i><span class="ms-2">@translator.Translate(userLanguage, "Garage")</span></button>
</li> </li>
@if (config.GetServerEnableShopSupplies()) @if (config.GetServerEnableShopSupplies())
{ {
@ -45,7 +44,7 @@
</ul> </ul>
</li> </li>
<li class="nav-item ms-auto" role="presentation"> <li class="nav-item ms-auto" role="presentation">
<button class="nav-link resizable-nav-link @(Model == "settings" ? "active" : "")" id="settings-tab" data-bs-toggle="tab" data-bs-target="#settings-tab-pane" type="button" role="tab"><i class="bi bi-gear"></i><span class="ms-2">@translator.Translate(userLanguage, "Settings")</span></button> <button class="nav-link resizable-nav-link" id="settings-tab" data-bs-toggle="tab" data-bs-target="#settings-tab-pane" type="button" role="tab"><i class="bi bi-gear"></i><span class="ms-2">@translator.Translate(userLanguage, "Settings")</span></button>
</li> </li>
@if (User.IsInRole("CookieAuth") || User.IsInRole("APIAuth")) @if (User.IsInRole("CookieAuth") || User.IsInRole("APIAuth"))
{ {
@ -88,7 +87,7 @@
<div class="lubelogger-mobile-nav" onclick="hideMobileNav()"> <div class="lubelogger-mobile-nav" onclick="hideMobileNav()">
<ul class="navbar-nav" id="homeTab" role="tablist"> <ul class="navbar-nav" id="homeTab" role="tablist">
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link user-select-none @(Model == "garage" ? "active" : "")" ontouchstart="detectLongTouch(this)" ontouchend="detectTouchEndPremature(this)" id="garage-tab" data-bs-toggle="tab" data-bs-target="#garage-tab-pane" type="button" role="tab"><span class="ms-2 display-3"><i class="bi bi-car-front me-2"></i>@translator.Translate(userLanguage,"Garage")</span></button> <button class="nav-link" id="garage-tab" data-bs-toggle="tab" data-bs-target="#garage-tab-pane" type="button" role="tab"><span class="ms-2 display-3"><i class="bi bi-car-front me-2"></i>@translator.Translate(userLanguage,"Garage")</span></button>
</li> </li>
@if(config.GetServerEnableShopSupplies()) @if(config.GetServerEnableShopSupplies())
{ {
@ -102,7 +101,7 @@
</li> </li>
} }
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link @(Model == "settings" ? "active" : "")" id="settings-tab" data-bs-toggle="tab" data-bs-target="#settings-tab-pane" type="button" role="tab"><span class="ms-2 display-3"><i class="bi bi-gear me-2"></i>@translator.Translate(userLanguage,"Settings")</span></button> <button class="nav-link" id="settings-tab" data-bs-toggle="tab" data-bs-target="#settings-tab-pane" type="button" role="tab"><span class="ms-2 display-3"><i class="bi bi-gear me-2"></i>@translator.Translate(userLanguage,"Settings")</span></button>
</li> </li>
@if (User.IsInRole("CookieAuth") || User.IsInRole("APIAuth")) @if (User.IsInRole("CookieAuth") || User.IsInRole("APIAuth"))
{ {
@ -131,16 +130,13 @@
</div> </div>
<div class="container"> <div class="container">
<div class="tab-content" id="homeTab"> <div class="tab-content" id="homeTab">
<div class="tab-pane fade @(Model == "garage" ? "show active" : "")" id="garage-tab-pane" role="tabpanel" tabindex="0"> <div class="tab-pane fade" id="garage-tab-pane" role="tabpanel" tabindex="0">
<div id="garageContainer">
</div>
</div> </div>
<div class="tab-pane fade" id="supply-tab-pane" role="tabpanel" tabindex="0"> <div class="tab-pane fade" id="supply-tab-pane" role="tabpanel" tabindex="0">
</div> </div>
<div class="tab-pane fade" id="calendar-tab-pane" role="tabpanel" tabindex="0"> <div class="tab-pane fade" id="calendar-tab-pane" role="tabpanel" tabindex="0">
</div> </div>
<div class="tab-pane fade @(Model == "settings" ? "show active" : "")" id="settings-tab-pane" role="tabpanel" tabindex="0"> <div class="tab-pane fade" id="settings-tab-pane" role="tabpanel" tabindex="0">
</div> </div>
</div> </div>
</div> </div>
@ -172,7 +168,8 @@
<div class="stickerPrintContainer hideOnPrint"> <div class="stickerPrintContainer hideOnPrint">
</div> </div>
<script> <script>
loadGarage(); bindTabEvent();
loadTabFromURL();
bindWindowResize(); bindWindowResize();
checkNavBarOverflow(); checkNavBarOverflow();
</script> </script>

View File

@ -10,6 +10,7 @@
var searchExist = userConfig.ShowSearch && Model.Count() > 1; var searchExist = userConfig.ShowSearch && Model.Count() > 1;
var renderTopRow = tagsExist || searchExist; var renderTopRow = tagsExist || searchExist;
} }
<div id="garageContainer">
@if (renderTopRow) @if (renderTopRow)
{ {
<div class='row'> <div class='row'>
@ -101,4 +102,5 @@
<img src="/defaults/addnew_vehicle.png" style="object-fit:scale-down;height:100%;pointer-events:none;" /> <img src="/defaults/addnew_vehicle.png" style="object-fit:scale-down;height:100%;pointer-events:none;" />
</div> </div>
</div> </div>
</div> </div>
</div>

View File

@ -136,17 +136,17 @@
</div> </div>
<div class="container"> <div class="container">
<div class="tab-content" id="vehicleTabContent"> <div class="tab-content" id="vehicleTabContent">
<div class="tab-pane fade @StaticHelper.DefaultActiveTabContent(userConfig, ImportMode.ServiceRecord)" id="servicerecord-tab-pane" role="tabpanel" tabindex="0"></div> <div class="tab-pane fade" id="servicerecord-tab-pane" role="tabpanel" tabindex="0"></div>
<div class="tab-pane fade @StaticHelper.DefaultActiveTabContent(userConfig, ImportMode.GasRecord)" id="gas-tab-pane" role="tabpanel" tabindex="0"></div> <div class="tab-pane fade" id="gas-tab-pane" role="tabpanel" tabindex="0"></div>
<div class="tab-pane fade @StaticHelper.DefaultActiveTabContent(userConfig, ImportMode.TaxRecord)" id="tax-tab-pane" role="tabpanel" tabindex="0"></div> <div class="tab-pane fade" id="tax-tab-pane" role="tabpanel" tabindex="0"></div>
<div class="tab-pane fade @StaticHelper.DefaultActiveTabContent(userConfig, ImportMode.NoteRecord)" id="notes-tab-pane" role="tabpanel" tabindex="0"></div> <div class="tab-pane fade" id="notes-tab-pane" role="tabpanel" tabindex="0"></div>
<div class="tab-pane fade @StaticHelper.DefaultActiveTabContent(userConfig, ImportMode.RepairRecord)" id="accident-tab-pane" role="tabpanel" tabindex="0"></div> <div class="tab-pane fade" id="accident-tab-pane" role="tabpanel" tabindex="0"></div>
<div class="tab-pane fade @StaticHelper.DefaultActiveTabContent(userConfig, ImportMode.ReminderRecord)" id="reminder-tab-pane" role="tabpanel" tabindex="0"></div> <div class="tab-pane fade" id="reminder-tab-pane" role="tabpanel" tabindex="0"></div>
<div class="tab-pane fade @StaticHelper.DefaultActiveTabContent(userConfig, ImportMode.Dashboard)" id="report-tab-pane" role="tabpanel" tabindex="0"></div> <div class="tab-pane fade" id="report-tab-pane" role="tabpanel" tabindex="0"></div>
<div class="tab-pane fade @StaticHelper.DefaultActiveTabContent(userConfig, ImportMode.UpgradeRecord)" id="upgrade-tab-pane" role="tabpanel" tabindex="0"></div> <div class="tab-pane fade" id="upgrade-tab-pane" role="tabpanel" tabindex="0"></div>
<div class="tab-pane fade @StaticHelper.DefaultActiveTabContent(userConfig, ImportMode.SupplyRecord)" id="supply-tab-pane" role="tabpanel" tabindex="0"></div> <div class="tab-pane fade" id="supply-tab-pane" role="tabpanel" tabindex="0"></div>
<div class="tab-pane fade @StaticHelper.DefaultActiveTabContent(userConfig, ImportMode.PlanRecord)" id="plan-tab-pane" role="tabpanel" tabindex="0"></div> <div class="tab-pane fade" id="plan-tab-pane" role="tabpanel" tabindex="0"></div>
<div class="tab-pane fade @StaticHelper.DefaultActiveTabContent(userConfig, ImportMode.OdometerRecord)" id="odometer-tab-pane" role="tabpanel" tabindex="0"></div> <div class="tab-pane fade" id="odometer-tab-pane" role="tabpanel" tabindex="0"></div>
</div> </div>
</div> </div>
<div class="modal fade" data-bs-focus="false" id="editVehicleModal" tabindex="-1" role="dialog" aria-hidden="true"> <div class="modal fade" data-bs-focus="false" id="editVehicleModal" tabindex="-1" role="dialog" aria-hidden="true">

View File

@ -16,9 +16,7 @@ function hideAddVehicleModal() {
//refreshable function to reload Garage PartialView //refreshable function to reload Garage PartialView
function loadGarage() { function loadGarage() {
$.get('/Home/Garage', function (data) { $.get('/Home/Garage', function (data) {
$("#garageContainer").html(data); $("#garage-tab-pane").html(data);
loadSettings();
bindTabEvent();
}); });
} }
function loadSettings() { function loadSettings() {
@ -40,6 +38,12 @@ function GetVehicleId() {
function bindTabEvent() { function bindTabEvent() {
$('button[data-bs-toggle="tab"]').on('show.bs.tab', function (e) { $('button[data-bs-toggle="tab"]').on('show.bs.tab', function (e) {
switch (e.target.id) { switch (e.target.id) {
case "garage-tab":
loadGarage();
break;
case "settings-tab":
loadSettings();
break;
case "supply-tab": case "supply-tab":
getVehicleSupplyRecords(); getVehicleSupplyRecords();
break; break;
@ -47,18 +51,27 @@ function bindTabEvent() {
getVehicleCalendarEvents(); getVehicleCalendarEvents();
break; break;
} }
switch (e.relatedTarget.id) { //clear out previous tabs with grids in them to help with performance
case "supply-tab":
$("#supply-tab-pane").html("");
break;
case "calendar-tab":
$("#calendar-tab-pane").html("");
break;
}
$(`.lubelogger-tab #${e.target.id}`).addClass('active'); $(`.lubelogger-tab #${e.target.id}`).addClass('active');
$(`.lubelogger-mobile-nav #${e.target.id}`).addClass('active'); $(`.lubelogger-mobile-nav #${e.target.id}`).addClass('active');
$(`.lubelogger-tab #${e.relatedTarget.id}`).removeClass('active'); if (e.relatedTarget != null) {
$(`.lubelogger-mobile-nav #${e.relatedTarget.id}`).removeClass('active'); switch (e.relatedTarget.id) { //clear out previous tabs with grids in them to help with performance
case "garage-tab":
$("#garage-tab-pane").html("");
break;
case "settings-tab":
$("#settings-tab-pane").html("");
break;
case "supply-tab":
$("#supply-tab-pane").html("");
break;
case "calendar-tab":
$("#calendar-tab-pane").html("");
break;
}
$(`.lubelogger-tab #${e.relatedTarget.id}`).removeClass('active');
$(`.lubelogger-mobile-nav #${e.relatedTarget.id}`).removeClass('active');
}
setBrowserHistory('tab', getTabNameForURL(e.target.id));
}); });
} }
function getVehicleCalendarEvents() { function getVehicleCalendarEvents() {
@ -482,4 +495,8 @@ function generateTokenForUser() {
errorToast(genericErrorMessage()) errorToast(genericErrorMessage())
} }
}); });
}
function loadTabFromURL() {
let tabFromURL = getTabNameFromURL('garage');
waitForElement(`#${tabFromURL}`, () => { $(`#${tabFromURL}`).tab('show'); }, '');
} }

View File

@ -1738,4 +1738,22 @@ function openAttachmentPreview(fileName, fileLocation) {
} }
function closeAttachmentPreview() { function closeAttachmentPreview() {
$('#attachmentPreviewModal').modal('hide'); $('#attachmentPreviewModal').modal('hide');
}
function setBrowserHistory(param, val) {
let currentParams = new URLSearchParams(window.location.search);
currentParams.set(param, val);
let updatedURL = `${window.location.origin}${window.location.pathname}?${currentParams.toString()}`;
window.history.pushState({}, '', updatedURL);
}
function getTabNameForURL(tabName) {
return tabName.toLowerCase().split('-')[0];
}
function getTabNameFromURL(defaultValue) {
let currentParams = new URLSearchParams(window.location.search);
let currentTab = currentParams.get('tab');
if (currentTab == null || currentTab == undefined || currentTab == '') {
return `${defaultValue.toLowerCase()}-tab`;
} else {
return `${currentTab}-tab`;
}
} }

View File

@ -37,82 +37,50 @@
getVehicleOdometerRecords(vehicleId); getVehicleOdometerRecords(vehicleId);
break; break;
} }
switch (e.relatedTarget.id) { //clear out previous tabs with grids in them to help with performance
case "servicerecord-tab":
$("#servicerecord-tab-pane").html("");
break;
case "gas-tab":
$("#gas-tab-pane").html("");
break;
case "accident-tab":
$("#accident-tab-pane").html("");
break;
case "tax-tab":
$("#tax-tab-pane").html("");
break;
case "report-tab":
$("#report-tab-pane").html("");
break;
case "reminder-tab":
$("#reminder-tab-pane").html("");
break;
case "upgrade-tab":
$("#upgrade-tab-pane").html("");
break;
case "notes-tab":
$("#notes-tab-pane").html("");
break;
case "supply-tab":
$("#supply-tab-pane").html("");
break;
case "plan-tab":
$("#plan-tab-pane").html("");
break;
case "odometer-tab":
$("#odometer-tab-pane").html("");
break;
}
$(`.lubelogger-tab #${e.target.id}`).addClass('active'); $(`.lubelogger-tab #${e.target.id}`).addClass('active');
$(`.lubelogger-mobile-nav #${e.target.id}`).addClass('active'); $(`.lubelogger-mobile-nav #${e.target.id}`).addClass('active');
$(`.lubelogger-tab #${e.relatedTarget.id}`).removeClass('active'); if (e.relatedTarget != null) {
$(`.lubelogger-mobile-nav #${e.relatedTarget.id}`).removeClass('active'); switch (e.relatedTarget.id) { //clear out previous tabs with grids in them to help with performance
case "servicerecord-tab":
$("#servicerecord-tab-pane").html("");
break;
case "gas-tab":
$("#gas-tab-pane").html("");
break;
case "accident-tab":
$("#accident-tab-pane").html("");
break;
case "tax-tab":
$("#tax-tab-pane").html("");
break;
case "report-tab":
$("#report-tab-pane").html("");
break;
case "reminder-tab":
$("#reminder-tab-pane").html("");
break;
case "upgrade-tab":
$("#upgrade-tab-pane").html("");
break;
case "notes-tab":
$("#notes-tab-pane").html("");
break;
case "supply-tab":
$("#supply-tab-pane").html("");
break;
case "plan-tab":
$("#plan-tab-pane").html("");
break;
case "odometer-tab":
$("#odometer-tab-pane").html("");
break;
}
$(`.lubelogger-tab #${e.relatedTarget.id}`).removeClass('active');
$(`.lubelogger-mobile-nav #${e.relatedTarget.id}`).removeClass('active');
}
setBrowserHistory('tab', getTabNameForURL(e.target.id));
}); });
var defaultTab = GetDefaultTab().tab; loadDefaultTab();
switch (defaultTab) {
case "ServiceRecord":
getVehicleServiceRecords(vehicleId);
break;
case "NoteRecord":
getVehicleNotes(vehicleId);
break;
case "GasRecord":
getVehicleGasRecords(vehicleId);
break;
case "RepairRecord":
getVehicleCollisionRecords(vehicleId);
break;
case "TaxRecord":
getVehicleTaxRecords(vehicleId);
break;
case "Dashboard":
getVehicleReport(vehicleId);
break;
case "ReminderRecord":
getVehicleReminders(vehicleId);
break;
case "UpgradeRecord":
getVehicleUpgradeRecords(vehicleId);
break;
case "SupplyRecord":
getVehicleSupplyRecords(vehicleId);
break;
case "PlanRecord":
getVehiclePlanRecords(vehicleId);
break;
case "OdometerRecord":
getVehicleOdometerRecords(vehicleId);
break;
}
}); });
function getVehicleNotes(vehicleId) { function getVehicleNotes(vehicleId) {
@ -745,4 +713,48 @@ function loadGlobalSearchResult(recordId, recordType) {
waitForElement('#planRecordModalContent', showEditPlanRecordModal, recordId); waitForElement('#planRecordModalContent', showEditPlanRecordModal, recordId);
break; break;
} }
}
function loadDefaultTab() {
//check if tab param exists
let userDefaultTab = getDefaultTabName();
let tabFromURL = getTabNameFromURL(userDefaultTab);
waitForElement(`#${tabFromURL}`, () => { $(`#${tabFromURL}`).tab('show'); }, '');
}
function getDefaultTabName() {
var defaultTab = GetDefaultTab().tab;
switch (defaultTab) {
case "ServiceRecord":
return 'servicerecord';
break;
case "NoteRecord":
return 'notes';
break;
case "GasRecord":
return 'gas';
break;
case "RepairRecord":
return 'accident';
break;
case "TaxRecord":
return 'tax';
break;
case "Dashboard":
return 'report';
break;
case "ReminderRecord":
return 'reminder';
break;
case "UpgradeRecord":
return 'upgrade';
break;
case "SupplyRecord":
return 'supply';
break;
case "PlanRecord":
return 'plan';
break;
case "OdometerRecord":
return 'odometer';
break;
}
} }