Skip to content

frontend improvements & bug fixes - #356

Merged
edenbar23 merged 16 commits into
mainfrom
chore/frontend/structure-improvements
Aug 10, 2026
Merged

frontend improvements & bug fixes#356
edenbar23 merged 16 commits into
mainfrom
chore/frontend/structure-improvements

Conversation

@SagiEv

@SagiEv SagiEv commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator

Walkthrough: Frontend Codebase Improvements & Maintenance Mode

This document summarizes all the structural and architectural changes implemented in the frontend application, along with the backend authentication adjustments to accommodate cookie-based web sessions and the newly requested Maintenance Mode.

Structural Improvements

  • Component Consolidation: We removed the duplicate frontend/components/ directory and merged its UI components (e.g., collapsible.tsx, themed-view.tsx) strictly into frontend/app/components/. We now have a single source of truth for UI components.
  • Dependency Cleanup: expo-router was completely uninstalled and removed from package.json, cutting down unnecessary bundle weight since @react-navigation/native is strictly handling all navigation.
  • TS Path Aliasing:
    • tsconfig.json was updated to support the @/* alias mapping to ./app/*.
    • All relative imports globally (e.g., ../../api/apiFetch) were refactored to use the cleaner, module-based @/ aliasing.

Design System Integration

  • Centralized Theme Tokens: Created a foundational theme.ts inside app/theme/. This abstracts colors, typography, spacing, and border radii.
  • LoginScreen Refactor: Updated the LoginScreen to strip out all magic hex colors (like #4B7BE5 and #2E8B57), replacing them with semantic equivalents like theme.colors.primary and theme.colors.secondary.

Security & API Hardening

  • Cookie-Based Web Authentication:

    • Backend Updates: Overhauled the backend AuthController.java and ExternalAuthController.java to set HttpOnly session cookies (accessToken and refreshToken) for browser protection against XSS. SecurityConfig was also updated to explicitly allowCredentials(true).
    • Frontend Handling: Built an abstraction layer, tokenUtils.ts, which correctly identifies the platform. On Web, it bypasses unsafe localStorage token caching entirely and instructs apiFetch.ts to include cookies on all network requests natively. On Mobile, it delegates storage back to expo-secure-store.
    • Circular dependencies between authStore and apiFetch have been removed in the process.
  • Global Error Handling:

    • Added a <GlobalErrorBoundary> wrapper around the entire app to catch unexpected React rendering failures gracefully.
    • Implemented react-native-toast-message for global, visual Toast notifications during standard API failures (4xx codes) instead of failing silently.

Maintenance Mode Implementation

  • Introduced a new feature to gracefully degrade user experience during backend outages or updates.
  • Implementation Highlights:
    • Catching 500s: The core apiFetch.ts logic now intercepts any 5xx internal server error responses and immediately dispatches a global state flag isMaintenanceMode in appStateStore.ts.
    • Overlay Rendering: App.tsx conditionally halts the standard RootNavigator presentation and renders a full-screen MaintenanceScreen.
    • Self-Healing Poll: A background hook, useHealthCheck.ts, automatically polls the /health endpoint every 10 seconds while the app is in maintenance mode. Once it returns an HTTP 200 OK, the app autonomously resumes standard operation.

Tip

The placeholder GIF for the maintenance screen is currently located at frontend/assets/images/maintenance.gif. Please replace this file with the actual animated GIF you intended to use!

Handled Some Console Warnings

Those warnings are specific to React Native Web's rendering in the DOM:

  1. "Password field is not contained in a form": When password managers inspect the DOM, they look for standard HTML <form> tags. By default, React Native <View> components render as <div>s, which triggers this warning in Chrome. I fixed this by wrapping the inputs in a <View accessibilityRole="form">, which instructs React Native Web to render an actual <form> tag.
  2. "Blocked aria-hidden on an element...": This happens because you clicked the "Login" button (giving it focus), and immediately after, the app navigated you to the Dashboard screen. React Native Web hides the previous login screen from screen readers by applying aria-hidden="true", but the button still technically had focus in the DOM. Browsers flag this as an accessibility violation. I added Keyboard.dismiss() and a direct document.activeElement.blur() trigger right when you press login so the button safely releases focus before the screen transition.

Both warnings should now be resolved!

Logout error fix

The 401 Unauthorized error during logout was happening because of a combination of two things:

  1. Backend Security Filter: /api/v1/auth/logout was accidentally left out of the permitAll() block in SecurityConfig.java. Spring Security was intercepting the logout request and demanding a valid access token first, throwing the 401 before the request even reached the AuthController!
  2. Frontend Token Clearing: In authStore.ts, the code was clearing the token from local storage before making the API call to logout. It also used credentials: "omit", which meant the web cookies weren't sent to the backend anyway.

I've updated SecurityConfig.java to permitAll the logout route (since we just want to invalidate the refresh token in the payload/cookie). I also updated authStore.ts to retrieve the refreshToken before clearing the local state, and changed it to credentials: "include" so the cookies are successfully sent and cleared by the backend.

Task Progression & Button State Fixes

I have successfully implemented the changes outlined in the implementation plan to ensure your users' task progression accurately updates and the interface reacts correctly to their progress.

What was Changed

  • Immediate Cache Invalidation (SwipeScreen.tsx):
    When a user successfully submits a classification (swiping an image), the frontend now explicitly clears the cache for their task lists and global statistics. This forces the app to immediately fetch the new progress (imagesClassified) behind the scenes. Your progress bars in Quick Start, Task Details, and My Collection will now update instantly without needing to wait 5 minutes for the cache to go stale!

  • Dynamic Task Details Button (TaskDetailsScreen.tsx):
    The big blue button at the bottom of the Task Details screen now acts intelligently based on the user's progress:

    • Start Classifying: Shown if the user hasn't classified any images in this task yet.
    • Continue Classifying: Shown if they have partially completed the task.
    • Completed (Disabled): Shown if there are 0 pending images left to classify. This gracefully prevents users from trying to classify a task they have already finished.

Verification

  • You can test this by logging in as a normal user.
  • Start a new task, swipe a single image, and then hit the back button.
  • You will see that your "Quick Start" bar has moved up, and opening the task details again will display "Continue Classifying"!

Secure Password Changes for External Users

I have successfully restricted all password management functionality so that it is strictly available only for LOCAL users, completely preventing Google Auth or STARdbi users from changing or resetting passwords.

What was Changed

1. Created the Missing Backend Endpoint

The frontend's "Change Password" button was silently failing because the /api/v1/auth/password/change backend API didn't actually exist! I created the endpoint in AuthController.java and implemented its logic in AuthenticationService.java to securely update the user's password.

2. Backend Security Enforcement

  • Change Password: The newly created endpoint explicitly checks the authenticated user's provider. If it is not LOCAL, it instantly throws a security exception.
  • Forgot Password: The /password/forgot logic has been patched. When an email is submitted, it now checks if the matched user account is LOCAL. If the user is authenticated via Google or STARdbi, it gracefully returns success to prevent email enumeration, but deliberately skips sending a reset token.

3. Frontend UI Updates

  • Passed the authentication provider type securely from the backend to the frontend within the user's profile data (UserProfileResponse.java).
  • Updated the Profile Screen (ProfileScreen.tsx) to conditionally render the "Change Password" button. If the user is logged in via Google Auth or STARdbi, the button is entirely hidden from the UI to avoid confusion.

Verification

  • Local users can now successfully change their passwords via the Profile Screen, and they can use the "Forgot Password" link on the login page.
  • For Google or STARdbi users, the "Change Password" button will no longer appear on their profile, and they cannot bypass this restriction via direct backend API calls.

@SagiEv SagiEv added bug Something isn't working enhancement New feature or request labels Aug 9, 2026
@SagiEv SagiEv linked an issue Aug 9, 2026 that may be closed by this pull request
@SagiEv SagiEv added the chore setup, cleanup, configs, folder structure, refactors label Aug 9, 2026
@SagiEv
SagiEv marked this pull request as ready for review August 9, 2026 21:26
@SagiEv SagiEv self-assigned this Aug 9, 2026
@edenbar23
edenbar23 merged commit af545d9 into main Aug 10, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working chore setup, cleanup, configs, folder structure, refactors enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Frontend Structure Improvements

2 participants