Commit Graph

105 Commits

Author SHA1 Message Date
Trey t
b5b3353529 Fix StoreKitManager SubscriptionApi initialization
Fixed Swift compilation error by explicitly passing httpClient parameter
to SubscriptionApi constructor. Kotlin default parameters are not
available when calling from Swift.

Changed from:
  SubscriptionApi()
To:
  SubscriptionApi(client: ApiClient.shared.httpClient)

iOS build now succeeds.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-24 14:15:46 -06:00
Trey t
0946842737 Fix SubscriptionApi compilation errors
Fixed unresolved references by matching the standard API client pattern:
- Changed from apiCall helper to try-catch pattern
- Use ApiClient.httpClient instead of direct httpClient reference
- Use ApiClient.getBaseUrl() instead of ApiConfig.baseUrl
- Added proper HttpClient parameter with default value
- Added proper error handling with response status checks
- Fixed verifyIOSReceipt to include transactionId parameter
- Fixed Android verification request format (use map instead of data class)

Now matches the pattern used by other API classes (ResidenceApi, TaskApi, etc.)

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-24 13:55:46 -06:00
Trey t
90c3858c90 Implement StoreKit 2 purchase flow with backend verification
Fully implemented StoreKit 2 in-app purchase system:

StoreKitManager.swift:
- Product loading from App Store with Product.products() API
- Complete purchase flow with result handling (success/cancelled/pending)
- Transaction verification using VerificationResult
- Backend receipt verification via SubscriptionApi
- Automatic transaction observation with Transaction.updates
- Current entitlements checking with Transaction.currentEntitlements
- Restore purchases with AppStore.sync()
- Transaction finishing to acknowledge purchases
- Subscription cache updates after successful verification
- Error handling with custom StoreKitError enum

UpgradePromptView.swift:
- Integration with StoreKitManager singleton
- Automatic product loading on view appear
- Display of subscription options with real pricing
- Product selection with loading states
- Purchase flow with try/catch error handling
- Success alert on purchase completion
- Error message display for failed purchases
- Restore purchases button
- SubscriptionProductButton component for product display
- Annual subscription highlighted with "Save 17%" badge
- Retry loading if products fail to fetch

Key features:
- Async/await pattern throughout
- MainActor dispatching for UI updates
- Transaction cryptographic verification
- Backend verification sends transaction ID
- Purchased product IDs tracking
- Transaction listener cleanup in deinit
- Products sorted by price (monthly first)

Ready for testing with Configuration.storekit in simulator.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-24 13:46:33 -06:00
Trey t
e838eecc64 Add StoreKit Configuration file for local in-app purchase testing
Created Configuration.storekit with two subscription products:
- MyCrib Pro Monthly ($4.99/month)
  * Product ID: com.example.mycrib.pro.monthly
  * 1 week free trial
  * Recurring monthly subscription
- MyCrib Pro Annual ($49.99/year)
  * Product ID: com.example.mycrib.pro.annual
  * 1 month free trial
  * Recurring annual subscription (17% savings)

This allows testing StoreKit 2 purchase flows in the iOS Simulator
without needing TestFlight or App Store Connect configuration.

Setup instructions:
1. Open iosApp.xcodeproj in Xcode
2. Add Configuration.storekit to project (drag into Project Navigator)
3. Edit scheme (Product > Scheme > Edit Scheme)
4. Go to Run > Options tab
5. Set StoreKit Configuration to "Configuration.storekit"
6. Run app in simulator to test purchases locally

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-24 13:43:24 -06:00
Trey t
bf2e572abf Phase 6: Add Android subscription UI with Jetpack Compose
Implemented Android subscription UI components:
- UpgradeFeatureScreen: Full-screen view for restricted features (contractors, documents)
  * Shows feature icon, name, and description
  * Displays "This feature is available with Pro" badge
  * Opens UpgradePromptDialog on button click
- UpgradePromptDialog: Modal dialog with upgrade options
  * Trigger-specific title and message from backend
  * Feature preview list with Material icons
  * "Upgrade to Pro" button with loading state
  * "Compare Free vs Pro" button
  * "Maybe Later" cancel option
- FeatureComparisonDialog: Full-screen comparison table
  * Free vs Pro feature comparison
  * Displays data from SubscriptionCache.featureBenefits
  * Default features if no data loaded
  * Upgrade button
- BillingManager: Google Play Billing Library placeholder
  * Singleton manager for in-app purchases
  * Product query placeholder
  * Purchase flow placeholder
  * Backend receipt verification placeholder
  * Restore purchases placeholder

All components follow Material3 design system with theme-aware colors and spacing constants.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-24 13:41:06 -06:00
Trey t
d12a2d315c Implement freemium subscription system - iOS UI (Phase 5)
iOS Subscription Features:
- Complete SwiftUI subscription UI components
- SubscriptionCache wrapper for accessing Kotlin state
- SubscriptionHelper wrapper for limit checking
- Upgrade prompt and feature comparison screens

Components Created:
1. SubscriptionCache.swift
   - Swift wrapper for Kotlin SubscriptionCache
   - ObservableObject for reactive UI updates
   - Manages currentSubscription state

2. SubscriptionHelper.swift
   - Swift wrapper for Kotlin SubscriptionHelper
   - canAddProperty(), canAddTask()
   - shouldShowUpgradePromptForContractors/Documents()

3. UpgradeFeatureView.swift
   - Full-screen view for restricted features
   - Shows when free users navigate to contractors/documents
   - Beautiful upgrade prompt with feature icon and description
   - "Upgrade to Pro" button

4. UpgradePromptView.swift
   - Modal upgrade dialog
   - Shows when limits are reached (property/task limits)
   - Displays trigger-specific messaging
   - Quick feature preview
   - Compare plans button

5. FeatureComparisonView.swift
   - Free vs Pro tier comparison table
   - Loads feature benefits from backend
   - Shows all feature differences
   - Upgrade button

6. StoreKitManager.swift
   - StoreKit 2 integration (placeholder)
   - Product loading and purchase methods
   - Receipt verification hooks
   - Transaction observer
   - NOTE: Requires App Store Connect configuration

Usage:
- Use UpgradeFeatureView for contractors/documents screens
- Use UpgradePromptView when limits are reached
- SubscriptionHelper checks limits before actions

Next: Integrate into contractors/documents screens

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-24 13:35:25 -06:00
Trey t
65476e2d66 Implement freemium subscription system - Shared Kotlin models (Phase 4)
Shared Kotlin Features:
- Complete subscription data models with kotlinx.serialization
- SubscriptionApi client for all backend endpoints
- SubscriptionCache for storing subscription state
- SubscriptionHelper utility for checking user limits

Models (Subscription.kt):
- SubscriptionStatus (tier, usage, limits, master toggle flag)
- UsageStats (current usage counts)
- TierLimits (tier-specific limits, null = unlimited)
- UpgradeTriggerData (configurable prompts)
- FeatureBenefit (Free vs Pro comparison)
- Promotion (seasonal campaigns)
- ReceiptVerificationRequest/Response
- PurchaseVerificationRequest/Response

API Client (SubscriptionApi.kt):
- getSubscriptionStatus() - fetch user subscription
- getUpgradeTriggers() - fetch upgrade prompts
- getFeatureBenefits() - fetch tier comparison
- getActivePromotions() - fetch active promotions
- verifyIOSReceipt() - verify Apple purchase
- verifyAndroidPurchase() - verify Google purchase

Cache (SubscriptionCache.kt):
- Stores currentSubscription in mutableState
- Stores upgradeTriggers, featureBenefits, promotions
- Reactive state for UI observation
- clear() method for logout

Helper (SubscriptionHelper.kt):
- canAddProperty() - check property limit
- canAddTask() - check task limit
- shouldShowUpgradePromptForContractors() - check if should show upgrade screen
- shouldShowUpgradePromptForDocuments() - check if should show upgrade screen
- Respects master toggle (limitationsEnabled)
- Returns UsageCheck(allowed, triggerKey)

Next: iOS StoreKit implementation (Phase 5)

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-24 13:30:53 -06:00
Trey t
b2c3fac3f9 Update warranty status to use backend calculation and add comprehensive tests
Client-Side Changes:
- Add WarrantyStatus data class to Document model for backend-calculated status
- Update WarrantyCard to display backend status (statusText, statusColor) with client fallback
- Fix document list refresh: call loadDocuments() after create/update operations

Testing:
- Add ComprehensiveDocumentWarrantyTests with 25+ XCUITest cases
- Test document creation, update, delete, image upload
- Test warranty-specific fields and property selection
- Test both general documents and warranties
- Includes helper methods for form interaction and cleanup

Other:
- Update ApiConfig and PushNotificationManager

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-24 13:09:55 -06:00
Trey t
15fac54f14 Add theme persistence and comprehensive Android design guidelines
This commit adds persistent theme storage and comprehensive documentation for Android development.

Theme Persistence:
- Created ThemeStorage with platform-specific implementations (SharedPreferences/UserDefaults)
- Updated ThemeManager.initialize() to load saved theme on app start
- Integrated ThemeStorage initialization in MainActivity and MainViewController
- Theme selection now persists across app restarts

Documentation (CLAUDE.md):
- Added comprehensive Android Design System section
- Documented all 11 themes and theme management
- Provided color system guidelines (use MaterialTheme.colorScheme)
- Documented spacing system (AppSpacing/AppRadius constants)
- Added standard component usage examples (StandardCard, FormTextField, etc.)
- Included screen patterns (Scaffold, pull-to-refresh, lists)
- Provided button and dialog patterns
- Listed key design principles for Android development

Build Status:
-  Android builds successfully
-  iOS builds successfully
-  Theme persistence works on both platforms

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-22 10:53:00 -06:00
Trey t
f1f71224aa Add Android theme system and fix package naming issues
This commit adds a comprehensive theming system to Android matching iOS, and fixes package declarations throughout the codebase to match directory structure.

Theme System Additions:
- Added 11 themes matching iOS: Default, Teal, Ocean, Forest, Sunset, Monochrome, Lavender, Crimson, Midnight, Desert, Mint
- Created ThemeColors.kt with exact iOS color values for light/dark modes
- Added ThemeManager.kt for dynamic theme switching
- Created Spacing.kt with standardized spacing constants (xs/sm/md/lg/xl)
- Added ThemePickerDialog.kt for theme selection UI
- Integrated theme switching in ProfileScreen.kt
- Updated App.kt to observe ThemeManager for reactive theming

Component Library:
- Added StandardCard.kt and CompactCard.kt for consistent card styling
- Added FormTextField.kt with error/helper text support
- Added FormSection.kt for grouping related form fields
- Added StandardEmptyState.kt for empty state UI

Package Migration:
- Fixed all package declarations to match directory structure (com.example.mycrib.*)
- Updated package declarations in commonMain, androidMain, and iosMain
- Fixed all import statements across entire codebase
- Ensures compilation on both Android and iOS platforms

iOS Theme Rename:
- Renamed "Default" theme to "Teal" in iOS
- Renamed "Bright" theme to "Default" in iOS to make vibrant colors the default

Build Status:
-  Android builds successfully
-  iOS builds successfully

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-22 10:44:54 -06:00
Trey t
e40aed31a7 Remove API pagination and fix contractor UI issues
- Remove pagination from all Django REST Framework endpoints
- Update Kotlin API clients to return direct lists instead of paginated responses
- Update iOS ViewModels to handle direct list responses
- Remove ContractorListResponse, DocumentListResponse, and PaginatedResponse models
- Fix contractor form specialty selector loading with improved DataCache access
- Fix contractor sheet presentation to use full screen (.presentationDetents([.large]))
- Improve UI test scrolling to handle lists of any size with smart end detection

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 22:56:43 -06:00
Trey t
93bd50ac3e fix test 2025-11-21 20:07:40 -06:00
Trey t
b260eaa821 Add 5 new themes to iOS app (Lavender, Crimson, Midnight, Desert, Mint)
Expanded the theming system from 5 to 10 total themes with comprehensive light/dark mode support. Each new theme includes unique color palettes optimized for visibility and WCAG contrast compliance.

New Themes:
- Lavender: Soft purple with pink accents
- Crimson: Bold red with warm highlights
- Midnight: Deep navy with sky blue tones
- Desert: Warm terracotta and sand palette
- Mint: Fresh green with turquoise accents

Technical Details:
- Created 45 new colorset files (9 colorsets × 5 themes)
- Each theme includes Primary, Secondary, Accent, 2 Backgrounds, and 4 Text colors
- Dark mode colors use 60-90% lightness for high visibility on dark backgrounds
- Consistent text colors across all themes for accessibility
- Updated ThemeManager.swift to include all 10 themes

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 09:07:54 -06:00
Trey t
050a486d6f Add comprehensive iOS design system documentation to CLAUDE.md
Document the 5-color semantic design system, including color palette reference,
usage guidelines, and complete patterns for creating new views, cards, buttons,
and UI components. Add critical styling rules for Form/List views with proper
background colors and row styling requirements.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 08:01:10 -06:00
Trey t
a2b81a244b Implement custom 5-color design system across entire iOS app
Apply consistent branding colors (BlueGreen, Cerulean, BrightAmber, PrimaryScarlet,
cream backgrounds) to all screens, components, buttons, icons, and text throughout
the app. Update all Form/List views with proper list row backgrounds to ensure
visual consistency with card-based layouts.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 07:58:01 -06:00
Trey t
a4ba6794d5 Update Xcode project configuration for UI test target
Updated project.pbxproj to properly configure the MyCribUITests target with
correct file references, build settings, and dependencies.

Changes:
- Added MyCribUITests target configuration
- Added all UI test files to test target membership
- Added AccessibilityIdentifiers.swift to main app target
- Added RootView.swift to main app target
- Removed references to deleted MyCribTests files
- Updated test scheme settings for UI tests

This enables running UI tests via Xcode or xcodebuild command line.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-20 23:07:37 -06:00
Trey t
5ba6e6c020 Remove obsolete test files and unused HomeScreenView
Cleaned up old MyCribTests directory containing outdated unit tests that
have been replaced by the comprehensive XCUITest suite in MyCribUITests.
Also removed unused HomeScreenView that was replaced by RootView.

Removed files:
- iosApp/MyCribTests/*.swift: Old unit tests (11 files)
- iosApp/iosApp/HomeScreenView.swift: Replaced by RootView

The new XCUITest suite provides better coverage with end-to-end UI tests
that validate actual user interactions rather than isolated unit tests.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-20 23:07:29 -06:00
Trey t
74a474007b Add project documentation and test setup guides
Added comprehensive documentation for the KMM project structure, build
commands, and UI testing setup/troubleshooting.

Documentation added:
- CLAUDE.md: Complete KMM project guide for Claude Code with architecture,
  build commands, common tasks, and development patterns
- iosApp/UI_TESTS_*.md: UI testing strategy, implementation guides, summaries
- iosApp/XCUITEST_*.md: XCUITest implementation and debugging guides
- iosApp/TEST_FAILURES_ANALYSIS.md: Analysis of common test failures
- iosApp/ACCESSIBILITY_IDENTIFIERS_FIX.md: Guide for fixing accessibility issues
- iosApp/FIX_TEST_TARGET*.md: Guides for fixing test target configuration
- iosApp/fix_test_target.sh: Script to automate test target setup

The CLAUDE.md serves as the primary documentation for working with this
repository, providing quick access to build commands, architecture overview,
and common development tasks for both iOS and Android platforms.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-20 23:07:14 -06:00
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
b9c82ffc37 Update client models to handle numeric decimals from optimized API
Model type updates:
- Change decimal cost fields from String to Double for better type safety
- actualCost: String? → Double? (TaskCompletion, TaskCompletionCreateRequest)
- estimatedCost: String? → Double? (CustomTask, TaskCreateRequest, TaskDetail)
- purchasePrice: String? → Double? (Residence, ResidenceCreateRequest)

TaskDetail model fixes:
- Add missing residenceName, createdBy, createdByUsername fields
- Add missing intervalDays field to match backend response
- Remove actualCost and notes fields (not in backend TaskDetailSerializer)
- Ensure 100% compatibility with Django API TaskDetailSerializer

UI input/output conversions:
- EditTaskScreen: Convert Double to String for display, String to Double for API
- AddTaskDialog: Convert String input to Double for API requests
- CompleteTaskDialog: Convert String input to Double for API requests
- App.kt: Handle type conversions in navigation route parameters

Display improvements:
- TaskCard: Update preview data to use numeric literals (150.00 vs "150.00")
- Cost display already handles Double correctly with string interpolation

Benefits:
- Type-safe numeric handling throughout the app
- Smaller JSON payloads (numbers vs quoted strings)
- Better performance with direct numeric deserialization
- Aligns with REST API best practices
- 100% backend compatibility verified

Testing:
- All models now match backend serializer field types exactly
- Build successful with no errors
- Ready for integration with optimized Django API

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-15 22:55:50 -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
7f6f77d95a fix contractor upload with image 2025-11-15 01:34:31 -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
225bdbc2bc Implement error handling with ApiResultHandler on key screens
Applied the new error handling utilities to ResidencesScreen and
ResidenceDetailScreen, replacing inline error displays with popup dialogs.

Changes:
- ResidencesScreen: Replaced inline error UI with ApiResultHandler
  - Shows error dialog popup instead of error message in center of screen
  - Maintains all functionality while improving UX

- ResidenceDetailScreen: Comprehensive error handling implementation
  - Main residence loading uses ApiResultHandler with custom loading content
  - Generate report operation uses HandleErrors() extension
  - Delete residence operation uses HandleErrors() extension
  - All operations now show retry/cancel dialogs on error

Benefits:
- Consistent error handling UX across screens
- Users can retry failed operations without navigating away
- Cleaner code with less boilerplate error handling
- Error dialogs are non-blocking and dismissible

These screens now demonstrate the pattern for implementing error handling
across the rest of the app using the error handling utilities.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-14 14:33: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
c189971906 Add order_id field to lookup models
Added order_id field to TaskCategory, TaskPriority, and TaskStatus models
to support custom ordering of lookup values from the API.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-14 10:31:04 -06:00
Trey t
e87c406695 Restore completion_date field to TaskCompletionCreateRequest
The completion_date should be provided by the client, not auto-generated
by the backend. Backend has been updated to accept this field.

This allows clients to specify when the task was actually completed,
which may be different from when the completion record is created.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-14 10:01:36 -06:00
Trey t
843833a6bc Fix TaskCompletionCreateRequest to remove completion_date field
The completion_date field is automatically set by the backend (auto_now_add)
and should not be sent in the create request. Removed this field from
TaskCompletionCreateRequest to match the API expectations.

Backend TaskCompletion model sets completion_date automatically, so
clients should not provide it when creating a completion.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-14 09:56:35 -06:00
Trey t
07dfd55507 Fix CustomTask model to match API response structure
Updated CustomTask to use nested objects for category, frequency,
priority, and status instead of strings to match the API's actual
response format after recent serializer changes.

Changes:
- category: String → TaskCategory?
- Added frequency: TaskFrequency
- priority: String → TaskPriority
- status: String? → TaskStatus?
- Added next_scheduled_date field
- Added completion_count field

This fixes the JSON parsing error when creating/updating tasks via
the iOS and Android apps, which was caused by the API returning
nested objects like {"id": 21, "name": "Flooring"} but the model
expecting simple strings.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-14 09:54:04 -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