Critical fixes for the scheduling flow:
- ScheduleEntity: add toScheduleDto() with snake_case keys, day_of_week,
and HH:MM zero-padded format required by the backend DTO @Matches validator
- Schedules: add toSchedulesArray() converting the day-keyed object to the
array format expected by PATCH /professionals/me/schedules
- ProfessionalFormProvider: updateProfesionalProfileScheduleInfo now calls
the correct endpoint (/professionals/me/schedules) instead of /professionals/me
which was stripping the schedules field via ValidationPipe whitelist
- Service.formatTimeOfDay: zero-pad hours and minutes so POST /services passes
the @Matches(/^\d{2}:\d{2}$/) DTO validation
- ProfessionalProvider: add getProfessionalById() calling /professionals/:id
(public endpoint) to load any professional's data, not the viewer's own
- CalendarServicesProvider: add getPublicServicesForProfessional() calling
/services/public-calendar/:id so the user calendar shows the target
professional's booked slots, not the viewer's own services
- CalendarView: use getProfessionalById + getPublicServicesForProfessional
so the calendar correctly reflects the selected professional's schedule
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
77 lines
2.2 KiB
Dart
77 lines
2.2 KiB
Dart
import 'package:flutter/widgets.dart';
|
|
import 'package:prosapp_web_app/models/location_preferences.dart';
|
|
import 'package:prosapp_web_app/models/payment_method_entity.dart';
|
|
import 'package:prosapp_web_app/models/profesional.dart';
|
|
import 'package:prosapp_web_app/models/schedules.dart';
|
|
import 'package:prosapp_web_app/services/api_service.dart';
|
|
|
|
class ProfessionalProvider extends ChangeNotifier {
|
|
Profesional? profesional;
|
|
bool _isProModeActive = false;
|
|
final _api = ApiService.instance;
|
|
|
|
bool get isProModeActive => _isProModeActive;
|
|
|
|
Future<Profesional> getProfessional(String uid) async {
|
|
try {
|
|
final data = await _api.get('/professionals/me');
|
|
profesional = Profesional.fromDocument(data as Map<String, dynamic>);
|
|
} catch (_) {
|
|
// Professional profile doesn't exist yet — return empty so the form shows blank
|
|
profesional = Profesional(
|
|
id: uid,
|
|
identification: '',
|
|
rethusCode: '',
|
|
rethusValidated: false,
|
|
address: '',
|
|
aditionalAddress: '',
|
|
profession: '',
|
|
ratePreferences: false,
|
|
rate: '',
|
|
locationPreferences: LocationPreferences.office,
|
|
bannerPicture: '',
|
|
identificationPicture: '',
|
|
certificatePicture: '',
|
|
latitude: 0,
|
|
longitude: 0,
|
|
specializations: [],
|
|
specializationsPictures: [],
|
|
schedules: Schedules.empty,
|
|
paymentMethods: PaymentMethodEntity.empty,
|
|
);
|
|
}
|
|
notifyListeners();
|
|
return profesional!;
|
|
}
|
|
|
|
// Fetches any professional by UUID or user_id via the public endpoint.
|
|
// Used by CalendarView to load the target professional (not the logged-in user).
|
|
Future<Profesional> getProfessionalById(String id) async {
|
|
try {
|
|
final data = await _api.get('/professionals/$id');
|
|
final prof = Profesional.fromDocument(data as Map<String, dynamic>);
|
|
notifyListeners();
|
|
return prof;
|
|
} catch (_) {
|
|
return Profesional.empty();
|
|
}
|
|
}
|
|
|
|
void logout() {
|
|
_isProModeActive = false;
|
|
notifyListeners();
|
|
}
|
|
|
|
void toggleProMode() {
|
|
_isProModeActive = !_isProModeActive;
|
|
notifyListeners();
|
|
}
|
|
|
|
void setIsProModeActive(bool value) {
|
|
_isProModeActive = value;
|
|
notifyListeners();
|
|
}
|
|
|
|
sendProfessionalToReview() {}
|
|
}
|