_isOccupied matched any service on the slot regardless of status. Unblocking
sets the service to cancelled, so a released slot still rendered as occupied
and the unblock looked like it did nothing. Cancelled and denied services are
now ignored, and self-booked slots get their own "Bloqueado" state with a
release action, mirroring the web.
Self-booking now spans the professional's configured slot duration instead of
a hardcoded two hours, which no longer matched the generated slots.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Root cause behind most "stuck loading" reports: the backend changed shape
(schedules became an array, location_preferences a string) while the mobile
parser still hard-cast to Map/int. The TypeError was swallowed by a silent
catch that returned null, and screens only handled the success state, so a
parse failure rendered as a permanent spinner. Same class of bug appeared
across service lists via non-null map lookups and a total absence of
request timeouts.
Ported from prosappweb:
- in-app suggestions (POST /suggestions)
- policies/terms from GET /settings/policies
- configurable appointment length (slot_duration_minutes)
- block/unblock calendar slots (POST /services/block)
- GPS city detection on the profile (Nominatim)
- server-side professional search with haversine distance
- retry cooldown after a rejected professional application
Reliability:
- parse schedules array (day_of_week 0=Mon) and string location_preferences
- read times as wall clock, so 08:00 stays 08:00 across timezones
- carry minutes into hours in TimeOfDay.add; a minute-based step used to
loop forever and freeze the calendar (covered by test/time_slots_test.dart)
- semver update check instead of string equality, which blocked every build
that did not exactly match the configured version
- request timeouts across all repositories
- surface HTTP >= 400 instead of reporting failed writes as success
- error states with retry instead of an indefinite shimmer
Includes pre-existing uncommitted work from the UI redesign.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Port the same card UI pattern from the redesigned solicitudes screen
to the 4 remaining list screens (pro/user active services + history):
- 4px colored left strip matching service status color
- Circular avatar with status-colored border + letter fallback
- Status badge with icon + colored border (replaces solid filled badges)
- Date/time row with calendar icon
- Theme-aware colors via _Th extension (respects dark/light mode)
- AppBar with brand blue (replaces default grey)
- Empty state with icon + descriptive text
- Shimmer placeholders as rounded cards (replaces ListTile shimmer)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Port the 3 redesigned views from prosappweb to prosappco:
- Solicitudes: modern cards with 4px colored left strip, status badge with
icon+border, avatar with status-colored ring, date/time row, empty state
- Calendario: card-wrapped TableCalendar with custom CalendarStyle (blue
selected/ring today), day header card with date box + occupied/available
stat pills, slot cards with colored strip and time badge instead of
gradient circles
- Perfil profesional: gradient banner header with profession pill + camera
overlay, section cards with icon+title, payment method chips (animated)
instead of checkboxes, schedule rows with colored active/inactive dots,
theme-aware colors throughout (respects dark/light mode)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- professional_denied_screen: full UI with icon, bullet list of next steps,
re-register button and logout option (was just a Text widget)
- professional_pending_screen: replace static GIF screen with step-by-step
progress indicator (submitted → in review → approved), notification tip,
logout button
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- MyUser: add isPhoneVerified field (from is_phone_verified in API)
- ApiUserRepository: signInWithPhoneNumber calls POST /auth/send-otp,
verifyOTP calls POST /auth/phone, linkWithOTP calls POST /auth/verify-phone
Added updateFcmToken and changePassword methods
- AuthBloc: remove Firebase PhoneVerificationService, use repository OTP flow
- app_view.dart: gate authenticated users without verified phone to
PhoneVerifyRequiredScreen before showing HomeScreen
- welcome_screen.dart: full redesign with gradient header, logo, integrated
OTP flow (phone → code in same screen), 60s resend timer
- PhoneVerifyRequiredScreen: new screen for users who need to verify phone
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
score.createdAt is now String (ISO 8601) not Firebase Timestamp, so .toDate()
was a compile error. Use DateTime.tryParse() with fallback to DateTime.now().
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace all Firebase* repositories with Api* repositories using HTTP + SharedPreferences JWT
- Remove Firebase.initializeApp() and firebase_messaging background handler from main.dart
- Update DI (app_di.dart) to inject Api* repositories instead of Firebase* ones
- Replace all Timestamp/cloud_firestore usage with ISO 8601 String dates
- Stub PhoneVerificationService (Firebase phone OTP → backend OTP when implemented)
- Add ApiService singleton with JWT management in lib/services/
- Legacy firebase_*_repository.dart files preserved for Fase 4 cleanup
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>