Skip to content

Conversation

@ucswift
Copy link
Member

@ucswift ucswift commented Jan 23, 2026

Summary by CodeRabbit

  • New Features

    • Added web-optimized login page with validation, server URL management, and rotating feature showcase.
    • Statistics header styling now supports explicit light/dark background colors.
  • Bug Fixes

    • Onboarding no longer triggers on web; web onboarding state is disabled.
    • Map layer handling tightened to skip invalid or non-array feature data.
  • Tests

    • Added comprehensive web login test suite.
  • Localization

    • Added/updated login translations (en/ar/es).

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 23, 2026

📝 Walkthrough

Walkthrough

Onboarding is now disabled on web; map layer rendering adds defensive Array.isArray checks for Features; new web-only LoginWeb component and tests added; StatItem gains configurable background colors; translation keys for login were expanded across languages.

Changes

Cohort / File(s) Summary
Web Login Feature
src/app/login/index.web.tsx, src/app/login/__tests__/index.web.test.tsx
Added LoginWeb component (forms with zod/react-hook-form, server URL modal, rotating features, analytics, auth flow) and a comprehensive test suite validating UI, form interactions, modal behavior, accessibility, and loading states.
Onboarding Platform Gating
src/app/(app)/_layout.tsx, src/lib/storage/index.web.tsx
Onboarding trigger now requires non-web platforms (Platform.OS !== 'web'); web useIsFirstTime returns [false, no-op] and no longer reads/writes localStorage.
Map Layer Feature Validation
src/app/(app)/map.tsx, src/app/(app)/map.web.tsx, src/components/maps/unified-map-view.tsx, src/components/maps/unified-map-view.web.tsx
Tightened guards to require Array.isArray(layer.Data.Features) before processing layers, preventing non-array Features from being treated as valid.
Stats Component Styling
src/components/dispatch-console/stats-header.tsx
StatItem props changed: bgClassName optional; added bgColor and darkBgColor for explicit light/dark background styling; updated StatsHeader usage for personnel items.
Translations
src/translations/ar.json, src/translations/en.json, src/translations/es.json
Added login-related keys (branding_*, feature_*_*, welcome_title, etc.) and updated page_subtitle / username_placeholder strings in multiple locales.
Minor Map UI Adjustments
src/components/maps/full-screen-location-picker.web.tsx
Small formatting/line changes only (no behavior change).

Sequence Diagram

sequenceDiagram
    actor User
    participant LoginWeb as LoginWeb\r\nComponent
    participant Form as Form\r\n(Validation)
    participant ServerModal as Server URL\r\nModal
    participant Auth as Authentication\r\nService
    participant Analytics as Analytics
    participant Store as Zustand\r\nStore
    participant App as App

    User->>LoginWeb: Load page
    LoginWeb->>Analytics: track view
    LoginWeb->>User: render form + rotating features

    alt open server URL modal
        User->>ServerModal: open
        User->>ServerModal: enter URL
        ServerModal->>Form: validate URL
        ServerModal->>Store: save server URL
        ServerModal->>User: close
    end

    User->>Form: enter credentials
    User->>LoginWeb: submit (click/enter)
    LoginWeb->>Form: validate (zod)
    
    alt validation fails
        Form->>User: show inline errors
    else
        LoginWeb->>LoginWeb: set loading
        LoginWeb->>Analytics: track attempt
        LoginWeb->>Auth: submit credentials

        alt auth succeeds
            Auth->>LoginWeb: return token
            LoginWeb->>Store: update auth
            LoginWeb->>Analytics: track success
            LoginWeb->>App: redirect
        else auth fails
            Auth->>LoginWeb: return error
            LoginWeb->>User: show error modal
            LoginWeb->>Analytics: track failure
            LoginWeb->>LoginWeb: clear loading
        end
    end
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I hopped to the login, bright and new,
Forms that validate, rotating views too,
Server modal saved with a thump and a clack,
Maps now check arrays before they unpack,
I twirl my whiskers — the UI’s on track!

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title covers multiple distinct changes (login page update, header fix, mapbox issue) but the PR primarily focuses on a comprehensive login page redesign. The title is vague and lacks specificity about the main work. Clarify the primary objective: consider 'Redesign web login page with feature carousel and server URL management' or 'Add web login component with animated UI and feature showcase' to better reflect the dominant changes in this PR.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ 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

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

Copy link
Contributor

@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

🤖 Fix all issues with AI agents
In `@src/app/login/index.web.tsx`:
- Around line 1-17: Imports at the top of index.web.tsx are unsorted and failing
the linter; run the ESLint autofix (npx eslint --fix) or your repo's lint:fix
script to reorder them, or manually sort the import groups so that external
packages (e.g., zodResolver, expo-router, lucide-react-native, nativewind,
react, react-hook-form, react-i18next, react-native, react-native-reanimated,
zod) come before internal aliases (e.g., Text, useAnalytics, useAuth, Env,
logger, useServerUrlStore), preserving alphabetical order within groups to
satisfy the import/order rule. Ensure no other import statements are duplicated
or incorrectly grouped and re-run the pipeline to confirm the issue is resolved.
🧹 Nitpick comments (7)
src/components/dispatch-console/stats-header.tsx (1)

30-30: Consider handling partial prop scenarios for robustness.

The current logic bgColor || darkBgColor ? (isDark ? darkBgColor : bgColor) : undefined could return undefined in light mode if only darkBgColor is provided, or in dark mode if only bgColor is provided. While the current usage always provides both values, this could cause unexpected behavior for future callers.

♻️ Optional: Fallback to the other color if one is missing
-  const backgroundColor = bgColor || darkBgColor ? (isDark ? darkBgColor : bgColor) : undefined;
+  const backgroundColor = bgColor || darkBgColor ? (isDark ? (darkBgColor ?? bgColor) : (bgColor ?? darkBgColor)) : undefined;
src/app/(app)/map.web.tsx (1)

489-492: Avoid gap property in StyleSheet for web compatibility.

Per the coding guidelines, the gap property has inconsistent support on web. Consider using margin properties instead.

♻️ Replace gap with margin
  layersPanelActions: {
    flexDirection: 'row',
    padding: 12,
-   gap: 8,
  },
  actionButton: {
    flex: 1,
    paddingVertical: 8,
    paddingHorizontal: 12,
    borderRadius: 8,
    alignItems: 'center',
+   marginHorizontal: 4,
  },
src/app/login/__tests__/index.web.test.tsx (2)

106-109: Module-level mock is unused.

The mockLogin at line 106 is never invoked because MockLoginWeb creates its own internal mockLogin (line 18). If you intend to verify that login was called with correct arguments, you need to wire the module-level mock into MockLoginWeb.

♻️ Suggested approach to use the module-level mock
 // Mock the entire web login module
 jest.mock('../index.web', () => {
   const React = require('react');
   const { View, Text, TextInput, Pressable } = require('react-native');
+  const { mockLogin } = require('../__mocks__/loginHelpers'); // or pass via closure
 
   const MockLoginWeb = () => {
     const [username, setUsername] = React.useState('');
     const [password, setPassword] = React.useState('');
     const [showPassword, setShowPassword] = React.useState(false);
     const [isLoading, setIsLoading] = React.useState(false);
     const [showServerUrlModal, setShowServerUrlModal] = React.useState(false);
     const [showErrorModal, setShowErrorModal] = React.useState(false);
 
-    const mockLogin = jest.fn();
     const mockOnSubmit = () => {
       if (username && password) {
         setIsLoading(true);
-        mockLogin({ username, password });
+        // Use the external mock for assertions
         setTimeout(() => setIsLoading(false), 100);
       }
     };

Alternatively, if the internal mock suffices for current test scope, consider removing the unused mockLogin at line 106 to avoid confusion.


83-91: Error modal display is untestable with current mock.

The showErrorModal state is initialized to false and never set to true in MockLoginWeb, making it impossible to test error modal visibility. Consider adding a mechanism to trigger the error state if error handling tests are needed.

src/app/login/index.web.tsx (3)

78-100: Consider adding accessibility attributes to native input.

The native HTML input lacks proper ARIA attributes for screen reader support. While placeholders provide visual context, they don't serve as accessible labels.

♿ Suggested accessibility improvements
 <input
   type={type === 'password' && !showPassword ? 'password' : 'text'}
   className="web-input-accessible"
+  aria-label={placeholder}
+  aria-invalid={!!error}
+  aria-describedby={error ? `${placeholder}-error` : undefined}
   style={{
     flex: 1,
     border: 'none',
     // ... rest of styles
   }}
   placeholder={placeholder}
   // ... rest of props
 />

And for the error container:

 {error ? (
-  <Animated.View entering={FadeIn.duration(200)} style={styles.errorContainer}>
+  <Animated.View entering={FadeIn.duration(200)} style={styles.errorContainer} id={`${placeholder}-error`} role="alert">
     <AlertCircle size={14} color="#ef4444" />
     <Text style={styles.errorText}>{error}</Text>
   </Animated.View>
 ) : null}

815-817: Multiple uses of gap property in StyleSheet.

Per coding guidelines, the gap property has inconsistent support. However, since this is a web-only component (.web.tsx), modern browser support should be adequate. If older browser support is needed, consider using margin properties instead.

Occurrences: formContainer (line 816), errorContainer (line 853), loadingContainer (line 885), serverUrlButton (line 893), footerContainer (line 925), modalButtonRow (line 1035), featuresGrid (line 670).


356-418: Inconsistent indentation in form container section.

The static analysis flagged extra indentation in this section (lines 356-418). Running the formatter should fix this automatically.

@ucswift
Copy link
Member Author

ucswift commented Jan 23, 2026

Approve

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

This PR is approved.

@ucswift ucswift merged commit a291b70 into master Jan 23, 2026
9 of 10 checks passed
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