Commit Graph

61 Commits

Author SHA1 Message Date
Trey t
2fc4a48fc9 Replace PostHog integration with AnalyticsManager architecture
Remove old PostHogAnalytics singleton and replace with guide-based
two-file architecture: AnalyticsManager (singleton wrapper with super
properties, session replay, opt-out, subscription funnel) and
AnalyticsEvent (type-safe enum with associated values).

Key changes:
- New API key, self-hosted analytics endpoint
- All 19 events ported to type-safe AnalyticsEvent enum
- Screen tracking via AnalyticsManager.Screen enum + SwiftUI modifier
- Remove all identify() calls — fully anonymous analytics
- Add lifecycle hooks: flush on background, update super properties on foreground
- Add privacy opt-out toggle in Settings
- Subscription funnel methods ready for IAP integration

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 09:48:49 -06:00
Trey t
09be5fa444 Add cancel task confirmation dialog
- Add L10n strings for cancel confirmation
- Add confirmation dialog to ResidenceDetailView
- Fix AllTasksView cancel dialog (was using archive strings)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 10:46:13 -06:00
Trey t
4daaa1f7d8 Consolidate task metrics to single source of truth
- Add API column name constants to WidgetDataManager (overdueColumn,
  dueWithin7DaysColumn, due8To30DaysColumn, etc.)
- Update DataManagerObservable to use WidgetDataManager column constants
- Remove duplicate ResidenceTaskStats struct, use TaskMetrics everywhere
- Delete TaskStatsCalculator.swift (consolidated into WidgetDataManager)
- Rename confusing flags: isUpcoming → isDueWithin7Days, isLater → isDue8To30Days
- Add comprehensive unit tests for TaskMetrics and WidgetTask

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 20:26:52 -06:00
Trey t
b39d37a6e8 Fix residence auto-update, widget theming, and document patterns
- Fix residence detail not updating after edit:
  - DataManager.updateResidence() now updates both _residences and _myResidences
  - ResidenceViewModel auto-updates selectedResidence when data changes
  - No pull-to-refresh needed after editing

- Add widget theme support:
  - Widgets now use user's selected theme via App Group UserDefaults
  - ThemeManager has simplified version for widget extension context
  - Added WIDGET_EXTENSION compiler flag to CaseraExtension target

- Redesign widget views with organic aesthetic:
  - Updated FreeWidgetView, SmallWidgetView, MediumWidgetView, LargeWidgetView
  - Created OrganicTaskRowView, OrganicStatsView, OrganicStatPillWidget

- Document patterns in CLAUDE.md:
  - Added Mutation & Auto-Update Pattern section
  - Added iOS Shared Components documentation
  - Documented reusable buttons, forms, empty states, cards, modifiers

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 22:58:55 -06:00
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
44c7b23cc2 Unify task stats calculation and update UI labels
- Create shared TaskStatsCalculator for consistent date bucket logic
- Fix widget stats to use exclusive buckets (overdue | 7 days | 30 days)
- Update labels: "This Week" → "Next 7 Days" / "7 Days"
- Large widget now shows Overdue, 7 Days, 30 Days (removed Total)
- Rename "Pros" tab to "Contractors"
- Remove red pulsing ring from residence card icons

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 12:07:35 -06:00
Trey t
bcd8b36a9b Fix TokenStorage stale cache bug and add user-friendly error messages
- Fix TokenStorage.getToken() returning stale cached token after login/logout
- Add comprehensive ErrorMessageParser with 80+ error code mappings
- Add Suite9 and Suite10 UI test files for E2E integration testing
- Fix accessibility identifiers in RegisterView and ResidenceFormView
- Fix UITestHelpers logout to target alert button specifically
- Update various UI components with proper accessibility identifiers

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 11:48:35 -06:00
Trey t
b05e52521f Apply Warm Organic design system to all iOS views
- Full-screen views: Added WarmGradientBackground() to CompleteTaskView,
  ContractorDetailView, DocumentDetailView, DocumentFormView,
  FeatureComparisonView, TaskTemplatesBrowserView, ManageUsersView,
  ContractorPickerView

- Onboarding: Redesigned all 8 screens with organic styling including
  animated hero sections, gradient buttons, decorative blobs

- Components: Updated ErrorView, EmptyStateView, EmptyResidencesView,
  EmptyTasksView, TaskSuggestionsView, StatView, SummaryStatView,
  CompletionCardView, DynamicTaskColumnView with organic styling

- Applied consistent patterns: OrganicSpacing, naturalShadow modifier,
  RoundedRectangle with .continuous style, rounded font designs

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 09:05:47 -06:00
Trey t
c3a9494b0f Fix task stats consistency and improve residence card UI
- Compute task stats locally from kanban data for both summary card and residence cards
- Filter out completed_tasks and cancelled_tasks columns from counts
- Use startOfDay for accurate date comparisons (overdue, due this week, next 30 days)
- Add parseDate helper to DateUtils
- Make address tappable to open in Apple Maps
- Remove navigation title from residences list
- Update CLAUDE.md with Go backend references and DataManager architecture

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 23:57:01 -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
59a827f692 Fix iOS build errors and notification time picker crash
- Remove invalid 'summary' parameter from TaskColumnsResponse calls
- Remove invalid 'totalDueSoon' parameter from TotalSummary call
- Fix TimePickerSheet crash when scrolling by properly initializing @State
  with State(initialValue:) and pre-computing hours array

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 17:40:03 -06:00
Trey t
fbe45da9ff Remove summary from list responses, calculate client-side
- Remove summary field from MyResidencesResponse and TaskColumnsResponse
- Update HomeScreen and ResidencesScreen to observe DataManager.totalSummary
- Load tasks when residence views appear to ensure accurate summary
- Add pull-to-refresh for tasks on ResidencesScreen
- Update iOS views to use client-side calculated summary

Summary is now calculated via refreshSummaryFromKanban() from cached
kanban data. This ensures summary is always up-to-date after CRUD
operations and when residence views are shown.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 17:06:48 -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
c334ce0bd0 Add PostHog analytics integration for Android and iOS
Implement comprehensive analytics tracking across both platforms:

Android (Kotlin):
- Add PostHog SDK dependency and initialization in MainActivity
- Create expect/actual pattern for cross-platform analytics (commonMain/androidMain/iosMain/jvmMain/jsMain/wasmJsMain)
- Track screen views: registration, login, residences, tasks, contractors, documents, notifications, profile
- Track key events: user_registered, user_signed_in, residence_created, task_created, contractor_created, document_created
- Track paywall events: contractor_paywall_shown, documents_paywall_shown
- Track sharing events: residence_shared, contractor_shared
- Track theme_changed event

iOS (Swift):
- Add PostHog iOS SDK via SPM
- Create PostHogAnalytics wrapper and AnalyticsEvents constants
- Initialize SDK in iOSApp with session replay support
- Track same screen views and events as Android
- Track user identification after login/registration

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 23:53:00 -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
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
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
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
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
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
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
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
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
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
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
0a7e7bc27f Fix ScrollView content obstruction by tab bar on iOS
This commit fixes the issue where ScrollView content at the bottom of screens was being hidden behind the tab bar.

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

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

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

All tab views now provide smooth, unobstructed scrolling experience.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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