Skip to content

Fix: Cached Data Shown After Logout and Re-login#4040

Open
priyankeshh wants to merge 1 commit intobeckn:mainfrom
priyankeshh:degCache
Open

Fix: Cached Data Shown After Logout and Re-login#4040
priyankeshh wants to merge 1 commit intobeckn:mainfrom
priyankeshh:degCache

Conversation

@priyankeshh
Copy link

@priyankeshh priyankeshh commented Apr 26, 2025

Fixes #4027

What

Implemented a comprehensive solution to fix the issue where previously searched or viewed results were still visible after logging out and logging back in.

Why

This resolves the issue described in [reference to ticket/issue] where data was being retrieved from the cache instead of re-fetching fresh data for the new session.

How

  • Created a centralized logout utility that properly clears all caches
  • Updated Redux store to reset all state on logout
  • Added cache control headers to API requests
  • Implemented proper clearing of localStorage and cookies

Testing

  • Tested logout and re-login flow in development environment
  • Verified search results, product details, and cart data are properly cleared on logout

Summary by CodeRabbit

  • New Features

    • Added a "Logout" option to the menu modal for easier user sign-out.
  • Improvements

    • Logout actions now consistently clear user data and state, ensuring a more reliable sign-out process.
    • Enhanced data security by enforcing cache control on all network requests.
    • Centralized and streamlined logout handling across the application.
  • Refactor

    • Updated store management to fully reset user state on logout.
    • Replaced direct API calls with a utility for consistent cache control.

@coderabbitai
Copy link

coderabbitai bot commented Apr 26, 2025

Walkthrough

The changes introduce a unified logout utility that clears Redux state, cookies, localStorage (with selective preservation), and sessionStorage, and redirects to the login page. Redux store logic is updated to reset state on logout. Axios cache control is enforced globally via a new utility and interceptors, and all API calls are refactored to use this utility. The header component now consistently uses the new logout flow for both the home icon and menu actions. These updates collectively ensure cached data from previous sessions is cleared on logout.

Changes

File(s) Change Summary
apps/retail/components/header/index.tsx Refactored logout logic to use new centralized logoutUser utility and Redux dispatch; added logout option to menu modal.
apps/retail/pages/_app.tsx Imported and invoked axios cache control interceptor setup at the app level.
apps/retail/pages/search.tsx Replaced direct axios usage with fetchWithCacheControl utility for search API calls.
apps/retail/store/index.ts Refactored store setup to use a rootReducer that resets all state on logout action.
apps/retail/utilities/api-utils.ts Added new utility functions: fetchWithCacheControl for API calls with cache headers, and setupAxiosInterceptors for global use.
apps/retail/utilities/logout.ts Added new logoutUser utility for comprehensive logout: clears Redux, cookies, storage, and redirects.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant TopHeader
    participant ReduxStore
    participant logoutUser
    participant Cookies
    participant localStorage
    participant sessionStorage
    participant Router

    User->>TopHeader: Clicks Logout/Home
    TopHeader->>logoutUser: logoutUser(dispatch, router)
    logoutUser->>ReduxStore: Dispatch logout action
    logoutUser->>Cookies: Remove auth/user cookies
    logoutUser->>localStorage: Preserve userPhone, clear others
    logoutUser->>sessionStorage: Clear all
    logoutUser->>Router: Redirect to login page
Loading
sequenceDiagram
    participant App
    participant setupAxiosInterceptors
    participant axios

    App->>setupAxiosInterceptors: On app startup
    setupAxiosInterceptors->>axios: Add request interceptor for cache control headers
Loading

Assessment against linked issues

Objective Addressed Explanation
Clear all previous session data (Redux, cookies, localStorage, sessionStorage) on logout (#4027)
Ensure API calls do not use cached data after logout and re-login (#4027)
Enforce cache control headers on all axios requests to prevent stale data retrieval (#4027)

Poem

Oh, what a hop, what a leap,
Clearing caches, no secrets to keep!
With Redux reset, and cookies gone,
Old data’s memory has withdrawn.
Fresh as clover in morning dew,
Logout now starts everything new!
— 🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (6)
apps/retail/utilities/logout.ts (2)

11-11: Use a more specific type for dispatch parameter.

The type Dispatch<any> is too generic and can lead to type safety issues. Consider using a more specific type such as Dispatch<AnyAction> or a custom type defining the actions your application supports.

-export const logoutUser = (dispatch: Dispatch<any>, router: NextRouter) => {
+export const logoutUser = (dispatch: Dispatch<AnyAction>, router: NextRouter) => {

Don't forget to add the import:

import { Dispatch, AnyAction } from '@reduxjs/toolkit'
🧰 Tools
🪛 ESLint

[error] 11-11: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)


39-40: Consider adding error handling for router operations.

The router.push operation could potentially fail, especially in case of network issues or invalid routes. Consider adding error handling.

-  // Redirect to login page
-  router.push('/')
+  // Redirect to login page
+  router.push('/')
+    .catch(error => {
+      console.error('Failed to redirect to login page:', error)
+      // Consider fallback action like window.location.href = '/'
+    })
apps/retail/utilities/api-utils.ts (1)

9-25: Extract cache control headers into a constant to avoid duplication.

The cache control headers are duplicated between this function and the setupAxiosInterceptors function, which could lead to maintenance issues.

+const CACHE_CONTROL_HEADERS = {
+  'Cache-Control': 'no-cache, no-store, must-revalidate',
+  Pragma: 'no-cache',
+  Expires: '0'
+}
+
 export const fetchWithCacheControl = async (url: string, options: AxiosRequestConfig = {}) => {
-  const defaultHeaders = {
-    'Cache-Control': 'no-cache, no-store, must-revalidate',
-    Pragma: 'no-cache',
-    Expires: '0'
-  }
+  const defaultHeaders = CACHE_CONTROL_HEADERS

   const requestOptions: AxiosRequestConfig = {
     ...options,
     headers: {
       ...defaultHeaders,
       ...options.headers
     }
   }

   return axios(url, requestOptions)
 }

Also update the interceptor function to use this constant:

 export const setupAxiosInterceptors = () => {
   axios.interceptors.request.use(config => {
     // Add cache control headers to all requests
     config.headers = {
       ...config.headers,
-      'Cache-Control': 'no-cache, no-store, must-revalidate',
-      Pragma: 'no-cache',
-      Expires: '0'
+      ...CACHE_CONTROL_HEADERS
     }

     return config
   })
 }
apps/retail/pages/search.tsx (1)

92-94: Enhance error handling for failed API requests.

The error handling is minimal and doesn't provide any feedback to the user if the search request fails.

       .catch(e => {
         setIsLoading(false)
+        console.error('Search request failed:', e)
+        // Consider adding user-friendly error notification
+        // For example:
+        // toast.error('Unable to load search results. Please try again.')
       })
🧰 Tools
🪛 ESLint

[error] 92-92: 'e' is defined but never used.

(@typescript-eslint/no-unused-vars)

apps/retail/pages/_app.tsx (2)

1-1: Remove unused useEffect import.

The useEffect hook is imported but never used in this file.

-import React, { useEffect } from 'react'
+import React from 'react'
🧰 Tools
🪛 ESLint

[error] 1-1: 'useEffect' is defined but never used.

(@typescript-eslint/no-unused-vars)


24-25: Consider moving interceptor setup into a component lifecycle.

The setupAxiosInterceptors is called at the module level, which might lead to issues if the setup depends on component state or props. Consider moving it into a useEffect hook inside the MyApp component.

-// Set up axios interceptors for cache control
-setupAxiosInterceptors()
 function MyApp({ Component, pageProps }: AppProps) {
+  useEffect(() => {
+    // Set up axios interceptors for cache control
+    setupAxiosInterceptors()
+  }, [])
+
   return (
     <BecknProvider
       theme={{

Note: If you implement this change, keep the useEffect import from React.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0ac0865 and 70e0f35.

⛔ Files ignored due to path filters (1)
  • apps/retail/public/images/logout.svg is excluded by !**/*.svg
📒 Files selected for processing (6)
  • apps/retail/components/header/index.tsx (3 hunks)
  • apps/retail/pages/_app.tsx (2 hunks)
  • apps/retail/pages/search.tsx (2 hunks)
  • apps/retail/store/index.ts (2 hunks)
  • apps/retail/utilities/api-utils.ts (1 hunks)
  • apps/retail/utilities/logout.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
apps/retail/pages/search.tsx (1)
apps/retail/utilities/api-utils.ts (1)
  • fetchWithCacheControl (9-25)
apps/retail/components/header/index.tsx (1)
apps/retail/utilities/logout.ts (1)
  • logoutUser (11-41)
apps/retail/pages/_app.tsx (1)
apps/retail/utilities/api-utils.ts (1)
  • setupAxiosInterceptors (30-42)
🪛 ESLint
apps/retail/utilities/logout.ts

[error] 11-11: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)

apps/retail/pages/_app.tsx

[error] 1-1: 'useEffect' is defined but never used.

(@typescript-eslint/no-unused-vars)

apps/retail/store/index.ts

[error] 37-37: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)


[error] 37-37: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)

🔇 Additional comments (8)
apps/retail/utilities/logout.ts (1)

19-26: Well-structured approach for preserving specific localStorage items.

The implementation elegantly preserves certain localStorage values during logout, which maintains user preferences while clearing sensitive data.

apps/retail/pages/search.tsx (2)

81-85: Good implementation of cache-controlled API requests.

The switch to using fetchWithCacheControl ensures consistent cache control headers, aligning with the PR objective to prevent cached data issues after logout and re-login.


107-115:

Details

✅ Verification successful

Verify if cached search results are properly cleared during logout.

This useEffect hook loads cached search results from localStorage on component mount. Ensure that the logoutUser function clears 'searchItems' from localStorage to prevent stale data being shown after logout and re-login.


🏁 Script executed:

#!/bin/bash
# Check if the 'searchItems' key is cleared during logout

# First, check if the logoutUser function clears localStorage entirely
echo "Checking if localStorage is cleared during logout:"
cat apps/retail/utilities/logout.ts | grep -A 5 "Clear all localStorage"

# Next, verify if there's any specific handling for 'searchItems'
echo -e "\nChecking for specific handling of 'searchItems':"
grep -r "searchItems" --include="*.ts" --include="*.tsx" apps/retail/

Length of output: 843


🏁 Script executed:

#!/bin/bash
echo "Inspecting preservedData in logout utility:"
grep -R "preservedData" -n apps/retail/utilities/logout.ts || echo "No preservedData declaration found"

echo -e "\nShowing logout.ts for context (first 200 lines):"
sed -n '1,200p' apps/retail/utilities/logout.ts

Length of output: 1621


Confirm searchItems Is Cleared on Logout
The logoutUser function in apps/retail/utilities/logout.ts calls localStorage.clear() and only restores keys listed in keysToPreserve (which does not include "searchItems"). Therefore, the cached search results are removed on logout as intended—no further changes needed.

apps/retail/pages/_app.tsx (1)

24-25: Good implementation of global cache control.

Setting up axios interceptors at the application level ensures consistent cache control for all API requests, which helps prevent cached data issues after logout and re-login.

apps/retail/components/header/index.tsx (1)

13-14: Add appropriate imports for unified logout handling

Good addition of Redux dispatch and the centralized logout utility. This sets the foundation for consistent logout behavior across the application.

apps/retail/store/index.ts (3)

1-1: Good import of combineReducers for improved store organization

Adding combineReducers helps organize the Redux store structure and enables the state reset pattern on logout.


16-34: Well-structured combined reducer implementation

Good job restructuring the store to use combineReducers. This provides a cleaner structure and facilitates the logout state reset functionality.


47-49: Good integration with configureStore

The rootReducer is properly integrated with configureStore, ensuring that the state reset on logout works throughout the application.

Comment on lines +30 to +42
export const setupAxiosInterceptors = () => {
axios.interceptors.request.use(config => {
// Add cache control headers to all requests
config.headers = {
...config.headers,
'Cache-Control': 'no-cache, no-store, must-revalidate',
Pragma: 'no-cache',
Expires: '0'
}

return config
})
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Prevent adding multiple identical interceptors.

If setupAxiosInterceptors is called multiple times, it will add the same interceptor multiple times. Consider adding a check to prevent this.

+let isInterceptorSetup = false;

 export const setupAxiosInterceptors = () => {
+  if (isInterceptorSetup) return;
+
   axios.interceptors.request.use(config => {
     // Add cache control headers to all requests
     config.headers = {
       ...config.headers,
       'Cache-Control': 'no-cache, no-store, must-revalidate',
       Pragma: 'no-cache',
       Expires: '0'
     }

     return config
   })
+  
+  isInterceptorSetup = true;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const setupAxiosInterceptors = () => {
axios.interceptors.request.use(config => {
// Add cache control headers to all requests
config.headers = {
...config.headers,
'Cache-Control': 'no-cache, no-store, must-revalidate',
Pragma: 'no-cache',
Expires: '0'
}
return config
})
}
let isInterceptorSetup = false;
export const setupAxiosInterceptors = () => {
if (isInterceptorSetup) return;
axios.interceptors.request.use(config => {
// Add cache control headers to all requests
config.headers = {
...config.headers,
'Cache-Control': 'no-cache, no-store, must-revalidate',
Pragma: 'no-cache',
Expires: '0'
}
return config
})
isInterceptorSetup = true;
}

Comment on lines 141 to 144
onClick={() => {
const user = localStorage.getItem('userPhone') as string
localStorage.clear()
localStorage.setItem('userPhone', user)
const dispatch = useDispatch()
logoutUser(dispatch, router)
router.push(`/homePage`)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Incorrect usage of useDispatch hook in event handler

The useDispatch hook is being called inside an event handler, which violates React's rules of hooks. Hooks should only be called at the top level of your component.

- onClick={() => {
-   const dispatch = useDispatch()
-   logoutUser(dispatch, router)
-   router.push(`/homePage`)
- }}
+ const dispatch = useDispatch()
+ onClick={() => {
+   logoutUser(dispatch, router)
+   // Remove this line as logoutUser already redirects to login page
+   // router.push(`/homePage`)
+ }}

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +183 to +196
<Box
onClick={() => {
const dispatch = useDispatch()
logoutUser(dispatch, router)
setMenuModalOpen(false)
}}
className={styles.top_header_modal}
>
<Image
src="/images/logout.svg"
alt="Logout icon"
/>
Logout
</Box>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Incorrect usage of useDispatch hook in Logout menu item

Similar to the home icon issue, useDispatch is being called inside an event handler. Additionally, the menu item's behavior conflicts with the logout utility's redirect.

+ const dispatch = useDispatch()
  <Box
    onClick={() => {
-     const dispatch = useDispatch()
      logoutUser(dispatch, router)
      setMenuModalOpen(false)
    }}
    className={styles.top_header_modal}
  >

Consider removing setMenuModalOpen(false) as it's unnecessary - the logout function will redirect the user away from this page anyway.

Committable suggestion skipped: line range outside the PR's diff.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DEG App - Cached Data Shown After Logout and Re-login

1 participant