Skip to content

fix(pwa,tracking): toast race condition, scroll setState deduplication, activeCourseMeta lookup trim consistency#584

Merged
devakesu merged 2 commits into3.0.4from
copilot/sub-pr-582
Mar 6, 2026
Merged

fix(pwa,tracking): toast race condition, scroll setState deduplication, activeCourseMeta lookup trim consistency#584
devakesu merged 2 commits into3.0.4from
copilot/sub-pr-582

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 6, 2026

Three correctness/perf bugs identified in PR review thread #582, addressed together.

Description

useBackToExit — toast callback race condition
When showExitToast() dismissed an old toast and immediately created a new one, Sonner's async exit animation could fire the old toast's onDismiss/onAutoClose after the new toast was registered, resetting firstBackTimeRef, exitArmedRef, and exitModeRef for the live toast. Fixed by capturing the toast id in a closure and guarding clearState() behind an identity check:

let newToastId: ReturnType<typeof toast> | null = null;
const handleClear = () => {
  if (toastIdRef.current === newToastId) clearState();
};
newToastId = toast("Press back again to exit", {
  duration: THRESHOLD_MS,
  onDismiss: handleClear,
  onAutoClose: handleClear,
});
toastIdRef.current = newToastId;

TrackingClient — scroll/resize handler redundant re-renders
updateActiveCourse called setActiveCourseKey + setShowPinnedCourse unconditionally on every scroll/resize event, even when the computed value was unchanged. Added lastActiveCourseKeyRef / lastShowPinnedCourseRef to gate setState to actual changes. Also wrapped the event handler in requestAnimationFrame throttling so rapid bursts incur at most one layout read + setState per frame.

TrackingClientactiveCourseMeta lookup trim mismatch
displayCourseName and courseCode were looked up using items[0].course (raw, untrimmed) while grouping keys are keyed on item.course.trim(). Replaced with activeCourseKey (already trimmed) to guarantee lookup hits.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Code refactoring
  • Performance improvement
  • Test updates

Related Issues

Relates to #582

Changes Made

  • src/hooks/useBackToExit.ts: scope onDismiss/onAutoClose callbacks to their toast id via closure guard to prevent stale callbacks clearing active toast state
  • src/app/(protected)/tracking/TrackingClient.tsx: add lastActiveCourseKeyRef + lastShowPinnedCourseRef; gate setActiveCourseKey/setShowPinnedCourse to value changes only; add RAF throttle on scroll/resize handler
  • src/app/(protected)/tracking/TrackingClient.tsx: use activeCourseKey (trimmed) instead of items[0].course for attendanceData/coursesData lookups in activeCourseMeta

Version Bump

  • Version automatically bumped by workflow (same-repo PRs)
  • Version manually bumped using node scripts/bump-version.js (fork PRs)
  • Version already up-to-date (no bump needed)

Testing

Test Environment

  • Node version: 22.x
  • npm version: 10.x
  • OS: Linux

Tests Performed

  • Unit tests pass (npm run test)
  • E2E tests pass (npm run test:e2e)
  • Linting passes (npm run lint)
  • Manual testing completed

Test Coverage

30 existing unit tests across useBackToExit and TrackingClient suites pass with no modifications required.

Documentation

  • Documentation updated (if needed)
  • Code comments added for complex logic
  • API documentation updated (if API changes)

Checklist

  • My code follows the project's code style
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings or errors
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published

Screenshots (if applicable)

N/A — logic-only changes, no UI visual delta.

Additional Notes

The newToastId = null initialization in showExitToast is intentional: handleClear must capture the variable by reference (not value) before toast() is called, making a let + deferred assignment the only viable pattern for this circular closure dependency.


For maintainers:

  • PR title follows conventional commit format
  • Version bump is correct
  • All checks pass
  • Documentation is complete
  • Ready to merge

🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.

Copilot AI mentioned this pull request Mar 6, 2026
10 tasks
…, fix activeCourseMeta lookups

Co-authored-by: devakesu <61821107+devakesu@users.noreply.github.com>
Copilot AI changed the title [WIP] Improve tracking UX and align legal policy updates fix(pwa,tracking): toast race condition, scroll setState deduplication, activeCourseMeta lookup trim consistency Mar 6, 2026
@devakesu devakesu marked this pull request as ready for review March 6, 2026 02:24
@devakesu devakesu self-requested a review as a code owner March 6, 2026 02:24
Copilot AI review requested due to automatic review settings March 6, 2026 02:24
@devakesu devakesu merged commit eb02084 into 3.0.4 Mar 6, 2026
@devakesu devakesu deleted the copilot/sub-pr-582 branch March 6, 2026 02:24
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes a couple of correctness edge cases and reduces unnecessary rendering work in PWA/back-navigation and the tracking page, improving stability and scroll performance in GhostClass.

Changes:

  • Prevents stale Sonner toast callbacks from clearing state for a newer “press back again to exit” toast in useBackToExit.
  • Deduplicates scroll/resize-driven React state updates and throttles the active-course header computation with requestAnimationFrame.
  • Fixes activeCourseMeta lookups to use the trimmed activeCourseKey consistently.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
src/hooks/useBackToExit.ts Guards toast clear callbacks by toast-id identity to avoid race conditions during dismiss/create cycles.
src/app/(protected)/tracking/TrackingClient.tsx Adds RAF throttling + last-value refs to avoid redundant re-renders and ensures trimmed key is used for active course metadata lookups.

devakesu added a commit that referenced this pull request Mar 6, 2026
* feat(tracking,legal): improve tracking UX and align legal policy updates

- add sticky course headers on tracking page
- add right-side scroll-to-bottom floating button near tracking controls
- switch accept-terms success navigation to router.replace to prevent back nav to terms
- update legal policy text (Turnstile clarity, AWS ap-south-1 disclosure, Kochi jurisdiction)
- bump terms version to 2.5 and align legal effective date docs/env examples
- enhance legal page external link visibility and secure external link behavior
- update related tests and mocks (tracking + save-token terms version)

* fix(tracking,pwa): refine pinned course header and reset deep back-exit state

- use header-based scroll detection for pinned course title timing
- adjust scroll-to-end FAB margins slightly on mobile and md breakpoints
- reset non-dashboard back counter when exit state/toast is cleared
- add regression test for deep-mode threshold expiry re-arming behavior

* fix(pwa,tracking): extract clearState helper, consolidate depth counter into navDepthRef, fix Tailwind utilities (#583)

* Initial plan

* fix(pwa,tracking): extract clearState helper, use navDepthRef for deep-back tracking, fix Tailwind utilities

Co-authored-by: devakesu <61821107+devakesu@users.noreply.github.com>

* refine(pwa): clarify navDepthRef semantics and add comment on intentional separation from clearState

Co-authored-by: devakesu <61821107+devakesu@users.noreply.github.com>

* fix(pwa): merge navDepthRef into single qualifying-back counter, remove nonDashboardBackCountRef

Co-authored-by: devakesu <61821107+devakesu@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: devakesu <61821107+devakesu@users.noreply.github.com>

* fix(pwa,tracking): toast race condition, scroll setState deduplication, activeCourseMeta lookup trim consistency (#584)

* Initial plan

* fix(tracking,pwa): guard toast callbacks, deduplicate scroll setState, fix activeCourseMeta lookups

Co-authored-by: devakesu <61821107+devakesu@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: devakesu <61821107+devakesu@users.noreply.github.com>

* fix(tracking): remove unused cardVariants and improve toast dismissal logic in useBackToExit

* fix(legal): normalize legal effective date format and improve handling

* Update src/app/config/legal.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Devanarayanan <fusion@devakesu.com>

* fix(tracking,hooks): aria-hidden decorative icons + accurate stale comments (#585)

* Initial plan

* fix(tracking,hooks): add aria-hidden to decorative BookOpen icons and update stale comments

Co-authored-by: devakesu <61821107+devakesu@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: devakesu <61821107+devakesu@users.noreply.github.com>

---------

Signed-off-by: Devanarayanan <fusion@devakesu.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
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.

3 participants