Commit Graph

67 Commits

Author SHA1 Message Date
Trey t
56b1f57ec7 Add comprehensive UI test suite with XCUITest
Added complete UI test suite covering authentication, residences, tasks,
and contractors. Tests follow best practices with helper methods, proper
waits, and accessibility identifier usage.

New test files:
- UITestHelpers.swift: Shared helper methods for login, navigation, waits
- AuthenticationTests.swift: Login, registration, logout flow tests
- ComprehensiveResidenceTests.swift: Full residence CRUD and validation tests
- ComprehensiveTaskTests.swift: Task creation, editing, completion tests
- ComprehensiveContractorTests.swift: Contractor management and edge case tests
- ResidenceTests.swift: Additional residence-specific scenarios
- TaskTests.swift: Additional task scenarios
- SimpleLoginTest.swift: Basic smoke test for CI/CD
- MyCribUITests.swift: Base test class setup
- AccessibilityIdentifiers.swift: Test target copy of identifiers

Test coverage:
- Authentication: Login, registration, logout, error handling
- Residences: Create, edit, delete, validation, multi-field scenarios
- Tasks: Create, complete, edit, cancel, status changes
- Contractors: Create with minimal/full data, phone formats, specialties

All tests use accessibility identifiers for reliable element location and
include proper waits for asynchronous operations.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-20 23:06:57 -06:00
Trey t
73c9f2d5a3 Add RootView for authentication state management
Added RootView to manage authentication state and navigation between login
and main tab views. This simplifies the app structure and makes it easier
to test authentication flows.

Changes:
- Added RootView.swift: Centralized auth state management using
  AuthenticationManager singleton
- Updated iOSApp.swift: Changed entry point from LoginView to RootView
- RootView automatically shows LoginView or MainTabView based on auth state
- Supports logout flow and automatic navigation on login success

This enables UI tests to start from a known state and test full
authentication flows end-to-end.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-20 23:06:39 -06:00
Trey t
a2295672b9 Add comprehensive accessibility identifiers for UI testing
Added AccessibilityIdentifiers helper struct with identifiers for all major
UI elements across the app. Applied identifiers throughout authentication,
navigation, forms, and feature screens to enable reliable UI testing.

Changes:
- Added Helpers/AccessibilityIdentifiers.swift with centralized ID definitions
- LoginView: Added identifiers for username, password, login button fields
- RegisterView: Added identifiers for registration form fields
- MainTabView: Added identifiers for all tab bar items
- ProfileTabView: Added identifiers for logout and settings buttons
- ResidencesListView: Added identifier for add button
- Task views: Added identifiers for add, save, and form fields
- Document forms: Added identifiers for form fields and buttons

Identifiers follow naming pattern: [Feature].[Element]
Example: AccessibilityIdentifiers.Authentication.loginButton

This enables UI tests to reliably locate elements using:
app.buttons[AccessibilityIdentifiers.Authentication.loginButton]

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-20 23:06:31 -06:00
Trey t
1100bc423d Make contractor phone optional and add UI test accessibility identifiers
Updated contractor models and forms to make phone field optional. Added
accessibility identifiers for add buttons to enable UI testing.

Contractor changes:
- Kotlin: Made phone nullable in Contractor, ContractorCreateRequest,
  ContractorSummary models
- Android: Updated AddContractorDialog validation to only require name
- Android: Removed asterisk from phone field label
- Android: Updated ContractorDetailScreen to handle nullable phone
- iOS: Updated ContractorFormSheet validation to only check name field
- iOS: Updated form footer text to show only name as required
- iOS: Updated ContractorDetailView to use optional binding for phone display

Accessibility improvements:
- iOS: Added accessibility identifier to contractor add button in
  ContractorsListView
- iOS: Added accessibility identifier to task add button in
  ResidenceDetailView

These identifiers enable reliable UI testing by allowing tests to access
buttons by their accessibility identifiers instead of searching by label.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-20 23:04:06 -06:00
Trey t
dd5e050025 Make residence address fields optional (only name required)
Updated Kotlin models, Android UI, and iOS UI to make all address fields
optional for residences. Only the residence name is now required.

Changes:
- Kotlin: Made propertyType, streetAddress, city, stateProvince, postalCode,
  country nullable in Residence, ResidenceSummary, ResidenceWithTasks models
- Kotlin: Updated navigation routes to handle nullable address fields
- Android: Updated ResidenceFormScreen and ResidenceDetailScreen to handle nulls
- iOS: Updated ResidenceFormView validation to only check name field
- iOS: Updated PropertyHeaderCard and ResidenceCard to use optional binding
  for address field displays

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-20 23:03:45 -06:00
Trey t
630e95e462 add in profile tab 2025-11-17 09:39:31 -08:00
Trey t
52afefc17e Fix residence list not refreshing after add/edit on iOS and Android
Fixed issue where adding or editing a residence didn't update the residence
list, requiring manual refresh to see changes.

iOS Changes:
- ResidencesListView: Added onResidenceCreated callback to AddResidenceView
  sheet that triggers loadMyResidences(forceRefresh: true)
- AddResidenceView: Added onResidenceCreated callback parameter
- ResidenceFormView: Added onSuccess callback that fires before dismissing
  in both create and update modes

Android Changes:
- ResidencesScreen: Added shouldRefresh parameter with LaunchedEffect that
  watches for changes and reloads residences when flag is true
- App.kt (ResidencesRoute): Read "refresh" flag from saved state handle
- App.kt (AddResidenceRoute): Set "refresh" flag in previous back stack
  entry before navigating back on residence created
- App.kt (EditResidenceRoute): Set "refresh" flag before navigating back
  on residence updated

Both platforms now properly refresh the residence list when:
- A new residence is added
- An existing residence is edited
- User joins a residence with code (already working)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-17 09:38:31 -08:00
Trey t
d777880d2b Fix iOS build errors - Update TaskDetail model usage for Double cost fields
Fixed type conversion issues in iOS Swift files to handle KotlinDouble for
cost fields instead of String. Updated all task-related views to properly
convert between String (for TextField input) and KotlinDouble (for API calls).

Changes:
- TaskCard.swift: Updated preview data with new TaskDetail signature (added
  residenceName, createdBy, createdByUsername, intervalDays; changed
  estimatedCost from String to Double; removed actualCost and notes)
- TasksSection.swift: Updated two preview TaskDetail instances with new signature
- CompleteTaskView.swift: Convert actualCost String to KotlinDouble for API
- EditTaskView.swift: Convert estimatedCost between KotlinDouble and String
  for display and API calls
- TaskFormView.swift: Convert estimatedCost String to KotlinDouble for API

Pattern used:
- Display: KotlinDouble -> String using .doubleValue
- API: String -> Double -> KotlinDouble using KotlinDouble(double:)

Build now succeeds with all type conversions properly handling Decimal/Double
values from backend instead of String.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-15 23:12:57 -06:00
Trey t
0130b2cdf1 Add documentation and remove hardcoded task threshold from API calls
Added comprehensive usage documentation for dynamic task summary components
and updated TaskApi to rely on backend's default threshold value.

**Changes:**

**New: TASK_SUMMARY_USAGE.md**
- Complete Android usage guide for TaskSummaryCard component
- Examples of basic usage, filtering categories, and customization
- Documents all available categories and their metadata
- Shows how to use dynamic task summary in different screens

**New: iosApp/TASK_SUMMARY_USAGE_IOS.md**
- Complete iOS usage guide for TaskSummaryCard SwiftUI component
- Examples for ResidenceDetailView, ResidenceCard, and HomeScreen
- Documents SF Symbol icon usage and color parsing
- Integration examples and troubleshooting tips

**New: TaskConstants.kt**
- Created client-side constants file (currently unused)
- Contains TASK_CURRENT_THRESHOLD_DAYS = 29
- Available for future use if client needs local threshold

**Updated: TaskApi.kt**
- Changed days parameter from `days: Int = 30` to `days: Int? = null`
- Now only sends days parameter to backend if explicitly provided
- Allows backend's default threshold (29 days) to be used
- Applied to both getTasks() and getTasksByResidence()

**Updated: ApiConfig.kt**
- Minor configuration update

**Benefits:**
 Comprehensive documentation for both platforms
 Apps now use backend's default threshold value
 Cleaner API calls without unnecessary parameters
 Client can still override threshold if needed
 Documentation includes troubleshooting and best practices

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-15 11:18:14 -06:00
Trey t
bb5664c954 Implement fully dynamic task summary UI from API data
Updated both iOS and Android to build residence task summary UI entirely
from API response data, with no hardcoded categories, icons, colors, or labels.

**Changes:**

**Backend Integration:**
- Updated TaskSummary model to use dynamic categories list instead of static fields
- Added TaskColumnCategory and TaskColumnIcon models for metadata
- Categories now include: name, displayName, icons (ios/android/web), color, count

**Android (ResidencesScreen.kt):**
- Removed hardcoded category extraction (overdue_tasks, current_tasks, in_progress_tasks)
- Now dynamically iterates over first 3 categories from API
- Added getIconForCategory() helper to map icon names to Material Icons
- Added parseHexColor() helper that works in commonMain (no Android-specific code)
- Uses category.displayName, category.icons.android, category.color from API

**iOS (ResidenceCard.swift):**
- Removed hardcoded category extraction and SF Symbol names
- Now dynamically iterates over first 3 categories using ForEach
- Uses category.displayName, category.icons.ios, category.color from API
- Leverages existing Color(hex:) extension for color parsing

**Component Organization:**
- Moved TaskSummaryCard.kt from commonMain to androidMain (uses Android-specific APIs)
- Created TaskSummaryCard.swift for iOS with dynamic category rendering

**Benefits:**
 Backend controls all category metadata (icons, colors, display names)
 Apps automatically reflect backend changes without redeployment
 No platform-specific hardcoded values
 Single source of truth in task/constants.py TASK_COLUMNS

**Files Changed:**
- Residence.kt: Added TaskColumnCategory, TaskColumnIcon models
- ResidencesScreen.kt: Dynamic category rendering with helpers
- ResidenceCard.swift: Dynamic category rendering with ForEach
- TaskSummaryCard.kt: Moved to androidMain
- TaskSummaryCard.swift: New iOS dynamic component

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-15 11:13:37 -06:00
Trey t
2730c94e4d Add comprehensive error message parsing to prevent raw JSON display
- Created ErrorMessageParser utility for both iOS (Swift) and Android (Kotlin)
- Parser detects JSON-formatted error messages and extracts user-friendly text
- Identifies when data objects (not errors) are returned and provides generic messages
- Updated all API error handling to pass raw error bodies instead of concatenating
- Applied ErrorMessageParser across all ViewModels and screens on both platforms
- Fixed ContractorApi and DocumentApi to not concatenate error bodies with messages
- Updated ApiResultHandler to automatically parse all error messages
- Error messages now show "Request failed. Please check your input and try again." instead of raw JSON

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-14 22:59:42 -06:00
Trey t
1d3a06f492 Add comprehensive error handling utilities for all screens
Created reusable error handling components that can be used across all
screens in both Android and iOS apps to show retry/cancel dialogs when
network calls fail.

Android Components:
- ApiResultHandler: Composable that automatically handles ApiResult states
  with loading indicators and error dialogs
- HandleErrors(): Extension function for ApiResult to show error dialogs
  for operations that don't return display data
- Updated ResidencesScreen to import ApiResultHandler

iOS Components:
- ViewStateHandler: SwiftUI view that handles loading/error/success states
  with automatic error alerts
- handleErrors(): View modifier for automatic error monitoring
- Both use the existing ErrorAlertModifier for consistent alerts

Documentation:
- Created ERROR_HANDLING.md with comprehensive usage guide
- Includes examples for data loading and create/update/delete operations
- Migration guide for updating existing screens
- Best practices and testing guidelines

These utilities make it easy to add consistent error handling with retry
functionality to any screen that makes network calls, improving the user
experience across the entire app.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-14 14:28:09 -06:00
Trey t
0e3b9681f6 Add error dialogs with retry/cancel for network failures
Implemented user-friendly error handling for network call failures:

Android (Compose):
- Created reusable ErrorDialog component with retry and cancel buttons
- Updated TasksScreen to show error dialog popup instead of inline error
- Error dialog appears when network calls fail with option to retry

iOS (SwiftUI):
- Created ErrorAlertModifier and ErrorAlertInfo helpers
- Added .errorAlert() view modifier for consistent error handling
- Updated TaskFormView to show error alerts with retry/cancel options
- Error alerts appear when task creation or other network calls fail

Both platforms now provide a consistent user experience when network
errors occur, giving users the choice to retry the operation or cancel.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-14 11:20:58 -06:00
Trey t
6ffd5ff626 Add confirmation dialogs for destructive task actions
iOS:
- Add archive task confirmation to TaskActionButtons.swift
- Add archive task confirmation to AllTasksView.swift
- Add cancel and archive task confirmations to ResidenceDetailView.swift
- Fix generatePropertyReport call to use new method signature

Android:
- Add cancel task confirmation to ResidenceDetailScreen.kt
- Add archive task confirmation to ResidenceDetailScreen.kt

All destructive task actions (cancel, archive/delete) now require user confirmation with clear warning messages before proceeding.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-13 23:44:41 -06:00
Trey t
a2de0f3454 Migrate iOS app to system colors and improve UI/UX
- Remove AppColors struct, migrate to iOS system colors throughout
- Redesign ContractorFormSheet to use native SwiftUI Form components
- Add color-coded icons to contractor form sections
- Improve dark mode contrast for task cards
- Add background colors to document detail fields
- Fix text alignment issues in ContractorDetailView
- Make task completion lists expandable/collapsible by default
- Clear app badge on launch and when app becomes active
- Update button styling with proper gradients and shadows
- Improve form field focus states and accessibility

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-13 22:22:52 -06:00
Trey t
29c136d612 Migrate Android app to Material3 system colors and improve UX
- Remove AppColors object, migrate to Material3 semantic colors throughout
- Add collapsible dropdown menu for task card actions
- Implement pull-to-refresh on Residences, Documents, and Contractors screens
- Add refresh button to All Tasks screen with forceRefresh support
- Fix nullable function reference error in TaskCard (make onEditClick nullable)
- Fix layout padding issues on All Tasks and Tasks screens
- Remove unused AppColors import from HomeScreen

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-13 22:21:54 -06:00
Trey t
ff390a85c2 ios push notifications 2025-11-13 16:13:36 -06:00
Trey t
b2f2627ad5 Update task cards to use menu-based actions and horizontal grid layout
- Replaced individual action buttons with a single Actions menu in DynamicTaskCard
  - Organized menu items into sections (primary, secondary, destructive)
  - Added visual dividers between action groups
  - Blue button styling for better visibility
  - Added debug logging for menu interactions
  - Menu properly handles all action types (mark in progress, complete, edit, cancel, restore, archive, unarchive)

- Converted AllTasksView to use horizontal grid layout (LazyHGrid)
  - Changed from vertical scroll to horizontal scroll
  - Added paging behavior with scroll target alignment
  - Added scroll transitions for smooth animations (fade and scale)
  - Fixed width columns (350pt) for consistent sizing
  - Maintained pull-to-refresh functionality

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-13 14:53:30 -06:00
Trey t
2b95c3b9c1 Refactor iOS forms and integrate notification API with APILayer
- Refactored ContractorFormSheet to follow SwiftUI best practices
  - Moved Field enum outside struct and renamed to ContractorFormField
  - Extracted body into computed properties for better readability
  - Replaced deprecated NavigationView with NavigationStack
  - Fixed input field contrast in light mode by adding borders
  - Fixed force cast in loadContractorSpecialties

- Refactored TaskFormView to eliminate screen flickering
  - Moved Field enum outside struct and renamed to TaskFormField
  - Fixed conditional view structure that caused flicker on load
  - Used ZStack with overlay instead of if/else for loading state
  - Changed to .task modifier for proper async initialization
  - Made loadLookups properly async and fixed force casts
  - Replaced deprecated NavigationView with NavigationStack

- Integrated PushNotificationManager with APILayer
  - Updated registerDeviceWithBackend to use APILayer.shared.registerDevice()
  - Updated updateNotificationPreferences to use APILayer
  - Updated getNotificationPreferences to use APILayer
  - Added proper error handling with try-catch pattern

- Added notification operations to APILayer
  - Added NotificationApi instance
  - Implemented registerDevice, unregisterDevice
  - Implemented getNotificationPreferences, updateNotificationPreferences
  - Implemented getNotificationHistory, markNotificationAsRead
  - Implemented markAllNotificationsAsRead, getUnreadCount
  - All methods follow consistent pattern with auth token handling

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-13 13:12:54 -06:00
Trey t
230eb013dd Integrate static_data endpoint to replace 6 separate lookup API calls
- Added StaticDataResponse model to combine all lookup data
- Added getStaticData() method to LookupsApi
- Updated LookupsRepository to fetch all lookups in single API call
- Added updateAllLookups() method to DataCache for batch updates
- Reduces network requests from 6 to 1 for initial data load
- Improves app startup performance with Redis-cached response

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-12 22:15:29 -06:00
Trey t
4d05292daa Replace custom AppTypography with native iOS font sizes
Removed the custom AppTypography system and migrated all font references
to use native SwiftUI Dynamic Type sizes. This enables automatic text
scaling based on user preferences and ensures consistency with iOS
design standards.

Changes:
- Removed AppTypography struct from DesignSystem.swift
- Updated PrimaryButtonStyle and SecondaryButtonStyle to use .headline
- Replaced all typography references throughout the app with native fonts:
  - displayLarge → .largeTitle.weight(.bold)
  - headlineSmall → .title3.weight(.semibold)
  - titleMedium → .title3.weight(.semibold)
  - bodyMedium → .body
  - labelMedium → .footnote.weight(.medium)
  - And many more across 18 files

Benefits:
- Supports Dynamic Type for accessibility
- Reduces custom code maintenance
- Aligns with iOS design guidelines

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-12 21:26:56 -06:00
Trey t
b1a24014ab Add pull-to-refresh functionality and improve loading states across iOS views
- Added pull-to-refresh to ResidencesListView with force refresh support
- Added pull-to-refresh to AllTasksView with rotating refresh button
- Added pull-to-refresh to ContractorsListView with force refresh
- Added pull-to-refresh to DocumentsTabContent and WarrantiesTabContent
- Improved loading state checks to prevent empty list flash during initial load
- Added refresh button to AllTasksView toolbar with clockwise rotation animation
- Improved UX by disabling refresh button while loading is in progress

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-12 21:11:50 -06:00
Trey t
a61cada072 Implement unified network layer with APILayer and migrate iOS ViewModels
Major architectural improvements:
- Created APILayer as single entry point for all network operations
- Integrated cache-first reads with automatic cache updates on mutations
- Migrated all shared Kotlin ViewModels to use APILayer instead of direct API calls
- Migrated iOS ViewModels to wrap shared Kotlin ViewModels with StateFlow observation
- Replaced LookupsManager with DataCache for centralized lookup data management
- Added password reset methods to AuthViewModel
- Added task completion and update methods to APILayer
- Added residence user management methods to APILayer

iOS specific changes:
- Updated LoginViewModel, RegisterViewModel, ProfileViewModel to use shared AuthViewModel
- Updated ContractorViewModel, DocumentViewModel to use shared ViewModels
- Updated ResidenceViewModel to use shared ViewModel and APILayer
- Updated TaskViewModel to wrap shared ViewModel with callback-based interface
- Migrated PasswordResetViewModel and VerifyEmailViewModel to shared AuthViewModel
- Migrated AllTasksView, CompleteTaskView, EditTaskView to use APILayer
- Migrated ManageUsersView, ResidenceDetailView to use APILayer
- Migrated JoinResidenceView to use async/await pattern with APILayer
- Removed LookupsManager.swift in favor of DataCache
- Fixed PushNotificationManager @MainActor issue
- Converted all direct API calls to use async/await with proper error handling

Benefits:
- Reduced code duplication between iOS and Android
- Consistent error handling across platforms
- Automatic cache management for better performance
- Centralized network layer for easier testing and maintenance
- Net reduction of ~700 lines of code through shared logic

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-12 20:29:42 -06:00
Trey t
eeb8a96f20 Implement centralized data caching system
This commit adds a comprehensive caching system that loads all data
on app launch and keeps it in memory, eliminating redundant API calls
when navigating between screens.

Core Implementation:
- DataCache: Singleton holding all app data in StateFlow
- DataPrefetchManager: Loads all data in parallel on app launch
- Automatic cache updates on create/update/delete operations

Features:
-  Instant screen loads from cached data
-  Reduced API calls (no redundant requests)
-  Better UX (no loading spinners on navigation)
-  Offline support (data remains available)
-  Consistent state across all screens

Cache Contents:
- Residences (all + my residences + summaries)
- Tasks (all tasks + tasks by residence)
- Documents (all + by residence)
- Contractors (all)
- Lookup data (categories, priorities, frequencies, statuses)

ViewModels Updated:
- ResidenceViewModel: Uses cache with forceRefresh option
- TaskViewModel: Uses cache with forceRefresh option
- Updates cache on successful create/update/delete

iOS Integration:
- Data prefetch on successful login
- Cache cleared on logout
- Background prefetch doesn't block authentication

Usage:
// Load from cache (instant)
viewModel.loadResidences()

// Force refresh from API
viewModel.loadResidences(forceRefresh: true)

Next Steps:
- Update DocumentViewModel and ContractorViewModel (same pattern)
- Add Android MainActivity integration
- Add pull-to-refresh support

See composeApp/src/commonMain/kotlin/com/example/mycrib/cache/README_CACHING.md
for complete documentation and implementation guide.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-12 17:57:21 -06:00
Trey t
d5d16c5c48 Add comprehensive unit tests for iOS and Android/KMM
This commit adds extensive unit test coverage for the entire application,
including iOS ViewModels, design system, and shared Kotlin Multiplatform code.

iOS Unit Tests (49 tests):
- LoginViewModelTests: Authentication state and validation tests
- ResidenceViewModelTests: Residence loading and state management
- TaskViewModelTests: Task operations (cancel, archive, mark progress)
- DocumentViewModelTests: Document/warranty CRUD operations
- ContractorViewModelTests: Contractor management and favorites
- DesignSystemTests: Color system, typography, spacing, radius, shadows

Shared KMM Unit Tests (26 tests):
- AuthViewModelTest: Login, register, verify email state initialization
- TaskViewModelTest: Task state management verification
- DocumentViewModelTest: Document state initialization tests
- ResidenceViewModelTest: Residence state management tests
- ContractorViewModelTest: Contractor state initialization tests

Test Infrastructure:
- Reorganized test files from iosAppUITests to MyCribTests
- All shared KMM tests passing successfully (./gradlew test)
- Tests focus on state initialization and core functionality
- Ready for CI/CD integration

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-12 17:50:29 -06:00
Trey t
0a7e7bc27f Fix ScrollView content obstruction by tab bar on iOS
This commit fixes the issue where ScrollView content at the bottom of screens was being hidden behind the tab bar.

## Changes
- Added .safeAreaInset(edge: .bottom) to all main tab ScrollViews
- Increased bottom padding to AppSpacing.xxxl (64pt) for better spacing
- Removed .ignoresSafeArea(edges: .bottom) from AllTasksView which was causing issues

## Files Updated
- ResidencesListView.swift: Fixed residences list scrolling
- AllTasksView.swift: Fixed task columns horizontal scrolling
- ContractorsListView.swift: Fixed contractors list scrolling
- WarrantiesTabContent.swift: Fixed warranties list scrolling
- DocumentsTabContent.swift: Fixed documents list scrolling

## Technical Details
The .safeAreaInset modifier ensures ScrollViews properly account for the tab bar by:
- Automatically adjusting content insets for safe areas
- Allowing content to scroll fully above the tab bar
- Preventing content from being obscured

All tab views now provide smooth, unobstructed scrolling experience.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-12 16:41:12 -06:00
Trey t
ffb21aed62 Add full light and dark mode support for iOS and Android
This commit ensures both platforms properly support light and dark mode with automatic switching based on system settings.

## iOS Changes
- Updated DesignSystem.swift to use adaptive system colors
- Changed neutral colors to use UIKit system colors:
  - background: systemGroupedBackground
  - surface: secondarySystemGroupedBackground
  - text colors: label, secondaryLabel, tertiaryLabel
  - borders: separator, opaqueSeparator
- Colors now automatically adapt to light/dark mode
- Info.plist already configured to support both modes

## Android Changes
- Updated AndroidManifest.xml app theme
- Changed from Theme.Material.Light.NoActionBar to Theme.Material.NoActionBar
- Allows app to respect system dark mode settings
- Theme.kt already has complete light/dark color schemes
- MyCribTheme automatically switches based on system settings

## Testing
- iOS: Toggle Settings → Display & Brightness → Appearance
- Android: Toggle Settings → Display → Dark theme
- Both platforms automatically update colors

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-12 11:53:49 -06:00
Trey t
b888315e0c Complete iOS document form implementation and improve login error handling
This commit completes the DRY refactoring by implementing the missing document form functionality and enhancing user experience with better error messages.

## iOS Document Forms
- Implemented complete createDocument() method in DocumentViewModel:
  - Support for all warranty-specific fields (itemName, modelNumber, serialNumber, provider, etc.)
  - Multiple image uploads with JPEG compression
  - Proper UIImage to KotlinByteArray conversion
  - Async completion handlers
- Implemented updateDocument() method with full field support
- Completed DocumentFormView submitForm() implementation with proper API calls
- Fixed type conversion issues (Bool/KotlinBoolean, Int32/KotlinInt)
- Added proper error handling and user feedback

## iOS Login Error Handling
- Enhanced error messages to be user-friendly and concise
- Added specific messages for common HTTP error codes (400, 401, 403, 404, 500+)
- Implemented cleanErrorMessage() helper to remove technical jargon
- Added network-specific error handling (connection, timeout)
- Fixed MainActor isolation warnings with proper Task wrapping

## Code Quality
- Removed ~4,086 lines of duplicate code through form consolidation
- Added 429 lines of new shared form components
- Fixed Swift compiler performance issues
- Ensured both iOS and Android builds succeed

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-12 11:35:41 -06:00
Trey t
ec7c01e92d Add push notification support for Android and iOS
- Integrated Firebase Cloud Messaging (FCM) for Android
- Integrated Apple Push Notification Service (APNs) for iOS
- Created shared notification models and API client
- Added device registration and token management
- Added notification permission handling for Android
- Created PushNotificationManager for iOS with AppDelegate
- Added placeholder google-services.json (needs to be replaced with actual config)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 22:39:39 -06:00
Trey t
22949d18a7 Add image compression and improve document edit UI
- Add Swift ImageCompression helper to enforce 200KB limit on iOS
- Update iOS views to use compression for all image uploads
- Fix iOS EditDocumentView to show success only after all uploads complete
- Add AsyncImage thumbnails to Android EditDocumentScreen
- Fix Android success message visibility with delay before state reset
- Add proper error handling for failed image uploads
- Add resetUpdateState on error for consistency

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 21:23:22 -06:00
Trey t
7740438ea6 Add image upload functionality to iOS EditDocumentView
Added the ability to add and remove images when editing documents on iOS:

Backend API (DocumentApi.kt):
- Added uploadDocumentImage() method to upload images to existing documents
- Sends multipart/form-data with document ID, image bytes, and optional caption

iOS EditDocumentView:
- Added PhotosPicker for selecting images from library
- Added camera button (placeholder for future implementation)
- Added display of new images with thumbnails
- Added ability to remove new images before saving
- Updated saveDocument() to upload new images after updating metadata
- Shows total image count (existing + new, max 10)

Android formatFileSize fix:
- Changed from String.format() to simple division for KMM compatibility
- Rounds to 1 decimal place using integer arithmetic

Note: iOS has a known SwiftUI toolbar ambiguity issue that needs fixing.
The functionality is complete, just needs syntax adjustment to compile.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 20:36:03 -06:00
Trey t
415799b6d0 Refactor iOS and Android code to follow single responsibility principle
- iOS: Extracted views and helpers into separate files
  - Created Documents/Helpers/DocumentHelpers.swift for type/category helpers
  - Created Documents/Components/ with individual view files:
    - ImageViewerSheet.swift
    - WarrantyCard.swift
    - DocumentCard.swift
    - EmptyStateView.swift
    - WarrantiesTabContent.swift
    - DocumentsTabContent.swift
  - Cleaned up DocumentDetailView.swift and DocumentsWarrantiesView.swift

- Android: Extracted composables into organized component structure
  - Created ui/components/documents/ package with:
    - DocumentCard.kt (WarrantyCardContent, RegularDocumentCardContent, formatFileSize)
    - DocumentStates.kt (EmptyState, ErrorState)
    - DocumentsTabContent.kt
  - Reduced DocumentsScreen.kt from 506 lines to 211 lines
  - Added missing imports to DocumentDetailScreen.kt and EditDocumentScreen.kt

Net result: +770 insertions, -716 deletions across 15 files

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 14:39:33 -06:00
Trey t
611f7d853b Add document viewing, editing, and image deletion features
- Add DocumentDetailScreen and EditDocumentScreen for Compose (Android/Web)
- Add DocumentDetailView and EditDocumentView for iOS SwiftUI
- Add DocumentViewModelWrapper for iOS state management
- Implement document image deletion API integration
- Fix iOS navigation issues with edit button using hidden NavigationLink
- Add clickable warranties in iOS with NavigationLink
- Fix iOS build errors with proper type checking and state handling
- Add support for viewing and managing warranty-specific fields

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 14:00:01 -06:00
Trey t
e716c919f3 Add documents and warranties feature with image upload support
- Implement complete document management system for warranties, manuals, receipts, and other property documents
- Add DocumentsScreen with tabbed interface for warranties and documents
- Add AddDocumentScreen with comprehensive form including warranty-specific fields
- Integrate image upload functionality (camera + gallery, up to 5 images)
- Fix FAB visibility by adding bottom padding to account for navigation bar
- Fix content being cut off by bottom navigation bar (96dp padding)
- Add DocumentViewModel for state management with CRUD operations
- Add DocumentApi for backend communication with multipart image upload
- Add Document model with comprehensive field support
- Update navigation to include document routes
- Add iOS DocumentsWarrantiesView and AddDocumentView for cross-platform support

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 22:38:34 -06:00
Trey t
d3caffa792 Add contractor management and integrate with task completions
Features:
- Add full contractor CRUD functionality (Android & iOS)
- Add contractor selection to task completion dialog
- Display contractor info in completion cards
- Add ContractorSpecialty model and API integration
- Add contractors tab to bottom navigation
- Replace hardcoded specialty lists with API data
- Update lookup endpoints to return arrays instead of paginated responses

Changes:
- Add Contractor models (ContractorSummary, ContractorDetail, ContractorCreate/UpdateRequest)
- Add ContractorApi with endpoints for list, detail, create, update, delete, toggle favorite
- Add ContractorViewModel for state management
- Add ContractorsScreen and ContractorDetailScreen for Android
- Add AddContractorDialog with form validation
- Add Contractor views for iOS (list, detail, form)
- Update CompleteTaskDialog to include contractor selection
- Update CompletionCardView to show contractor name and phone
- Add contractor field to TaskCompletion model
- Update LookupsApi to return List<T> instead of paginated responses
- Update LookupsRepository and LookupsViewModel to handle array responses
- Update LookupsManager (iOS) to handle array responses for contractor specialties

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 19:39:41 -06:00
Trey t
e13448083c Modernize remaining views and badge components
Completed modernization of list views and badge components to match the new design system.

ResidencesListView:
- Modern background color from design system
- Improved loading state with text
- Property count display under header
- Modern toolbar icons with primary color
- Consistent spacing and padding

StatusBadge & PriorityBadge:
- Updated to use AppColors for semantic states
- Applied AppTypography for consistent font sizing
- Used AppSpacing for uniform padding
- Applied AppRadius for consistent corner radius
- Color-coded states (success, warning, error)
- Improved icon sizing and weight

All components now fully integrated with the design system:
- AppColors for all colors
- AppTypography for all text
- AppSpacing for all spacing
- AppRadius for all corner radii
- AppShadow for depth and elevation

The iOS app now has a completely modern, cohesive UI across all views.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 11:56:15 -06:00
Trey t
9305371276 Modernize task and residence card components
Applied modern design system to card components for consistent, sleek appearance.

TaskCard Improvements:
- Modern typography with design system fonts
- Pill-style metadata badges with icons
- Color-coded action buttons (success green, warning orange)
- Improved spacing and visual hierarchy
- Enhanced completion section with icon badge
- Redesigned secondary actions with better contrast

ResidenceCard Improvements:
- Gradient icon background for property type
- Star badge for primary residence with accent color
- Location icons for address fields
- Modernized task stats with color coding
- Consistent shadow and corner radius

Both cards now use:
- AppColors for consistent color palette
- AppTypography for font hierarchy
- AppSpacing for consistent spacing
- AppRadius for uniform corner radii
- AppShadow for depth and elevation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 11:53:39 -06:00
Trey t
8e82f43aba Fix SwiftUI type-checker timeout in LoginView
Broke up complex expressions into computed properties and subviews to help the Swift compiler type-check the view hierarchy.

Changes:
- Extracted isFormValid computed property
- Extracted loginButtonContent as separate view
- Extracted loginButtonBackground with @ViewBuilder
- Simplified button disabled condition

This resolves "The compiler is unable to type-check this expression in reasonable time" error.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 11:50:40 -06:00
Trey t
b7e0b6fefc Fix ambiguous Color init(hex:) extension
Removed duplicate Color.init(hex:) extension from AllTasksView.swift as it's now defined in DesignSystem.swift.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 11:48:22 -06:00
Trey t
4c9dc56e64 Implement modern design system for iOS app
Created a comprehensive, modern design system and applied it to key views for a sleek, contemporary look.

Design System Features:
- Modern color palette with blue primary and purple accent colors
- Semantic colors for success, warning, error, and info states
- Typography scale with SF Rounded for headlines
- Spacing and radius systems for consistent layout
- Shadow utilities for depth and elevation
- Reusable button and card styles

Modernized Views:
- LoginView: Card-based layout with gradient app icon, animated focus states, gradient buttons
- HomeScreenView: Personalized greeting, modern navigation cards
- OverviewCard: Stats grid with circular icon badges and dividers
- StatView: Circular backgrounds with modern typography
- HomeNavigationCard: Gradient icon backgrounds with clean hierarchy

Key Improvements:
- Replaced hardcoded colors with design system tokens
- Added gradient accents for visual interest
- Improved spacing and typography hierarchy
- Added subtle shadows for depth
- Implemented animated focus states
- Better disabled and loading states for buttons

Documentation:
- Added DESIGN_SYSTEM.md with comprehensive usage guide
- Documented colors, typography, spacing, and component patterns
- Included migration guide for updating remaining views

All views remain separate files as requested.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 11:45:45 -06:00
Trey t
77a118a6f7 Refactor iOS and Android views into separate files
Organized view components by extracting composables and views into separate files following single responsibility principle.

iOS Changes:
- Split MainTabView → extracted ProfileTabView
- Split CompleteTaskView → extracted ImageThumbnailView, CameraPickerView
- Split ManageUsersView → extracted ShareCodeCard, UserListItem
- Consolidated task action buttons into single TaskActionButtons.swift file
- Split HomeScreenView → extracted OverviewCard, StatView, HomeNavigationCard
- Split AllTasksView → extracted DynamicTaskColumnView, DynamicTaskCard
- Split ContentView → extracted ComposeView, CustomView

Android Changes:
- Split ResetPasswordScreen → extracted RequirementItem component
- Split TasksScreen → extracted TaskPill component
- Created TaskDisplayUtils for shared helper functions (getIconFromName, hexToColor)

All extracted components properly organized in:
- iOS: Subviews/Common, Subviews/Task, Subviews/Residence, Profile
- Android: ui/components/auth, ui/components/task, ui/utils

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 11:38:17 -06:00
Trey t
29b4c99f08 Add residence deletion functionality for iOS and Android
- Add delete residence button to iOS ResidenceDetailView (primary owners only)
- Add delete confirmation alert for iOS with destructive action
- Implement deleteResidence API call in iOS with navigation on success
- Add delete residence button to Android ResidenceDetailScreen (primary owners only)
- Add delete confirmation dialog for Android with error-colored button
- Add deleteResidenceState to ResidenceViewModel with StateFlow
- Implement deleteResidence() and resetDeleteResidenceState() in ViewModel
- Add LaunchedEffect to handle delete success (navigates back) and errors
- Display delete button with red/error styling on both platforms
- Restrict delete functionality to primary owners only

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 10:42:37 -06:00
Trey t
872a7df86f Add camera functionality for task completion photos
- Add camera picker interface to common ImagePicker.kt
- Implement camera capture for Android using ActivityResultContracts.TakePicture
- Implement camera capture for iOS using UIImagePickerController
- Add camera picker stubs for wasmJs, jsMain, and jvmMain platforms
- Update CompleteTaskDialog to show both "Take Photo" and "Choose from Library" buttons
- Add camera permissions to Android manifest (CAMERA permission, camera intent queries)
- Configure Android FileProvider for camera photo sharing
- Add camera and photo library usage descriptions to iOS Info.plist
- Update iOS CompleteTaskView with native camera picker support
- Fix cancel button in CompleteTaskView using @Environment(\.dismiss)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 10:25:37 -06:00
Trey t
131637e6f3 Add photo viewer for task completions on iOS and Android
- Add PhotoViewerDialog (Android) and PhotoViewerSheet (iOS) for viewing completion photos
- Add CompletionCardView (iOS) to display completion details with photo button
- Update AllTasksView (iOS) to show full completion details instead of just count
- Update TaskCard (Android) to use CompletionCard component
- Add Coil 3.0.4 image loading library for Android
- Configure ImageLoader in MainActivity with network, memory, and disk caching
- Add getMediaBaseUrl() to ApiClient for loading media files without /api path
- Fix photo viewer background color to match app theme

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 20:42:18 -06:00
Trey t
99228d03b5 Update login and password reset UI across iOS and Android
- Add email/username login support
  - Android: Update LoginScreen with email keyboard type
  - iOS: Update LoginView with email keyboard support

- Refactor iOS password reset screens to use native SwiftUI components
  - Convert ForgotPasswordView to use Form with Sections
  - Convert VerifyResetCodeView to use Form with Sections
  - Convert ResetPasswordView to use Form with Sections
  - Use Label components for error/success messages
  - Add navigation titles and improve iOS-native appearance

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 18:41:47 -06:00
Trey t
fdcc2a2e16 Add password reset feature for iOS and Android with deep link support
Implemented complete password reset flow with email verification and deep linking:

iOS (SwiftUI):
- PasswordResetViewModel: Manages 3-step flow (request, verify, reset) with deep link support
- ForgotPasswordView: Email entry screen with success/error states
- VerifyResetCodeView: 6-digit code verification with resend option
- ResetPasswordView: Password reset with live validation and strength indicators
- PasswordResetFlow: Container managing navigation between screens
- Deep link handling in iOSApp.swift for mycrib://reset-password?token=xxx
- Info.plist: Added CFBundleURLTypes for deep link scheme

Android (Compose):
- PasswordResetViewModel: StateFlow-based state management with coroutines
- ForgotPasswordScreen: Material3 email entry with auto-navigation
- VerifyResetCodeScreen: Code verification with Material3 design
- ResetPasswordScreen: Password reset with live validation checklist
- Deep link handling in MainActivity.kt and AndroidManifest.xml
- Token cleanup callback to prevent reusing expired deep link tokens
- Shared ViewModel scoping across all password reset screens
- Improved error handling for Django validation errors

Shared:
- Routes: Added ForgotPasswordRoute, VerifyResetCodeRoute, ResetPasswordRoute
- AuthApi: Enhanced resetPassword with Django validation error parsing
- User models: Added password reset request/response models

Security features:
- Deep link tokens expire after use
- Proper token validation on backend
- Session invalidation after password change
- Password strength requirements enforced

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 18:29:29 -06:00
Trey t
e6dc54017b Add PDF maintenance report generation feature for Android and iOS
- Add generateTasksReport API endpoint in ResidenceApi
- Implement report generation button in Android residence detail screen
- Add report generation state management in shared ResidenceViewModel
- Add report generation button to iOS residence detail view toolbar
- Implement iOS-specific report generation logic in ResidenceViewModel
- Display loading spinner and success/error alerts for report generation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 10:12:22 -06:00
Trey t
7dce211681 wip 2025-11-08 16:02:01 -06:00
Trey t
97eed0eee9 wip 2025-11-08 10:52:28 -06:00
Trey t
364f98a303 Fix logout, share code display, loading states, and multi-user support
iOS Logout Fix:
- Use @EnvironmentObject in MainTabView and ProfileTabView
- Pass loginViewModel from LoginView to MainTabView
- Handle logout by dismissing main tab when isAuthenticated becomes false
- Logout button now properly returns user to login screen

Share Code UX:
- Clear share code on ManageUsers screen open (iOS & Android)
- Remove auto-loading of share codes
- User must explicitly generate code each time
- Improves security with fresh codes

Loading State Improvements:
- iOS ResidenceDetailView shows loading immediately on navigation
- Android ResidenceDetailScreen enhanced with "Loading residence..." text
- Better user feedback during API calls

Multi-User Support:
- Add isPrimaryOwner and userCount to ResidenceWithTasks model
- Update iOS toResidences() extension to include new fields
- Sync with backend API changes for shared user access

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 10:51:51 -06:00