Update useNavigationHistory.ts (#1970)

This commit is contained in:
Leendert de Borst
2026-04-26 20:07:58 +02:00
committed by Leendert de Borst
parent 3ce53185f7
commit 5fa191bb43
2 changed files with 72 additions and 36 deletions

View File

@@ -1,5 +1,5 @@
import { useEffect, useRef } from 'react';
import { useLocation } from 'react-router-dom';
import { useLocation, useNavigationType } from 'react-router-dom';
/**
* Return type for the useNavigationHistory hook.
@@ -19,9 +19,20 @@ interface INavigationHistory {
*/
export const useNavigationHistory = (): INavigationHistory => {
const location = useLocation();
const navigationType = useNavigationType();
const historyRef = useRef<string[]>([]);
useEffect(() => {
if (navigationType === 'REPLACE') {
// Mirror the replace in our tracked stack so the current entry stays accurate.
if (historyRef.current.length === 0) {
historyRef.current.push(location.pathname + location.search);
} else {
historyRef.current[historyRef.current.length - 1] = location.pathname + location.search;
}
return;
}
const currentPath = location.pathname + location.search;
// Check if this is a back/forward navigation by looking for the path in history
@@ -34,7 +45,7 @@ export const useNavigationHistory = (): INavigationHistory => {
// New navigation - add to history
historyRef.current.push(currentPath);
}
}, [location]);
}, [location, navigationType]);
/**
* Find how many steps back we need to go to reach the target path.

View File

@@ -333,6 +333,15 @@ else
[Parameter]
public Guid? FolderId { get; set; }
/// <summary>
/// Gets or sets the filter from the URL query string.
/// Used to preserve the active filter when navigating into a folder so the folder view
/// matches the count shown on its pill.
/// </summary>
[Parameter]
[SupplyParameterFromQuery(Name = "filter")]
public string? FilterQuery { get; set; }
/// <summary>
/// Gets or sets whether the items are being loaded.
/// </summary>
@@ -663,25 +672,33 @@ else
/// <summary>
/// Gets the title based on the active filter and folder.
/// An active filter takes precedence over the folder name so the title (and the
/// "Filtering by" pill) reflects what's actually being filtered — matching the
/// filter shown in the dropdown and the count in the header.
/// </summary>
private string GetFilterTitle()
{
if (FilterType != ItemFilterType.All)
{
return FilterType switch
{
ItemFilterType.Passkeys => Localizer["FilterPasskeysOption"],
ItemFilterType.Attachments => Localizer["FilterAttachmentsOption"],
ItemFilterType.Totp => Localizer["FilterTotpOption"],
ItemFilterType.Login => ItemTypeSelectorLocalizer["TypeLogin"],
ItemFilterType.Alias => ItemTypeSelectorLocalizer["TypeAlias"],
ItemFilterType.CreditCard => ItemTypeSelectorLocalizer["TypeCreditCard"],
ItemFilterType.Note => ItemTypeSelectorLocalizer["TypeNote"],
_ => Localizer["PageTitle"],
};
}
if (IsInFolder && !string.IsNullOrEmpty(CurrentFolderName))
{
return CurrentFolderName;
}
return FilterType switch
{
ItemFilterType.Passkeys => Localizer["FilterPasskeysOption"],
ItemFilterType.Attachments => Localizer["FilterAttachmentsOption"],
ItemFilterType.Totp => Localizer["FilterTotpOption"],
ItemFilterType.Login => ItemTypeSelectorLocalizer["TypeLogin"],
ItemFilterType.Alias => ItemTypeSelectorLocalizer["TypeAlias"],
ItemFilterType.CreditCard => ItemTypeSelectorLocalizer["TypeCreditCard"],
ItemFilterType.Note => ItemTypeSelectorLocalizer["TypeNote"],
_ => Localizer["PageTitle"],
};
return Localizer["PageTitle"];
}
/// <summary>
@@ -716,14 +733,15 @@ else
}
/// <summary>
/// Sets the filter type and closes the dropdown.
/// Sets the filter type and closes the dropdown. The filter is reflected in the URL
/// query string so it persists across folder navigation and browser back/forward.
/// </summary>
private void SetFilter(ItemFilterType filterType)
{
FilterType = filterType;
VisibleItemCount = BatchSize; // Reset visible items when filter changes
ShowFilterDropdown = false;
StateHasChanged();
NavigationManager.NavigateTo(BuildItemsUrl(FolderId, filterType), replace: true);
}
/// <summary>
@@ -733,7 +751,21 @@ else
{
FilterType = ItemFilterType.All;
VisibleItemCount = BatchSize; // Reset visible items when filter changes
StateHasChanged();
NavigationManager.NavigateTo(BuildItemsUrl(FolderId, ItemFilterType.All), replace: true);
}
/// <summary>
/// Builds the items list URL for a given folder and filter. The filter is always
/// included in the query string so the active filter persists across navigation,
/// including when navigating between folder views.
/// </summary>
/// <param name="folderId">The folder ID, or null for the root view.</param>
/// <param name="filterType">The active filter type.</param>
/// <returns>The URL to navigate to.</returns>
private static string BuildItemsUrl(Guid? folderId, ItemFilterType filterType)
{
var basePath = folderId.HasValue ? $"/items/folder/{folderId.Value}" : "/items";
return $"{basePath}?filter={filterType}";
}
/// <summary>
@@ -819,21 +851,22 @@ else
}
/// <summary>
/// Navigate to a folder.
/// Navigate to a folder, preserving the active filter so the folder view matches
/// the count shown on the folder pill.
/// </summary>
private void NavigateToFolder(Guid folderId)
{
VisibleItemCount = BatchSize; // Reset visible items when navigating to folder
NavigationManager.NavigateTo($"/items/folder/{folderId}");
NavigationManager.NavigateTo(BuildItemsUrl(folderId, FilterType));
}
/// <summary>
/// Navigate back to root.
/// Navigate back to root, preserving the active filter.
/// </summary>
private void NavigateToRoot()
{
VisibleItemCount = BatchSize; // Reset visible items when navigating to root
NavigationManager.NavigateTo("/items");
NavigationManager.NavigateTo(BuildItemsUrl(null, FilterType));
}
/// <summary>
@@ -958,14 +991,7 @@ else
if (success)
{
// Navigate to parent folder if it exists, otherwise root
if (parentFolderId.HasValue)
{
NavigationManager.NavigateTo($"/items/folder/{parentFolderId.Value}");
}
else
{
NavigationManager.NavigateTo("/items");
}
NavigationManager.NavigateTo(BuildItemsUrl(parentFolderId, FilterType));
}
else
{
@@ -989,14 +1015,7 @@ else
if (success)
{
// Navigate to parent folder if it exists, otherwise root
if (parentFolderId.HasValue)
{
NavigationManager.NavigateTo($"/items/folder/{parentFolderId.Value}");
}
else
{
NavigationManager.NavigateTo("/items");
}
NavigationManager.NavigateTo(BuildItemsUrl(parentFolderId, FilterType));
}
else
{
@@ -1010,6 +1029,12 @@ else
{
await base.OnParametersSetAsync();
// Sync the in-memory filter with the URL query so that browser back/forward and
// folder navigation preserve the active filter. Unknown values fall back to All.
FilterType = Enum.TryParse<ItemFilterType>(FilterQuery, ignoreCase: true, out var parsed)
? parsed
: ItemFilterType.All;
// Initialize table sort state from saved sort order
SyncTableSortWithSortOrder();