1616 * specific language governing permissions and limitations
1717 * under the License.
1818 */
19- import { useEffect } from "react" ;
19+ import { useEffect , useRef } from "react" ;
2020import { useNavigate } from "react-router-dom" ;
2121import { useLocalStorage } from "usehooks-ts" ;
2222
@@ -43,50 +43,55 @@ type UseTabMemoryOptions = {
4343export const useTabMemory = ( options : UseTabMemoryOptions ) => {
4444 const { currentPath, enabled = true , storageKey, tabs } = options ;
4545 const navigate = useNavigate ( ) ;
46+ const defaultTab = tabs [ 0 ] ?. value ?? "" ;
47+ const [ savedTab , setSavedTab ] = useLocalStorage < string > ( storageKey , defaultTab ) ;
4648
47- const normalizedPath = currentPath . replace ( / \/ $ / u, "" ) ;
48- const segments = normalizedPath . split ( "/" ) ;
49- const lastSegment = segments [ segments . length - 1 ] ?? "" ;
50- const isTabSegment = tabs . some ( ( tab ) => tab . value === lastSegment ) ;
51- const baseUrl = isTabSegment && lastSegment !== "" ? segments . slice ( 0 , - 1 ) . join ( "/" ) : normalizedPath ;
52-
53- // Use entity-based storage key instead of URL-based key
54- const [ lastTab , setLastTab ] = useLocalStorage < string > ( storageKey , tabs [ 0 ] ?. value ?? "" ) ;
49+ // Track previous baseUrl to detect entity changes
50+ const previousBaseUrlRef = useRef < string | null > ( null ) ;
5551
5652 useEffect ( ( ) => {
5753 if ( ! enabled || tabs . length === 0 ) {
5854 return ;
5955 }
6056
61- const normalizedCurrentPath = currentPath . replace ( / \/ $ / u, "" ) ;
62- const normalizedBase = baseUrl . replace ( / \/ $ / u, "" ) ;
57+ const normalizedPath = currentPath . replace ( / \/ $ / u, "" ) ;
58+ const pathSegments = normalizedPath . split ( "/" ) ;
59+ const lastSegment = pathSegments [ pathSegments . length - 1 ] ?? "" ;
60+ const isTabSegment = tabs . some ( ( tab ) => tab . value === lastSegment ) ;
61+
62+ const baseUrl = isTabSegment && lastSegment !== "" ? pathSegments . slice ( 0 , - 1 ) . join ( "/" ) : normalizedPath ;
63+ const currentTab = isTabSegment ? lastSegment : "" ;
64+
65+ const isAtBase = normalizedPath === baseUrl ;
66+ const isSavedTabValid = Boolean ( savedTab ) && tabs . some ( ( tab ) => tab . value === savedTab ) ;
6367
64- const pathSegments = normalizedCurrentPath . split ( "/" ) ;
65- const baseSegments = normalizedBase . split ( "/" ) ;
66- const currentTab = pathSegments [ baseSegments . length ] ?? "" ;
68+ // Check if we've switched to a different entity (different baseUrl)
69+ const hasEntityChanged = previousBaseUrlRef . current !== null && previousBaseUrlRef . current !== baseUrl ;
70+ const isFirstVisit = previousBaseUrlRef . current === null ;
6771
68- const isValidTab = tabs . some ( ( tab ) => tab . value === currentTab ) ;
69- const isLastTabInCurrentTabs = ! lastTab || tabs . some ( ( tab ) => tab . value === lastTab ) ;
72+ previousBaseUrlRef . current = baseUrl ;
7073
71- // Only update localStorage if both currentTab is valid AND lastTab is also in current tabs
72- // This prevents different page types (e.g., Task Instance vs Task Group) from overwriting each other's tab memory
73- if ( isValidTab && isLastTabInCurrentTabs ) {
74- setLastTab ( currentTab ) ;
74+ // Check if current tab is valid (including empty string for default tab)
75+ const isCurrentTabValid = tabs . some ( ( tab ) => tab . value === currentTab ) ;
76+
77+ // Update saved preference when viewing a valid tab
78+ if ( isCurrentTabValid ) {
79+ const isPreviousSavedTabValid = ! savedTab || tabs . some ( ( tab ) => tab . value === savedTab ) ;
80+
81+ if ( isPreviousSavedTabValid && currentTab !== savedTab ) {
82+ setSavedTab ( currentTab ) ;
83+ }
7584 }
7685
77- const isAtBaseUrl =
78- normalizedCurrentPath === normalizedBase || normalizedCurrentPath === `${ normalizedBase } /` ;
79- const hasValidSavedTab = Boolean ( lastTab ) && tabs . some ( ( tab ) => tab . value === lastTab ) ;
80- const shouldRedirect = isAtBaseUrl && hasValidSavedTab && lastTab !== tabs [ 0 ] ?. value ;
86+ const shouldRedirect =
87+ isAtBase && isSavedTabValid && savedTab !== defaultTab && ( isFirstVisit || hasEntityChanged ) ;
8188
8289 if ( shouldRedirect ) {
83- const redirectPath = lastTab ? `${ normalizedBase } /${ lastTab } ` : normalizedBase ;
84-
8590 void Promise . resolve (
86- navigate ( redirectPath , {
91+ navigate ( ` ${ baseUrl } / ${ savedTab } ` , {
8792 replace : true ,
8893 } ) ,
8994 ) ;
9095 }
91- } , [ baseUrl , currentPath , enabled , lastTab , navigate , setLastTab , tabs ] ) ;
96+ } , [ currentPath , defaultTab , enabled , navigate , savedTab , setSavedTab , tabs ] ) ;
9297} ;
0 commit comments