- Auth: phone login → POST /auth/phone (direct, no OTP); link phone → POST /auth/verify-phone; add email → POST /auth/link-email
- Services: replace query-param paths with dedicated role endpoints (/services/me, /services/professional/requests, /services/professional, etc.)
- Services: PATCH /services/:id → PATCH /services/:id/status
- Calendar: → GET /services/professional/calendar
- Professionals: /users/professionals → /professionals (handles {data:[...]} response)
- Professional info: /professional-info/:id → /professionals/:id; PATCH → /professionals/me
- Comments: /comments?... → /comments/user/:id and /comments/professional/:id
- Chat: /chats → /chat; start chat → POST /chat/start/:professionalId; poll GET /chat/:chatId/messages; send → POST /chat/:chatId/message
- Cities: /cities → GET /locations/countries (parse nested countries→regions→cities)
- Profesional.fromDocument: null-safe fields; convert schedules array→Schedules, specializations array→name/picture lists, payment_methods object/array
- Usuario.fromDocument: null-safe professional_state and id
- UsuarioProfesional.fromDocument: handle backend format (users nested, professional at top level)
- ScheduleEntity.parseTime: handle ISO8601 time strings from backend
- MessageEntity.fromDocument: accept sender_id (backend) or owner_id (legacy)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
211 lines
7.7 KiB
Dart
211 lines
7.7 KiB
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/schedules.dart';
|
|
import 'package:prosapp_web_app/models/schedules_entity.dart';
|
|
|
|
class Profesional {
|
|
final String id;
|
|
final String identification;
|
|
final String address;
|
|
final String aditionalAddress;
|
|
final String profession;
|
|
final bool ratePreferences;
|
|
final String rate;
|
|
final LocationPreferences locationPreferences;
|
|
final String bannerPicture;
|
|
final String identificationPicture;
|
|
final String certificatePicture;
|
|
final double latitude;
|
|
final double longitude;
|
|
final List<String> specializations;
|
|
final List<String> specializationsPictures;
|
|
final Schedules schedules;
|
|
final PaymentMethodEntity paymentMethods;
|
|
|
|
const Profesional({
|
|
required this.id,
|
|
required this.identification,
|
|
required this.address,
|
|
required this.aditionalAddress,
|
|
required this.profession,
|
|
required this.ratePreferences,
|
|
required this.rate,
|
|
required this.locationPreferences,
|
|
required this.bannerPicture,
|
|
required this.identificationPicture,
|
|
required this.certificatePicture,
|
|
required this.latitude,
|
|
required this.longitude,
|
|
required this.specializations,
|
|
required this.specializationsPictures,
|
|
required this.schedules,
|
|
required this.paymentMethods,
|
|
});
|
|
|
|
static Profesional fromDocument(Map<String, dynamic> doc) {
|
|
// Backend returns schedules as array [{day_of_week, enabled, ...}]; convert to Schedules
|
|
Schedules parsedSchedules = Schedules.empty;
|
|
final rawSchedules = doc['schedules'];
|
|
if (rawSchedules is List && rawSchedules.isNotEmpty) {
|
|
final days = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'];
|
|
final map = <int, Map<String, dynamic>>{};
|
|
for (final s in rawSchedules) {
|
|
map[(s['day_of_week'] as int)] = s as Map<String, dynamic>;
|
|
}
|
|
ScheduleEntity _se(int day) {
|
|
final s = map[day];
|
|
if (s == null) return ScheduleEntity.empty;
|
|
return ScheduleEntity(
|
|
enabled: (s['enabled'] as bool?) ?? false,
|
|
continuousDay: (s['continuous_day'] as bool?) ?? false,
|
|
range1Hour1: ScheduleEntity.parseTime(s['range1_hour1']?.toString()),
|
|
range1Hour2: ScheduleEntity.parseTime(s['range1_hour2']?.toString()),
|
|
range2Hour1: ScheduleEntity.parseTime(s['range2_hour1']?.toString()),
|
|
range2Hour2: ScheduleEntity.parseTime(s['range2_hour2']?.toString()),
|
|
);
|
|
}
|
|
parsedSchedules = Schedules(
|
|
monday: _se(0), tuesday: _se(1), wednesday: _se(2), thursday: _se(3),
|
|
friday: _se(4), saturday: _se(5), sunday: _se(6),
|
|
);
|
|
} else if (rawSchedules is Map) {
|
|
parsedSchedules = Schedules.fromDocument(rawSchedules as Map<String, dynamic>);
|
|
}
|
|
|
|
// Specializations: array of objects [{name, picture}] or list of strings
|
|
List<String> specs = [];
|
|
List<String> specPics = [];
|
|
final rawSpecs = doc['specializations'];
|
|
if (rawSpecs is List) {
|
|
for (final s in rawSpecs) {
|
|
if (s is Map) {
|
|
specs.add((s['name'] as String?) ?? '');
|
|
specPics.add((s['picture'] as String?) ?? '');
|
|
} else {
|
|
specs.add(s.toString());
|
|
}
|
|
}
|
|
}
|
|
final rawSpecPics = doc['specializations_pictures'];
|
|
if (specPics.isEmpty && rawSpecPics is List) {
|
|
specPics = List<String>.from(rawSpecPics);
|
|
}
|
|
|
|
// payment_methods: object {nequi, datafono, transferencia} or array with one element or null
|
|
PaymentMethodEntity pm = PaymentMethodEntity.empty;
|
|
final rawPm = doc['payment_methods'];
|
|
if (rawPm is Map<String, dynamic>) {
|
|
pm = PaymentMethodEntity.fromDocument(rawPm);
|
|
} else if (rawPm is List && rawPm.isNotEmpty) {
|
|
pm = PaymentMethodEntity.fromDocument(rawPm.first as Map<String, dynamic>);
|
|
}
|
|
|
|
return Profesional(
|
|
id: doc['id'] as String,
|
|
identification: (doc['identification'] as String?) ?? '',
|
|
address: (doc['address'] as String?) ?? '',
|
|
aditionalAddress: (doc['aditional_address'] as String?) ?? '',
|
|
profession: (doc['profession'] as String?) ?? '',
|
|
ratePreferences: (doc['rate_preferences'] as bool?) ?? false,
|
|
rate: (doc['rate'] as String?) ?? '',
|
|
locationPreferences: intToEnum((doc['location_preferences'] as int?) ?? 0),
|
|
bannerPicture: (doc['banner_picture'] as String?) ?? '',
|
|
identificationPicture: (doc['identification_picture'] as String?) ?? '',
|
|
certificatePicture: (doc['certificate_picture'] as String?) ?? '',
|
|
latitude: (doc['latitude'] as num?)?.toDouble() ?? 0.0,
|
|
longitude: (doc['longitude'] as num?)?.toDouble() ?? 0.0,
|
|
specializations: specs,
|
|
specializationsPictures: specPics,
|
|
schedules: parsedSchedules,
|
|
paymentMethods: pm,
|
|
);
|
|
}
|
|
|
|
Profesional copyWith({
|
|
String? id,
|
|
String? identification,
|
|
String? address,
|
|
String? aditionalAddress,
|
|
String? profession,
|
|
bool ratePreferences = false,
|
|
String? rate,
|
|
LocationPreferences? locationPreferences,
|
|
String? bannerPicture,
|
|
String? identificationPicture,
|
|
String? certificatePicture,
|
|
double? latitude,
|
|
double? longitude,
|
|
List<String>? specializations,
|
|
List<String>? specializationsPictures,
|
|
Schedules? schedules,
|
|
PaymentMethodEntity? paymentMethods,
|
|
}) {
|
|
return Profesional(
|
|
id: id ?? this.id,
|
|
identification: identification ?? this.identification,
|
|
address: address ?? this.address,
|
|
aditionalAddress: aditionalAddress ?? this.aditionalAddress,
|
|
profession: profession ?? this.profession,
|
|
ratePreferences: ratePreferences,
|
|
rate: rate ?? this.rate,
|
|
locationPreferences: locationPreferences ?? this.locationPreferences,
|
|
bannerPicture: bannerPicture ?? this.bannerPicture,
|
|
identificationPicture:
|
|
identificationPicture ?? this.identificationPicture,
|
|
certificatePicture: certificatePicture ?? this.certificatePicture,
|
|
latitude: latitude ?? this.latitude,
|
|
longitude: longitude ?? this.longitude,
|
|
specializations: specializations ?? this.specializations,
|
|
specializationsPictures:
|
|
specializationsPictures ?? this.specializationsPictures,
|
|
schedules: schedules ?? this.schedules,
|
|
paymentMethods: paymentMethods ?? this.paymentMethods,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toDocument() {
|
|
return {
|
|
'id': id,
|
|
'identification': identification,
|
|
'address': address,
|
|
'aditional_address': aditionalAddress,
|
|
'profession': profession,
|
|
'rate_preferences': ratePreferences,
|
|
'rate': rate,
|
|
'location_preferences': enumToInt(locationPreferences),
|
|
'banner_picture': bannerPicture,
|
|
'identification_picture': identificationPicture,
|
|
'certificate_picture': certificatePicture,
|
|
'latitude': latitude,
|
|
'longitude': longitude,
|
|
'specializations': specializations,
|
|
'specializations_pictures': specializationsPictures,
|
|
'schedules': schedules.toJson(),
|
|
'payment_methods': paymentMethods.toDocument(),
|
|
};
|
|
}
|
|
|
|
@override
|
|
String toString() {
|
|
return '''Profesional{ {
|
|
id: $id,
|
|
identification: $identification,
|
|
address: $address,
|
|
aditional_address: $aditionalAddress,
|
|
profession: $profession,
|
|
rate_preferences: $ratePreferences,
|
|
rate: $rate,
|
|
location_preferences: $locationPreferences,
|
|
bannerPicture: $bannerPicture,
|
|
identificationPicture: $identificationPicture,
|
|
certificatePicture: $certificatePicture,
|
|
latitude: $latitude,
|
|
longitude: $longitude,
|
|
specializations: $specializations,
|
|
specializationsPictures: $specializationsPictures,
|
|
schedule: $schedules,
|
|
paymentMethods: $paymentMethods
|
|
}''';
|
|
}
|
|
}
|