Commit Graph

38 Commits

Author SHA1 Message Date
Trey t
42eda6a8c8 Add shared utilities and refactor iOS codebase for DRY compliance
Create centralized shared utilities in iosApp/Shared/:
- Extensions: ViewExtensions, DateExtensions, StringExtensions, DoubleExtensions
- Components: FormComponents, SharedEmptyStateView, ButtonStyles
- Modifiers: CardModifiers
- Utilities: ValidationHelpers, ErrorMessages

Migrate existing views to use shared utilities:
- LoginView: Use IconTextField, FieldLabel, FieldError, OrganicPrimaryButton
- TaskFormView: Use .loadingOverlay() modifier
- TaskCard/DynamicTaskCard: Use .toFormattedDate() extension
- CompletionCardView: Use .toCurrency() (with KotlinDouble support)
- ResidenceDetailView: Use OrganicEmptyState, StandardLoadingView
- Profile views: Use .standardFormStyle(), .sectionBackground()
- Form views: Use consistent form styling modifiers

Benefits:
- Eliminates ~180 lines of duplicate code
- Consistent styling across all forms and components
- KotlinDouble extensions for seamless KMM interop
- Single source of truth for UI patterns

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 13:19:59 -06:00
Trey t
3598a8d57f Add Warm Organic design system to iOS app
- Add OrganicDesign.swift with reusable components:
  - WarmGradientBackground, OrganicBlobShape, GrainTexture
  - OrganicDivider, OrganicCardBackground, NaturalShadow modifier
  - OrganicSpacing constants (cozy, comfortable, spacious, airy)

- Update high-priority screens with organic styling:
  - LoginView: hero glow, organic card background, rounded fonts
  - ResidenceDetailView, ResidencesListView: warm backgrounds
  - ResidenceCard, SummaryCard, PropertyHeaderCard: organic cards
  - TaskCard: metadata pills, secondary buttons, card background
  - TaskFormView: organic loading overlay, templates button
  - CompletionHistorySheet: organic loading/error/empty states
  - ProfileView, NotificationPreferencesView, ThemeSelectionView

- Update task badges with icons and capsule styling:
  - PriorityBadge: priority-specific icons
  - StatusBadge: status-specific icons

- Fix TaskCard isOverdue error using DateUtils.isOverdue()

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 20:15:32 -06:00
Trey t
b150c20e4b Reorganize share UI with Easy Share on top
Move Easy Share (.casera file) section above Share Code section in the
invite users dialog. Both platforms now have consistent UI with both
buttons using the same filled button style.

iOS changes:
- Move share functionality into ManageUsersView
- Remove share button from ResidenceDetailView toolbar
- Redesign ShareCodeCard with Easy Share on top

Android changes:
- Update ManageUsersDialog with matching layout
- Connect share package callback to existing share function

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-14 13:17:19 -06:00
Trey t
e2d264da7e Add client-side summary calculation and lookup resolution from cache
- Add calculateSummaryFromKanban() to compute summary stats from cached kanban data
- Add refreshSummaryFromKanban() called after task CRUD operations
- Fix column name matching to use API format (e.g., "overdue_tasks" not "overdue")
- Fix tasksDueNextMonth to only include due_soon tasks (not upcoming)
- Update TaskResponse computed properties to resolve from DataManager cache
- Update iOS task cards to use computed properties for priority/frequency/category
- This enables API to skip preloading lookups for better performance

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-14 01:04:52 -06:00
Trey t
258ccf7354 Improve error message handling with user-friendly messages
- Add ErrorMessageParser in Kotlin and Swift to detect network errors
  and technical messages, replacing them with human-readable text
- Update all ViewModels to use ErrorMessageParser.parse() for error display
- Remove redundant error popup from LoginView (error shows inline only)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-11 20:46:43 -06:00
Trey t
cbe073aa21 Add push notification deep linking and sharing subscription checks
- Add deep link navigation from push notifications to specific task column on kanban board
- Fix subscription check in push notification handler to allow navigation when limitations disabled
- Add pendingNavigationTaskId to handle notifications when app isn't ready
- Add ScrollViewReader to AllTasksView for programmatic scrolling to task column
- Add canShareResidence() and canShareContractor() subscription checks (iOS & Android)
- Add test APNS file for simulator push notification testing

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 23:17:28 -06:00
Trey t
4a04aff1e6 Replace status_id with in_progress boolean across mobile apps
- Remove TaskStatus model and status_id foreign key references
- Add in_progress boolean field to task models and forms
- Update TaskApi to use dedicated POST endpoints for task actions:
  - POST /tasks/:id/cancel/ instead of PATCH with is_cancelled
  - POST /tasks/:id/uncancel/
  - POST /tasks/:id/archive/
  - POST /tasks/:id/unarchive/
- Fix iOS TaskViewModel to use error-first pattern for Kotlin-Swift
  generic type bridging issues
- Update iOS callback signatures to pass full TaskResponse instead
  of just taskId to avoid stale closure lookups
- Add in_progress localization strings
- Update widget preview data to use inProgress boolean

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 20:47:59 -06:00
Trey t
83e2cd14a6 Add residence sharing via .casera files
- Add SharedResidence model and package type detection for .casera files
- Add generateSharePackage API endpoint integration
- Create ResidenceSharingManager for iOS and Android
- Add share button to residence detail screens (owner only)
- Add residence import handling with confirmation dialogs
- Update Quick Look extensions to show house icon for residence packages
- Route .casera imports by type (contractor vs residence)

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 18:54:46 -06:00
Trey t
859a6679ed Add contractor sharing feature and move settings to navigation bar
Contractor Sharing:
- Add .casera file format for sharing contractors between users
- Create SharedContractor model with JSON serialization
- Implement ContractorSharingManager for iOS (Swift) and Android (Kotlin)
- Register .casera file type in iOS Info.plist and Android manifest
- Add share button to ContractorDetailView (iOS) and ContractorDetailScreen (Android)
- Add import confirmation, success, and error dialogs
- Create expect/actual platform implementations for sharing and import handling

Navigation Changes:
- Remove Profile tab from bottom tab bar (iOS and Android)
- Add settings gear icon to left side of "My Properties" title
- Settings gear opens Profile/Settings screen as sheet (iOS) or navigates (Android)
- Add property button to top right action bar

Bug Fixes:
- Fix ResidenceUsersResponse to match API's flat array response format
- Fix GenerateShareCodeResponse handling to access nested shareCode property
- Update ManageUsersDialog to accept residenceOwnerId parameter

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 22:30:19 -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
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
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
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
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
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
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
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
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
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
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
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
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
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
Trey t
b922c4fb88 wip 2025-11-07 14:53:14 -06:00
Trey t
4e14352cd1 wip 2025-11-07 12:57:25 -06:00
Trey t
1b777049a8 wip 2025-11-07 12:21:48 -06:00
Trey t
66fe773398 wip 2025-11-06 17:53:41 -06:00
Trey t
e24d1d8559 wip 2025-11-06 09:25:21 -06:00
Trey t
e272e45689 wip 2025-11-05 21:35:52 -06:00
Trey t
b2b8cc62de wip 2025-11-05 18:02:34 -06:00
Trey t
86c89121e1 ios ui refactor 2025-11-05 17:15:17 -06:00
Trey t
1d48a9bff1 wip 2025-11-05 15:15:59 -06:00
Trey t
5deac95818 wip 2025-11-05 13:52:02 -06:00
Trey t
2be3a5a3a8 wip 2025-11-05 10:38:46 -06:00