Skip to content

[change] Extracted storage logic from Status component #918#1070

Open
kunalverma2512 wants to merge 2 commits into
openwisp:masterfrom
kunalverma2512:refactor-status-storage-918
Open

[change] Extracted storage logic from Status component #918#1070
kunalverma2512 wants to merge 2 commits into
openwisp:masterfrom
kunalverma2512:refactor-status-storage-918

Conversation

@kunalverma2512
Copy link
Copy Markdown

@kunalverma2512 kunalverma2512 commented Mar 22, 2026

Checklist

  • I have read the OpenWISP Contributing Guidelines.
  • I have manually tested the changes proposed in this pull request.
  • I have written new test cases for new code and/or updated existing tests for changes to existing code.
  • I have updated the documentation.

Reference to Existing Issue

Related to #918.

Description of Changes

This PR contributes to the ongoing refactoring of the Status component (#918). Following the "surgical" approach discussed in the issue, I have extracted the storage-related logic into a dedicated utility file.

Key Changes

  • Created client/utils/captive-portal-storage.js to house the storeValue and resolveStoredValue logic.
  • Updated client/components/status/status.js to import and use these utilities.
  • Refactored methods from class methods to plain exported functions, reducing the size of the Status component by approximately 50 lines.
  • Preserved all existing documentation, JSDoc comments, and logic to ensure backward compatibility.

Verification

  • Successfully ran npm run setup to clear environment dependencies.
  • Ran npm run lint: Passed with zero errors.
  • Ran npm test: All 369 tests passed, verifying that the refactoring did not break existing behavior.
  • Verified local formatting with npm run format.

Screenshot

No UI changes were made as this is a pure codebase maintainability improvement.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 22, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This pull request extracts captive-portal storage logic from the Status component into a new utility module client/utils/captive-portal-storage.js. Two functions, storeValue and resolveStoredValue, are implemented as standalone exported helpers and the Status component is updated to import and call these helpers everywhere it previously used internal class methods; the internal storage method definitions were removed from Status.

Sequence Diagram(s)

sequenceDiagram
    participant Status
    participant CaptivePortalStorage
    participant Cookies
    participant LocalStorage

    Status->>CaptivePortalStorage: storeValue(captivePortalSyncAuth, key, value, cookies)
    alt captivePortalSyncAuth falsy
        CaptivePortalStorage-->>Status: return immediately
    else
        CaptivePortalStorage->>LocalStorage: localStorage.setItem(key, value)
        CaptivePortalStorage->>Cookies: cookies.set(key, value, {path: "/", maxAge:60})
        CaptivePortalStorage-->>Status: return
    end

    Status->>CaptivePortalStorage: resolveStoredValue(captivePortalSyncAuth, key, fallback, cookies)
    alt captivePortalSyncAuth falsy
        CaptivePortalStorage-->>Status: return fallback
    else
        CaptivePortalStorage->>Cookies: cookies.get(key)
        alt cookie exists
            CaptivePortalStorage->>LocalStorage: localStorage.removeItem(key)
            CaptivePortalStorage-->>Status: return (cookieValue === true or "true")
        else
            CaptivePortalStorage->>LocalStorage: localStorage.getItem(key)
            alt localStorage value exists
                CaptivePortalStorage->>LocalStorage: localStorage.removeItem(key)
                CaptivePortalStorage-->>Status: return (value === "true")
            else
                CaptivePortalStorage-->>Status: return fallback
            end
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title follows the required format [type] with 'change' prefix and clearly describes the main refactoring work of extracting storage logic from the Status component, with reference to issue #918.
Description check ✅ Passed The description includes all required sections from the template: completed checklist, issue reference, detailed description of changes, and verification steps. Comprehensive details about the refactoring and testing confirm thorough quality assurance.
Bug Fixes ✅ Passed This PR is a refactoring that extracts existing storage logic from the Status component into reusable utility functions, not a bug fix.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@client/utils/captive-portal-storage.js`:
- Line 31: The JSDoc parameter name `cookieKey` mismatches the actual function
parameter `key`; update the JSDoc for the function in
client/utils/captive-portal-storage.js so the `@param` name matches the real
parameter (`key`) and its description, ensuring IDE/tooling show correct hints
for that function (replace `cookieKey` with `key` in the `@param` line and keep
the rest of the description unchanged).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 975726d1-72c4-4a96-86c6-05e5632cea31

📥 Commits

Reviewing files that changed from the base of the PR and between 5eef317 and 1df8a59.

📒 Files selected for processing (2)
  • client/components/status/status.js
  • client/utils/captive-portal-storage.js
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Tests and Coverage
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), real memory leaks are fixed by calling `clearTimeout(this.usageRetryTimeoutId)` and `window.removeEventListener("message", ...)` in `componentWillUnmount()`. These were actual leaks — the retry timeout could fire and the message handler could run after unmount.
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), `finalOperations()` has a single early return before setting up intervals/listeners to prevent the scenario where the component unmounts during async awaits. `safeSetState` is applied to success paths in `getUserRadiusSessions()`, `getUserRadiusUsage()`, `getPlansSuccessCallback()`, and `handlePostMessage()`.
📚 Learning: 2026-03-06T23:26:11.526Z
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), `finalOperations()` has a single early return before setting up intervals/listeners to prevent the scenario where the component unmounts during async awaits. `safeSetState` is applied to success paths in `getUserRadiusSessions()`, `getUserRadiusUsage()`, `getPlansSuccessCallback()`, and `handlePostMessage()`.

Applied to files:

  • client/components/status/status.js
📚 Learning: 2026-03-06T23:26:11.526Z
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), the Status component uses `this.isComponentMounted` (set to `true` in the constructor, `false` in `componentWillUnmount`) together with a `safeSetState()` helper method that checks `isComponentMounted` before calling `setState()`. This is the preferred pattern to guard against "setState on unmounted component" warnings.

Applied to files:

  • client/components/status/status.js
📚 Learning: 2026-03-06T23:26:11.526Z
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), real memory leaks are fixed by calling `clearTimeout(this.usageRetryTimeoutId)` and `window.removeEventListener("message", ...)` in `componentWillUnmount()`. These were actual leaks — the retry timeout could fire and the message handler could run after unmount.

Applied to files:

  • client/components/status/status.js
📚 Learning: 2026-03-06T23:26:11.526Z
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), catch blocks deliberately do NOT check `isComponentMounted` — console warnings from catch paths are considered harmless. Only real memory leaks (timers, event listeners) and "setState on unmounted" in success paths are fixed. The maintainer (nemesifier) explicitly wants to avoid over-engineering with defensive checks in every catch block.

Applied to files:

  • client/components/status/status.js
🔇 Additional comments (6)
client/utils/captive-portal-storage.js (2)

18-24: Good extraction of write-path storage logic.

The helper keeps the sync-auth gate and dual-write behavior intact, which makes the Status call sites cleaner without changing flow.


35-58: Read precedence and cleanup behavior look correct.

Cookie-first resolution with localStorage fallback and post-read cleanup is consistent and easy to reason about.

client/components/status/status.js (4)

40-43: Import wiring is clean and localized.

Good move to centralize captive-portal storage behavior in a utility module.


160-171: mustLogin/mustLogout resolution refactor preserves flow.

Using resolveStoredValue(...) here keeps the previous decision path intact while reducing component complexity.


234-239: All write-path call sites were updated consistently.

The storeValue(...) replacement is applied in login, upgrade, and logout paths in a consistent way.

Also applies to: 501-506, 589-594


706-711: Logout iframe read-path update is consistent with extracted helper usage.

This keeps the sync-auth logout restoration logic centralized and maintainable.

Based on learnings, the established client/components/status/status.js lifecycle/mounted-safety pattern should remain unchanged unless directly needed; this refactor does so.

Comment thread client/utils/captive-portal-storage.js Outdated
@openwisp-companion
Copy link
Copy Markdown

Commit Message Format Failure

Hello @kunalverma2512,
(Analysis for commit 1df8a59)

The commit message is missing the issue number in the body, even though it's present in the title.

Fix:
Ensure the commit message body includes a closing keyword (Fixes, Closes, Related to) followed by the issue number.

Example:

[change] Extracted storage logic from Status component #918

This commit extracts the storage logic from the Status component to improve modularity and testability.

Fixes #918

@kunalverma2512 kunalverma2512 force-pushed the refactor-status-storage-918 branch 2 times, most recently from 5000bc4 to 8f988ba Compare March 22, 2026 19:35
Copy link
Copy Markdown

@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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@client/utils/captive-portal-storage.js`:
- Line 59: The file ends with the closing token "};" (the end of the exported
object/function) but lacks a trailing newline; open
client/utils/captive-portal-storage.js, move the cursor to the end after the
final "};" and add a single newline character so the file ends with a blank
line, satisfying ESLint's newline-at-end-of-file rule.
- Around line 46-56: The cookie and localStorage branches return inconsistent
types (cookieValue vs localStorageValue === "true"); update the logic so both
branches return the same type (preferably boolean). In the code handling cookies
(cookieValue from cookies.get(key)) and localStorage
(localStorage.getItem(key)), coerce both values to boolean consistently—e.g.,
for cookieValue check its type and treat string "true" as true otherwise use
Boolean(cookieValue), and for localStorageValue continue using localStorageValue
=== "true"—so callers of cookies.get(key)/localStorage.getItem(key) via this
helper always receive a boolean.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 47215e8f-6c58-4b5e-95c4-0405b56954b6

📥 Commits

Reviewing files that changed from the base of the PR and between 5000bc4 and 8f988ba.

📒 Files selected for processing (2)
  • client/components/status/status.js
  • client/utils/captive-portal-storage.js
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Tests and Coverage
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), real memory leaks are fixed by calling `clearTimeout(this.usageRetryTimeoutId)` and `window.removeEventListener("message", ...)` in `componentWillUnmount()`. These were actual leaks — the retry timeout could fire and the message handler could run after unmount.
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), `finalOperations()` has a single early return before setting up intervals/listeners to prevent the scenario where the component unmounts during async awaits. `safeSetState` is applied to success paths in `getUserRadiusSessions()`, `getUserRadiusUsage()`, `getPlansSuccessCallback()`, and `handlePostMessage()`.
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), catch blocks deliberately do NOT check `isComponentMounted` — console warnings from catch paths are considered harmless. Only real memory leaks (timers, event listeners) and "setState on unmounted" in success paths are fixed. The maintainer (nemesifier) explicitly wants to avoid over-engineering with defensive checks in every catch block.
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), the Status component uses `this.isComponentMounted` (set to `true` in the constructor, `false` in `componentWillUnmount`) together with a `safeSetState()` helper method that checks `isComponentMounted` before calling `setState()`. This is the preferred pattern to guard against "setState on unmounted component" warnings.
📚 Learning: 2026-03-06T23:26:11.526Z
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), `finalOperations()` has a single early return before setting up intervals/listeners to prevent the scenario where the component unmounts during async awaits. `safeSetState` is applied to success paths in `getUserRadiusSessions()`, `getUserRadiusUsage()`, `getPlansSuccessCallback()`, and `handlePostMessage()`.

Applied to files:

  • client/components/status/status.js
📚 Learning: 2026-03-06T23:26:11.526Z
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), the Status component uses `this.isComponentMounted` (set to `true` in the constructor, `false` in `componentWillUnmount`) together with a `safeSetState()` helper method that checks `isComponentMounted` before calling `setState()`. This is the preferred pattern to guard against "setState on unmounted component" warnings.

Applied to files:

  • client/components/status/status.js
📚 Learning: 2026-03-06T23:26:11.526Z
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), real memory leaks are fixed by calling `clearTimeout(this.usageRetryTimeoutId)` and `window.removeEventListener("message", ...)` in `componentWillUnmount()`. These were actual leaks — the retry timeout could fire and the message handler could run after unmount.

Applied to files:

  • client/components/status/status.js
📚 Learning: 2026-03-06T23:26:11.526Z
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), catch blocks deliberately do NOT check `isComponentMounted` — console warnings from catch paths are considered harmless. Only real memory leaks (timers, event listeners) and "setState on unmounted" in success paths are fixed. The maintainer (nemesifier) explicitly wants to avoid over-engineering with defensive checks in every catch block.

Applied to files:

  • client/components/status/status.js
🪛 ESLint
client/utils/captive-portal-storage.js

[error] 59-59: Newline required at end of file but not found.

(eol-last)

🔇 Additional comments (6)
client/components/status/status.js (6)

40-43: LGTM!

The import is well-structured and correctly brings in both utility functions from the new module.


160-171: LGTM!

Both resolveStoredValue calls correctly pass the required parameters and maintain the original fallback logic using userMustLogin and userMustLogout from userData.


234-239: LGTM!

The storeValue call correctly persists mustLogin = false before form submission, preventing duplicate logins on page reload in synchronous auth mode.


501-506: LGTM!

The storeValue call correctly sets mustLogin = true before redirecting to payment, ensuring the user regains internet access upon return.


589-594: LGTM!

The storeValue call correctly persists mustLogout = true before form submission, ensuring the logout state is maintained across page reloads.


704-712: LGTM!

The resolveStoredValue call correctly checks for the stored logout flag in handleLogoutIframe, with an appropriate fallback of false. The integration with the existing loggedOut state check is preserved.

Comment thread client/utils/captive-portal-storage.js
Comment thread client/utils/captive-portal-storage.js Outdated
@openwisp-companion
Copy link
Copy Markdown

Prettier Code Style Failures

Hello @kunalverma2512,
(Analysis for commit 8f988ba)

  • Code Style (Prettier): The file client/utils/captive-portal-storage.js has code style issues.
  • Fix: Run yarn prettier --write "**/*.+(js|jsx|json|css|md)" to automatically format the code.

@kunalverma2512 kunalverma2512 force-pushed the refactor-status-storage-918 branch from 8f988ba to d22afcb Compare March 22, 2026 19:41
Copy link
Copy Markdown

@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.

♻️ Duplicate comments (1)
client/utils/captive-portal-storage.js (1)

46-56: ⚠️ Potential issue | 🟠 Major

Normalize resolveStoredValue return type to boolean in both branches.

Line 49 returns raw cookie value, while Line 55 returns a boolean. If cookie values are returned as strings (e.g. "false"), callers may treat them as truthy and mis-handle login/logout flags.

♻️ Proposed fix
   const cookieValue = cookies.get(key);
   if (cookieValue !== undefined) {
     localStorage.removeItem(key);
-    return cookieValue;
+    return cookieValue === true || cookieValue === "true";
   }

   const localStorageValue = localStorage.getItem(key);
   if (localStorageValue !== null) {
     localStorage.removeItem(key);
     return localStorageValue === "true";
   }
In react-cookie/universal-cookie, what value type does cookies.get("key") return when cookies.set("key", false) or cookies.set("key", true) is used?
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@client/utils/captive-portal-storage.js` around lines 46 - 56, The cookie
branch returns the raw cookie value (which may be the string "false") while the
localStorage branch coerces to boolean; update resolveStoredValue to always
return a boolean by coercing cookieValue to a boolean before returning: when
cookies.get(key) yields a value, remove the localStorage key then convert the
cookieValue to a boolean (e.g., treat the string "true" as true and everything
else as false, or use a safe JSON/boolean coercion) so both branches
consistently return boolean values; reference cookies.get, localStorage.getItem,
localStorage.removeItem and resolveStoredValue to find where to apply the
change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@client/utils/captive-portal-storage.js`:
- Around line 46-56: The cookie branch returns the raw cookie value (which may
be the string "false") while the localStorage branch coerces to boolean; update
resolveStoredValue to always return a boolean by coercing cookieValue to a
boolean before returning: when cookies.get(key) yields a value, remove the
localStorage key then convert the cookieValue to a boolean (e.g., treat the
string "true" as true and everything else as false, or use a safe JSON/boolean
coercion) so both branches consistently return boolean values; reference
cookies.get, localStorage.getItem, localStorage.removeItem and
resolveStoredValue to find where to apply the change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: a2e686b2-b673-411c-9fa9-c5e50e937e3f

📥 Commits

Reviewing files that changed from the base of the PR and between 8f988ba and d22afcb.

📒 Files selected for processing (2)
  • client/components/status/status.js
  • client/utils/captive-portal-storage.js
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Tests and Coverage
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), real memory leaks are fixed by calling `clearTimeout(this.usageRetryTimeoutId)` and `window.removeEventListener("message", ...)` in `componentWillUnmount()`. These were actual leaks — the retry timeout could fire and the message handler could run after unmount.
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), `finalOperations()` has a single early return before setting up intervals/listeners to prevent the scenario where the component unmounts during async awaits. `safeSetState` is applied to success paths in `getUserRadiusSessions()`, `getUserRadiusUsage()`, `getPlansSuccessCallback()`, and `handlePostMessage()`.
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), catch blocks deliberately do NOT check `isComponentMounted` — console warnings from catch paths are considered harmless. Only real memory leaks (timers, event listeners) and "setState on unmounted" in success paths are fixed. The maintainer (nemesifier) explicitly wants to avoid over-engineering with defensive checks in every catch block.
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), the Status component uses `this.isComponentMounted` (set to `true` in the constructor, `false` in `componentWillUnmount`) together with a `safeSetState()` helper method that checks `isComponentMounted` before calling `setState()`. This is the preferred pattern to guard against "setState on unmounted component" warnings.
📚 Learning: 2026-03-06T23:26:11.526Z
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), `finalOperations()` has a single early return before setting up intervals/listeners to prevent the scenario where the component unmounts during async awaits. `safeSetState` is applied to success paths in `getUserRadiusSessions()`, `getUserRadiusUsage()`, `getPlansSuccessCallback()`, and `handlePostMessage()`.

Applied to files:

  • client/components/status/status.js
📚 Learning: 2026-03-06T23:26:11.526Z
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), the Status component uses `this.isComponentMounted` (set to `true` in the constructor, `false` in `componentWillUnmount`) together with a `safeSetState()` helper method that checks `isComponentMounted` before calling `setState()`. This is the preferred pattern to guard against "setState on unmounted component" warnings.

Applied to files:

  • client/components/status/status.js
📚 Learning: 2026-03-06T23:26:11.526Z
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), real memory leaks are fixed by calling `clearTimeout(this.usageRetryTimeoutId)` and `window.removeEventListener("message", ...)` in `componentWillUnmount()`. These were actual leaks — the retry timeout could fire and the message handler could run after unmount.

Applied to files:

  • client/components/status/status.js
📚 Learning: 2026-03-06T23:26:11.526Z
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), catch blocks deliberately do NOT check `isComponentMounted` — console warnings from catch paths are considered harmless. Only real memory leaks (timers, event listeners) and "setState on unmounted" in success paths are fixed. The maintainer (nemesifier) explicitly wants to avoid over-engineering with defensive checks in every catch block.

Applied to files:

  • client/components/status/status.js
🔇 Additional comments (2)
client/components/status/status.js (1)

160-171: Call-site migration to storage helpers is consistent and behavior-preserving.

The replacement of in-class storage calls with utility helpers is applied coherently across login/logout flows and stored-flag resolution points.

Also applies to: 234-239, 501-506, 589-594, 706-711

client/utils/captive-portal-storage.js (1)

18-24: storeValue implementation is clean and correctly gated by sync-auth mode.

Writes are properly skipped when synchronous captive-portal auth is disabled.

@kunalverma2512 kunalverma2512 force-pushed the refactor-status-storage-918 branch from d22afcb to 8c0275c Compare March 22, 2026 19:52
@prathmeshkulkarni-coder
Copy link
Copy Markdown
Contributor

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 23, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@client/utils/captive-portal-storage.js`:
- Around line 36-59: Add unit tests for resolveStoredValue covering four
behaviors: (1) when captivePortalSyncAuth is false it returns the fallback; (2)
when cookies.get(key) exists it takes precedence over localStorage, coerces
boolean values (true and "true") and removes the localStorage entry; (3) when
cookies.get(key) is undefined but localStorage.getItem(key) returns "true" it
returns true and removes the localStorage key; and (4) when neither cookie nor
localStorage present it returns the fallback. In each test, stub/mock
cookies.get, localStorage.getItem, and localStorage.removeItem, call
resolveStoredValue(captivePortalSyncAuth, key, fallback, cookies) and assert the
returned boolean and that localStorage.removeItem was called when reading from
storage; include cases for cookie value true and "true" and ensure cookies takes
precedence over localStorage.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: c6ca0bb4-e8a2-4ad1-82c4-488a184178d5

📥 Commits

Reviewing files that changed from the base of the PR and between d22afcb and 8c0275c.

📒 Files selected for processing (2)
  • client/components/status/status.js
  • client/utils/captive-portal-storage.js
📜 Review details
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), `finalOperations()` has a single early return before setting up intervals/listeners to prevent the scenario where the component unmounts during async awaits. `safeSetState` is applied to success paths in `getUserRadiusSessions()`, `getUserRadiusUsage()`, `getPlansSuccessCallback()`, and `handlePostMessage()`.
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), real memory leaks are fixed by calling `clearTimeout(this.usageRetryTimeoutId)` and `window.removeEventListener("message", ...)` in `componentWillUnmount()`. These were actual leaks — the retry timeout could fire and the message handler could run after unmount.
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), catch blocks deliberately do NOT check `isComponentMounted` — console warnings from catch paths are considered harmless. Only real memory leaks (timers, event listeners) and "setState on unmounted" in success paths are fixed. The maintainer (nemesifier) explicitly wants to avoid over-engineering with defensive checks in every catch block.
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), the Status component uses `this.isComponentMounted` (set to `true` in the constructor, `false` in `componentWillUnmount`) together with a `safeSetState()` helper method that checks `isComponentMounted` before calling `setState()`. This is the preferred pattern to guard against "setState on unmounted component" warnings.
📚 Learning: 2026-03-06T23:26:11.526Z
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), `finalOperations()` has a single early return before setting up intervals/listeners to prevent the scenario where the component unmounts during async awaits. `safeSetState` is applied to success paths in `getUserRadiusSessions()`, `getUserRadiusUsage()`, `getPlansSuccessCallback()`, and `handlePostMessage()`.

Applied to files:

  • client/components/status/status.js
📚 Learning: 2026-03-06T23:26:11.526Z
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), the Status component uses `this.isComponentMounted` (set to `true` in the constructor, `false` in `componentWillUnmount`) together with a `safeSetState()` helper method that checks `isComponentMounted` before calling `setState()`. This is the preferred pattern to guard against "setState on unmounted component" warnings.

Applied to files:

  • client/components/status/status.js
📚 Learning: 2026-03-06T23:26:11.526Z
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), real memory leaks are fixed by calling `clearTimeout(this.usageRetryTimeoutId)` and `window.removeEventListener("message", ...)` in `componentWillUnmount()`. These were actual leaks — the retry timeout could fire and the message handler could run after unmount.

Applied to files:

  • client/components/status/status.js
📚 Learning: 2026-03-06T23:26:11.526Z
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), catch blocks deliberately do NOT check `isComponentMounted` — console warnings from catch paths are considered harmless. Only real memory leaks (timers, event listeners) and "setState on unmounted" in success paths are fixed. The maintainer (nemesifier) explicitly wants to avoid over-engineering with defensive checks in every catch block.

Applied to files:

  • client/components/status/status.js
🔇 Additional comments (2)
client/utils/captive-portal-storage.js (1)

18-24: Extraction is clean and preserves the intended storage resolution behavior.

The helper split is solid: sync-auth gating, cookie-first precedence, and localStorage cleanup are all applied consistently.

Also applies to: 36-59

client/components/status/status.js (1)

40-43: Storage-helper migration is consistent across all touched flows.

The new utility is wired correctly in login/logout/payment paths, and the key/fallback usage matches previous intent while reducing class-level duplication.

Also applies to: 160-171, 234-239, 501-506, 589-594, 706-711

Comment thread client/utils/captive-portal-storage.js
@kunalverma2512 kunalverma2512 force-pushed the refactor-status-storage-918 branch from 8c0275c to 08372c5 Compare March 23, 2026 12:15
@kilo-code-bot
Copy link
Copy Markdown

kilo-code-bot Bot commented Mar 23, 2026

Kilo Code Review could not run — your account is out of credits.

Add credits at app.kilo.ai to enable reviews on this change.

This commit extracts the storage logic from the Status component to improve modularity and testability.

Closes openwisp#918
@openwisp-companion
Copy link
Copy Markdown

QA and Linting Failures

Hello @kunalverma2512,
(Analysis for commit 08372c5)

  1. Code Style/QA: The eslint check failed due to an unused variable.
  • Fix: Remove the unused storeValue variable from client/utils/captive-portal-storage.test.js.

@kunalverma2512 kunalverma2512 force-pushed the refactor-status-storage-918 branch from 08372c5 to c74d184 Compare March 23, 2026 12:21
@openwisp-companion
Copy link
Copy Markdown

Hi @kunalverma2512 👋,

This pull request has been marked as stale due to 50 days of inactivity after changes were requested.

As a result, the linked issue(s) have been unassigned from you to allow other contributors to work on it.

However, you can still continue working on this PR! If you push new commits or respond to the review feedback:

  • The issue will be reassigned to you
  • Your contribution is still very welcome

If you need more time or have questions about the requested changes, please let us know. We're happy to help! 🤝

If there's no further activity within 10 more days, this PR will be automatically closed (but can be reopened anytime).

@openwisp-companion openwisp-companion Bot added stale and removed stale labels May 13, 2026
@kunalverma2512
Copy link
Copy Markdown
Author

@nemesifier All checks have passed and the PR is approved. It is ready for merge.
please let me know if any further changes are needed

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.

2 participants