Commit Graph

153 Commits

Author SHA1 Message Date
Trey t
2965ec4031 Add actionable push notifications for iOS and Android
iOS:
- Add notification categories with action buttons (complete, view, cancel, etc.)
- Handle notification actions in AppDelegate with API calls
- Add navigation to specific task from notification tap
- Register UNNotificationCategory for each task state

Android:
- Add NotificationActionReceiver BroadcastReceiver for handling actions
- Update MyFirebaseMessagingService to show action buttons
- Add deep link handling in MainActivity for task navigation
- Register receiver in AndroidManifest.xml

Shared:
- Add navigateToTaskId parameter to App for cross-platform navigation
- Add notification observers in MainTabView/AllTasksView for refresh

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 14:23:25 -06:00
Trey t
771f5d2bd3 Add task template suggestions for quick task creation
- Add TaskTemplate model with category grouping support
- Add TaskTemplateApi for fetching templates from backend
- Add TaskSuggestionDropdown component for Android task form
- Add TaskTemplatesBrowserSheet for browsing all templates
- Add TaskSuggestionsView and TaskTemplatesBrowserView for iOS
- Update DataManager to cache task templates
- Update APILayer with template fetch and search methods
- Update TaskFormView (iOS) with template suggestions
- Update AddTaskDialog (Android) with template suggestions
- Update onboarding task view to use templates

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 09:06:58 -06:00
Trey t
fd8f6d612c add support button, icon view 2025-12-04 23:59:39 -06:00
Trey t
70d46da14a Add smart device token caching for push notification registration
Cache device token in UserDefaults and only register with backend when
token changes. Also registers when app returns from background if token
differs from cached value, reducing unnecessary API calls.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 20:18:08 -06:00
Trey t
22bf109cf7 Add email notification preference for task completion
- Add emailTaskCompleted field to NotificationPreference model
- Add email preference toggle to notification settings UI (iOS & Android)
- Add localized strings for email notifications section
- Update ViewModel to support email preference updates

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 20:04:42 -06:00
Trey t
7c0238bdf8 Fix residence property values using KotlinInt/KotlinDouble incorrectly
When Kotlin types are bridged to Swift, Int? becomes KotlinInt? and
Double? becomes KotlinDouble?. These wrapper types don't work correctly
with String interpolation or format specifiers - need to use .intValue
and .doubleValue to get native Swift types.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 19:03:58 -06:00
Trey t
c0d693e4dd Fix task edit button not opening edit sheet in ResidenceDetailView
The onEditTask callback was setting selectedTaskForEdit but never
setting showEditTask to true, so the sheet never appeared. Added
showEditTask binding to TasksSectionContainer and set it when editing.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 19:01:39 -06:00
Trey t
fff1032c29 Add onboarding UI tests and improve app data management
- Add Suite0_OnboardingTests with fresh install and login test flows
- Add accessibility identifiers to onboarding views for UI testing
- Remove deprecated DataCache in favor of unified DataManager
- Update API layer to support public upgrade-triggers endpoint
- Improve onboarding first task view with better date handling
- Update various views with accessibility identifiers for testing
- Fix subscription feature comparison view layout
- Update document detail view improvements

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 15:55:34 -06:00
Trey t
43f5b9514f Add Android onboarding flow matching iOS implementation
Implement complete onboarding experience for Android with the following screens:
- Welcome screen with "Start Fresh" and "Join Existing Home" options
- Value props carousel showcasing app features (Tasks, Documents, Contractors, Family)
- Residence naming screen for new property setup
- Account creation with email registration (no Apple Sign In on Android)
- Email verification with 6-digit code
- Join residence screen for share code entry
- First task selection with 6 category templates
- Subscription upsell with monthly/yearly plans

Key implementation details:
- OnboardingViewModel manages all state and API integration
- AnimatedContent provides smooth screen transitions
- HorizontalPager for feature carousel
- Onboarding completion persisted in DataManager
- New users start at onboarding, returning users go to login

Files added:
- OnboardingViewModel.kt
- OnboardingScreen.kt (coordinator)
- OnboardingWelcomeContent.kt
- OnboardingValuePropsContent.kt
- OnboardingNameResidenceContent.kt
- OnboardingCreateAccountContent.kt
- OnboardingVerifyEmailContent.kt
- OnboardingJoinResidenceContent.kt
- OnboardingFirstTaskContent.kt
- OnboardingSubscriptionContent.kt

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 17:21:44 -06:00
Trey t
63a54434ed Add 1-hour cache timeout and fix pull-to-refresh across iOS
- Add configurable cache timeout (CACHE_TIMEOUT_MS) to DataManager
- Fix cache to work with empty results (contractors, documents, residences)
- Change Documents/Warranties view to use client-side filtering for cache efficiency
- Add pull-to-refresh support for empty state views in ListAsyncContentView
- Fix ContractorsListView to pass forceRefresh parameter correctly
- Fix TaskViewModel loading spinner not stopping after refresh completes
- Remove duplicate cache checks in iOS ViewModels, delegate to Kotlin APILayer

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 09:50:57 -06:00
Trey t
cf0cd1cda2 Add unified DataManager as single source of truth for all app data
- Create DataManager.kt with StateFlows for all cached data:
  - Authentication (token, user)
  - Residences, tasks, documents, contractors
  - Subscription status and upgrade triggers
  - All lookup data (residence types, task categories, etc.)
  - Theme preferences and state metadata

- Add PersistenceManager with platform-specific implementations:
  - Android: SharedPreferences
  - iOS: NSUserDefaults
  - JVM: Properties file
  - WasmJS: localStorage

- Migrate APILayer to update DataManager on every API response
- Update Kotlin ViewModels to use DataManager for token access
- Deprecate LookupsRepository (delegates to DataManager)
- Create iOS DataManagerObservable Swift wrapper for SwiftUI
- Update iOS auth flow to use DataManager.isAuthenticated()

Data flow: User Action → API Call → DataManager Updated → All Screens React

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 00:21:24 -06:00
Trey t
b79fda8aee Centralize kanban state in TaskViewModel to eliminate duplicate code
Move tasksResponse state and updateTaskInKanban logic from individual views
into TaskViewModel. Both AllTasksView and ResidenceDetailView now delegate
to the shared ViewModel, reducing code duplication and ensuring consistent
task state management across the app.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 22:07:52 -06:00
Trey t
00e303c3be Update task completion to use local kanban state update
- Add updatedTask field to TaskCompletionResponse model from API
- Modify CompleteTaskView callback to pass back the updated task
- Add updateTaskInKanban() function to AllTasksView and ResidenceDetailView
- Move completed tasks to correct kanban column without additional API call
- Remove debug print statements from ResidenceDetailView

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 20:50:25 -06:00
Trey t
0ddd542080 Add AuthenticatedImage components for secure media access
iOS:
- Add AuthenticatedImage.swift component with auth header support
- Update PhotoViewerSheet, ImageViewerSheet, DocumentDetailView, DocumentFormView
- Use TokenStorage for auth and ApiClient.getMediaBaseUrl() for URLs
- In-memory image caching for performance

Android/KMM:
- Add AuthenticatedImage.kt Compose component using Coil3 httpHeaders
- Add mediaUrl field to TaskCompletionImage and DocumentImage models
- Update PhotoViewerDialog, DocumentDetailScreen, DocumentFormScreen
- Use authenticated media URLs instead of public image URLs

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 19:47:48 -06:00
Trey t
b7dc8f3a29 Fix stat label truncation on smaller screens
- Add fixedSize to stat label to allow text wrapping
- Expand stat box to full width for better text flow

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 13:35:32 -06:00
Trey t
b19162a8ac Adjust feature card layout to show full description text
- Reduce icon and glow sizes for more content space
- Use smaller font sizes for title, subtitle, and description
- Add fixedSize modifier to prevent description truncation
- Use minLength spacers instead of flexible spacers

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 13:26:41 -06:00
Trey t
2f89f36f86 Improve onboarding statistics for better relevance and impact
- Update stats to include cost values for urgency
- Ensure each stat relates directly to its feature's value proposition
- Replace HVAC-specific stat with broader home repair data
- Update documentation with reorganized sources and additional reference stats

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 13:21:15 -06:00
Trey t
4446fc3379 Update onboarding statistics with verified sources
- Replace fabricated stats with real data from industry surveys
- 60% delay maintenance (FinanceBuzz 2024)
- 65% repairs preventable (Hippo Insurance 2023)
- 75% claim denials from coverage misunderstanding (This Old House)
- 37% more tasks with digital tools (Journal of Family Psychology 2023)
- Add docs/ONBOARDING_STATISTICS_SOURCES.md with full citations

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 13:13:08 -06:00
Trey t
374c0d1e9c added new strings 2025-12-02 13:08:04 -06:00
Trey t
d4b5da71b7 Redesign iOS onboarding UI with improved visuals and engagement
- Reorder flow: Welcome → Features → Name Residence → Account → Tasks → Upsell
- Features screen: 4 animated cards with stats, gradient icons, playful copy
- Name residence: Add name suggestions, gradient borders, encouraging text
- Task templates: Multi-select with 24 tasks in 6 categories, accordion UI
- Subscription upsell: Plan selection, animated crown, social proof, benefits

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 11:49:55 -06:00
Trey t
0652908c20 Add iOS onboarding flow with residence creation and task templates
- Add complete onboarding flow with 7 screens: Welcome, Name Residence,
  Value Props, Create Account, Verify Email, First Task, Subscription
- Auto-create residence after email verification for "Start Fresh" users
- Add predefined task templates (HVAC, Smoke Detectors, Lawn Care, Leaks)
  that create real tasks with today as due date
- Add returning user login button on welcome screen
- Update RootView to prioritize onboarding flow for first-time users
- Use app icon asset instead of house.fill SF Symbol
- Smooth slide transitions with fade-out for back navigation

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 11:00:51 -06:00
Trey t
db65fe125b Add 5 new language translations: Chinese, Japanese, Korean, Italian, Dutch
Expand localization support across all platforms with professional translations:
- KMM: Added strings.xml for zh, ja, ko, it, nl (473 strings each)
- iOS: Updated Localizable.xcstrings with ~1,500 new translation entries

App now supports 10 languages: en, es, fr, de, pt, zh, ja, ko, it, nl

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 08:43:41 -06:00
Trey t
c726320c1e Add comprehensive i18n localization for KMM and iOS
KMM (Android/Shared):
- Add strings.xml with 200+ localized strings
- Add translation files for es, fr, de, pt languages
- Update all screens to use stringResource() for i18n
- Add Accept-Language header to API client for all platforms

iOS:
- Add L10n.swift helper with type-safe string accessors
- Add Localizable.xcstrings with translations for all 5 languages
- Update all SwiftUI views to use L10n.* for localized strings
- Localize Auth, Residence, Task, Contractor, Document, and Profile views

Supported languages: English, Spanish, French, German, Portuguese

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 02:02:00 -06:00
Trey t
e62e7d4371 Add contractors section to residence detail and fix search filtering
- Add GET /contractors/by-residence/:id endpoint integration
- Display contractors on residence detail screen (iOS & Android)
- Fix contractor search/filter to use client-side filtering
- Backend doesn't support search query params, so filter locally

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-01 20:38:57 -06:00
Trey t
fe2e8275f5 Fix iOS widget date formatting for RFC3339 dates
- Add centralized formatWidgetDate() helper that handles both yyyy-MM-dd and ISO8601 formats
- Update widget date display to show "Today", "in X days", or "X days ago"
- Fix isTaskOverdue() to parse ISO8601 dates from Go API
- Remove duplicate date formatting functions from widget views
- Switch API environment back to DEV

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-01 18:09:16 -06:00
Trey t
c07821711f Add centralized DateUtils and enhance contractor detail views
- Add DateUtils.kt for shared Kotlin date formatting with formatDate,
  formatDateMedium, formatDateTime, formatRelativeDate, and isOverdue
- Add DateUtils.swift for iOS with matching date formatting functions
- Enhance ContractorDetailScreen (Android) with quick action buttons
  (call, email, website, directions), clickable contact rows, residence
  association, statistics section, and metadata
- Enhance ContractorDetailView (iOS) with same features, refactored into
  smaller @ViewBuilder functions to fix Swift compiler type-check timeout
- Fix empty string handling in iOS - check !isEmpty in addition to != nil
  for optional fields like phone, email, website, address
- Update various task and document views to use centralized DateUtils

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-01 14:08:45 -06:00
Trey t
94781f4c48 update profile and UI tweaks 2025-11-30 12:37:15 -06:00
Trey t
b0838d85df Add residence picker to contractor create/edit screens
Kotlin/KMM:
- Update Contractor model with optional residenceId and specialties array
- Rename averageRating to rating, update address field names
- Add ContractorMinimal model for task references
- Add residence picker and multi-select specialty chips to AddContractorDialog
- Fix ContractorsScreen and ContractorDetailScreen field references

iOS:
- Rewrite ContractorFormSheet with residence and specialty pickers
- Update ContractorDetailView with FlowLayout for specialties
- Add FlowLayout component for wrapping badge layouts
- Fix ContractorCard and CompleteTaskView field references
- Update ContractorFormState with residence/specialty selection

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 18:42:18 -06:00
Trey t
c748f792d0 Add notification preferences UI and subscription verification on launch
- Add NotificationPreferencesScreen (Android) and NotificationPreferencesView (iOS)
- Add NotificationPreferencesViewModel for shared business logic
- Wire up notification preferences from ProfileScreen on both platforms
- Add subscription verification on app launch for iOS (StoreKit) and Android (Google Play Billing)
- Update SubscriptionApi to match Go backend endpoints (/subscription/purchase/)
- Update StoreKit Configuration with correct product IDs and pricing ($2.99/month, $27.99/year)
- Update Android placeholder prices to match App Store pricing
- Fix NotificationPreference model to match Go backend schema

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 14:01:35 -06:00
Trey t
5a1a87fe8d Add Sign in with Apple for iOS
Kotlin Shared Layer:
- Add AppleSignInRequest and AppleSignInResponse models
- Add appleSignIn method to AuthApi and APILayer
- Add appleSignInState and appleSignIn() to AuthViewModel

iOS App:
- Create AppleSignInManager for AuthenticationServices integration
- Create AppleSignInViewModel to coordinate Apple auth flow
- Update LoginView with "Sign in with Apple" button
- Add Sign in with Apple entitlement
- Add accessibility identifier for UI testing

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 01:17:38 -06:00
Trey t
4b905ad5fe Add dismissKeyboard() calls to UI tests to fix keyboard blocking issues
- Add dismissKeyboard() helper that types newline to dismiss keyboard
- Call dismissKeyboard() before every tap() in RegistrationTests to prevent
  keyboard from covering buttons
- Update fillRegistrationForm to dismiss keyboard after form completion
- Fixes testSuccessfulRegistrationAndVerification test failure

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 00:34:18 -06:00
Trey t
a0c5223161 Fix CaseraUITests target configuration
Change TEST_TARGET_NAME from iosApp to Casera to fix
"UITargetAppPath should be provided" error after rebranding.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 22:01:06 -06:00
Trey t
19a76d1c8e wip 2025-11-28 21:27:45 -06:00
Trey t
daa70bbe20 Fix build issues after Casera rebranding
- Update google-services.json package name to com.example.casera
- Fix Xcode project paths from MyCrib/ to Casera/
- Update app display name and usage descriptions

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 21:19:22 -06:00
Trey t
c6eef720ed Rebrand from MyCrib to Casera
- Rename Kotlin package from com.example.mycrib to com.example.casera
- Update Android app name, namespace, and application ID
- Update iOS bundle identifiers and project settings
- Rename iOS directories (MyCribTests -> CaseraTests, etc.)
- Update deep link schemes from mycrib:// to casera://
- Update app group identifiers
- Update subscription product IDs
- Update all UI strings and branding

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 21:10:38 -06:00
Trey t
8dbc816a33 Update UI test to use Performance property name
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 21:01:23 -06:00
Trey t
fa1fab0e4a Fix Document API field names to match Go backend
- Change residence to residence_id with @SerialName annotation
- Change contractor to contractor_id with @SerialName annotation
- Update DocumentApi.kt to use correct field names in form data and JSON requests
- Fixes iOS document creation failing with "missing residence_id" error

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 21:00:42 -06:00
Trey t
2baf5484e0 Add task completion history feature and UI improvements
- Add CompletionHistorySheet for viewing task completion history (Android & iOS)
- Update TaskCard and DynamicTaskCard with completion history access
- Add getTaskCompletions API endpoint to TaskApi and APILayer
- Update models (CustomTask, Document, TaskCompletion, User) for Go API alignment
- Improve TaskKanbanView with completion history integration
- Update iOS TaskViewModel with completion history loading

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 12:01:56 -06:00
Trey t
60c824447d Update Kotlin models and iOS Swift to align with new Go API format
- Update all Kotlin API models to match Go API response structures
- Fix Swift type aliases (TaskDetail→TaskResponse, Residence→ResidenceResponse, etc.)
- Update TaskCompletionCreateRequest to simplified Go API format (taskId, notes, actualCost, photoUrl)
- Fix optional handling for frequency, priority, category, status in task models
- Replace isPrimaryOwner with ownerId comparison against current user
- Update ResidenceUsersResponse to use owner.id instead of ownerId
- Fix non-optional String fields to use isEmpty checks instead of optional binding
- Add type aliases for backwards compatibility in Kotlin models

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-27 11:03:00 -06:00
Trey t
d3e77326aa Fix iOS widget to use App Group shared data and add large widget view
- Create WidgetDataManager to write task data as JSON to App Group shared container
- Update widget CacheManager to read from App Group file instead of UserDefaults
- Add LargeWidgetView for .systemLarge widget family showing 5-6 tasks
- Add widget data save in AllTasksView after tasks load successfully
- Clear widget cache on logout in AuthenticationManager
- Add residenceName and isOverdue fields to widget task model

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-25 20:41:02 -06:00
Trey t
a0b038403c Fix post-registration navigation and add comprehensive registration UI tests
- Fix RegisterView to call AuthenticationManager.login() after email verification
  so user is properly transitioned to home screen instead of returning to login
- Fix ResidencesListView to load data when authentication state becomes true,
  ensuring residences load after registration/login
- Add accessibility identifier to verification code field for UI testing
- Add NSAppTransportSecurity exceptions for localhost/127.0.0.1 for local dev
- Add comprehensive XCUITest suite for registration flow including:
  - Form validation tests (empty fields, invalid email, mismatched passwords)
  - Full registration and verification flow test
  - Logout from verification screen test
  - Helper scripts for test user cleanup

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-25 19:56:30 -06:00
Trey t
f433dca1bb Add iOS Password AutoFill support for login and registration
Enable system-level password generation and iCloud Keychain integration:

RegisterView:
- Add .textContentType(.username) to username field
- Add .textContentType(.emailAddress) to email field
- Add .textContentType(.newPassword) to password fields for Strong Password
- iOS will suggest secure passwords and offer to save to Keychain

LoginView:
- Add .textContentType(.username) to email/username field
- Add .textContentType(.password) to password fields
- Enables AutoFill from saved Keychain credentials

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-25 18:32:00 -06:00
Trey t
7b0a0e5d85 Implement Android subscription system with freemium limitations
Major subscription system implementation for Android:

BillingManager (Android):
- Full Google Play Billing Library integration
- Product loading, purchase flow, and acknowledgment
- Backend verification via APILayer.verifyAndroidPurchase()
- Purchase restoration for returning users
- Error handling and connection state management

SubscriptionHelper (Shared):
- New limit checking methods: isResidencesBlocked(), isTasksBlocked(),
  isContractorsBlocked(), isDocumentsBlocked()
- Add permission checks: canAddProperty(), canAddTask(),
  canAddContractor(), canAddDocument()
- Enforces freemium rules based on backend limitationsEnabled flag

Screen Updates:
- ContractorsScreen: Show upgrade prompt when contractors limit=0
- DocumentsScreen: Show upgrade prompt when documents limit=0
- ResidencesScreen: Show upgrade prompt when properties limit reached
- ResidenceDetailScreen: Show upgrade prompt when tasks limit reached

UpgradeFeatureScreen:
- Enhanced with feature benefits comparison
- Dynamic content from backend upgrade triggers
- Platform-specific purchase buttons

Additional changes:
- DataCache: Added O(1) lookup maps for ID resolution
- New minimal models (TaskMinimal, ContractorMinimal, ResidenceMinimal)
- TaskApi: Added archive/unarchive endpoints
- Added Google Billing Library dependency
- iOS SubscriptionCache and UpgradePromptView updates

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-25 11:23:53 -06:00
Trey t
f9e522f734 Fix Android subscription limitations not working
Load subscription status and upgrade triggers during Android app
initialization in LookupsRepository.initialize(). Previously, only
iOS was loading this data via APILayer.initializeLookups().

Without subscription data, SubscriptionHelper couldn't enforce limits
because SubscriptionCache.currentSubscription was always null.

Changes:
- Add SubscriptionApi calls to load subscription status and upgrade
  triggers in parallel with other lookup data
- Clear SubscriptionCache on logout in clear() method
- Add debug logging for subscription loading

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-25 11:22:32 -06:00
Trey t
f3fbee1e27 Show full paywall inline and disable add button when upgrade required
- Update UpgradeFeatureView to display complete paywall experience
  (promo content, subscription products, purchase flow) instead of
  simple teaser
- Disable add button in Documents view when upgrade screen is showing
- Disable add button in Contractors view when upgrade screen is showing
- Gray out disabled add buttons to indicate non-interactive state

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-24 22:05:59 -06:00
Trey t
67e0057bfa Refactor iOS codebase with SOLID/DRY patterns
Core Infrastructure:
- Add StateFlowObserver for reusable Kotlin StateFlow observation
- Add ValidationRules for centralized form validation
- Add ActionState enum for tracking async operations
- Add KotlinTypeExtensions with .asKotlin helpers
- Add Dependencies factory for dependency injection
- Add ViewState, FormField, and FormState for view layer
- Add LoadingOverlay and AsyncContentView components
- Add form state containers (Task, Residence, Contractor, Document)

ViewModel Updates (9 files):
- Refactor all ViewModels to use StateFlowObserver pattern
- Add optional DI support via initializer parameters
- Reduce boilerplate by ~330 lines across ViewModels

View Updates (4 files):
- Update ResidencesListView to use ListAsyncContentView
- Update ContractorsListView to use ListAsyncContentView
- Update WarrantiesTabContent to use ListAsyncContentView
- Update DocumentsTabContent to use ListAsyncContentView

Net reduction: -332 lines (1007 removed, 675 added)

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-24 21:15:11 -06:00
Trey t
ce1ca0f0ce Optimize subscription tier management and empty state logic
Changes:
- Make currentTier a computed property from StoreKit instead of stored value
- Initialize StoreKit at app launch and refresh on foreground for ready subscription status
- Fix empty state logic: show empty state when limit > 0, upgrade prompt when limit = 0
- Add subscription status display in Profile screen (iOS/Android)
- Add upgrade prompts to Residences and Tasks screens for free tier users
- Improve SubscriptionHelper with better tier checking logic

iOS:
- SubscriptionCache: currentTier now computed from StoreKit.purchasedProductIDs
- StoreKitManager: add refreshSubscriptionStatus() method
- AppDelegate: initialize StoreKit at launch and refresh on app active
- ContractorsListView: use shouldShowUpgradePrompt(currentCount:limitKey:)
- WarrantiesTabContent/DocumentsTabContent: same empty state fix
- ProfileTabView: display current tier and limitations status
- ResidencesListView/ResidenceDetailView: add upgrade prompts for free users
- AllTasksView: add upgrade prompt for free users

Android:
- ContractorsScreen/DocumentsScreen: fix empty state logic
- ProfileScreen: display subscription status and limits
- ResidencesScreen/ResidenceDetailScreen: add upgrade prompts
- UpgradeFeatureScreen: improve UI layout

Shared:
- APILayer: add getSubscriptionStatus() method
- SubscriptionHelper: add hasAccessToFeature() utility
- Remove duplicate subscription checking logic

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-24 18:59:09 -06:00
Trey t
d92a4fd4f1 Fix iOS compilation errors in StoreKitManager
Fixed all compilation errors:

1. Changed from switch/case to if-let pattern for Kotlin ApiResult types
   - ApiResult doesn't have .success/.failure/.loading/.idle cases in Swift
   - Used "as? ApiResultSuccess" and "as? ApiResultError" pattern instead

2. Fixed SubscriptionStatus name conflict
   - Fully qualified as ComposeApp.SubscriptionStatus
   - Avoids conflict with StoreKit's Product.SubscriptionInfo.Status

3. Fixed VerificationResponse handling
   - VerificationResponse only has success, tier, error fields
   - After verification, fetch full subscription status via getSubscriptionStatus
   - Properly unwrap optional response.data

4. Added try-catch for Kotlin suspend functions
   - Kotlin suspend functions throw in Swift
   - Wrapped await calls in do-try-catch blocks

5. Removed unused getReceiptData function
   - Inlined the logic directly in verifyTransactionWithBackend

iOS build now succeeds with no errors.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-24 14:20:22 -06:00
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