Skip to content

feat:MobileAuth does not handle biometric prompt cancellation gracefully#729

Merged
RUKAYAT-CODER merged 1 commit into
rinafcode:mainfrom
SheyeJDev:feat/MobileAuth-does-not-handle-biometric-prompt-cancellation-gracefully
Jun 28, 2026
Merged

feat:MobileAuth does not handle biometric prompt cancellation gracefully#729
RUKAYAT-CODER merged 1 commit into
rinafcode:mainfrom
SheyeJDev:feat/MobileAuth-does-not-handle-biometric-prompt-cancellation-gracefully

Conversation

@SheyeJDev

@SheyeJDev SheyeJDev commented Jun 28, 2026

Copy link
Copy Markdown

Biometric cancel leaves loading spinner active
src/hooks/useBiometricAuth.ts
When a user tapped Cancel or "Use Password" on the biometric prompt, isLoading was never reset because the error path treated all failures identically. A switch/case on result.error now handles each case explicitly.

user_cancel — clears loading, no error shown, returns to auth options
user_fallback — sets shouldFallbackToPassword, transitions to password form
Hardware errors (system_cancel, not_enrolled, etc.) — clears loading, shows specific message
Uncaught throw also resets loading via catch block
Loading state cleared in every branch, including unexpected throws
Unit tests for all three branches and the crash path
Course completion event fires before server confirms
src/store/slices/courseProgressStore.ts
If the app was closed after courseCompleted fired but before updateProgressOnServer() resolved, the server record was never written. On relaunch the course showed 99% complete and analytics/certificate triggers had already fired incorrectly.

updateProgressOnServer() now awaited before courseCompleted is emitted
Server error suppresses event emission and rolls back optimistic local state
Retry up to 3× with exponential back-off (500 ms → 1 s → 2 s) before surfacing toast
Server endpoint idempotent — already-completed courses return 200 safely
Event fires only after server returns 2xx
Unit test confirms event not emitted when server returns 500 (after 3 retries)
Analytics events dropped on force-quit
src/services/analytics.ts · App.tsx
Events batched in memory (lesson completed, quiz submitted, certificate earned) were silently lost when the user force-quit before a flush. No retry or persistence was in place.

AppState listener calls flush() on transition to 'background'
Unflushed queue persisted to AsyncStorage on every background transition
On launch, AsyncStorage queue prepended to first batch and sent; cleared after success
Background flush uses expo-task-manager to complete after UI is suspended
Zero events lost across simulated background + force-quit cycle
Unit test confirms recovery on next launch
Search index leaks previous user's courses
src/services/searchIndex.ts · src/store/index.ts
On logout the search index was not cleared. The next user on the same device inherited the prior user's enrolled courses, bookmarks, and completion status in search suggestions — a data privacy issue.

SearchIndexService.clear() added — resets all index maps and cached data
searchIndex.clear() registered in the logout action in src/store/index.ts
AsyncStorage search history also cleared on logout
Index rebuilt fresh after new user login and course catalog load
Index empty immediately after logout
Unit test: build index as user A → logout → 0 results → login as user B → fresh index
Files changed
hooks/useBiometricAuth.ts
store/slices/courseProgressStore.ts
services/analytics.ts
services/searchIndex.ts
store/index.ts
App.tsx
tests/useBiometricAuth.test.ts
tests/courseProgressStore.test.ts
tests/analytics.test.ts
tests/searchIndex.test.ts
Testing notes
All four issues include unit tests covering the specific failure mode described. Biometric tests mock authenticateWithBiometric() per error code. Progress store tests spy on fetch to simulate 500 responses. Analytics tests simulate a background transition and app relaunch. Search index test builds a full index under one user, calls clear(), and asserts zero results on any query.

Closes #641
Closes #642
Closes #643
Closes #640

@drips-wave

drips-wave Bot commented Jun 28, 2026

Copy link
Copy Markdown

@SheyeJDev Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@RUKAYAT-CODER

Copy link
Copy Markdown
Contributor

Thank you for contributing to the project.

@RUKAYAT-CODER RUKAYAT-CODER merged commit 51b61b3 into rinafcode:main Jun 28, 2026
1 of 13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment