/services/public-calendar/{professionalId} exists after all — the web has been
using it all along. My earlier probes missed it because they guessed the URL
shape, and because it is keyed by the professionals row id rather than the
owning user id, which ProfessionalEntity was discarding.
Adds ProfessionalEntity.recordId and points the client calendar at the public
endpoint. Until now a client browsing a professional's availability was served
their own agenda, so every slot looked free and two people could book the same
hour. A failed load now hides the slots and offers a retry instead of showing
them as available.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
192 lines
6.4 KiB
Dart
192 lines
6.4 KiB
Dart
import 'package:equatable/equatable.dart';
|
|
import 'package:professional_repository/professional_repository.dart';
|
|
|
|
class ProfessionalEntity extends Equatable {
|
|
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;
|
|
final int slotDurationMinutes;
|
|
|
|
/// Row id in the `professionals` table. Distinct from [id], which is the
|
|
/// owning user's id. Endpoints such as /services/public-calendar are keyed
|
|
/// by this one.
|
|
final String recordId;
|
|
|
|
const ProfessionalEntity({
|
|
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,
|
|
this.slotDurationMinutes = 120,
|
|
this.recordId = '',
|
|
});
|
|
|
|
static ProfessionalEntity fromDocument(Map<String, dynamic> doc) {
|
|
return ProfessionalEntity(
|
|
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,
|
|
rate: doc['rate'] as String,
|
|
locationPreferences: intToEnum(doc['location_preferences'] as int),
|
|
bannerPicture: doc['banner_picture'] as String,
|
|
identificationPicture: doc['identification_picture'] as String,
|
|
certificatePicture: doc['certificate_picture'] as String,
|
|
latitude: double.parse(doc['latitude'].toString()),
|
|
longitude: double.parse(doc['longitude'].toString()),
|
|
specializations: List<String>.from(doc['specializations']),
|
|
specializationsPictures:
|
|
List<String>.from(doc['specializations_pictures']),
|
|
schedules: Schedules.fromDocument(doc['schedules']),
|
|
paymentMethods: PaymentMethodEntity.fromDocument(doc['payment_methods']),
|
|
slotDurationMinutes:
|
|
(doc['slot_duration_minutes'] as num?)?.toInt() ?? 120,
|
|
recordId: doc['id']?.toString() ?? '',
|
|
);
|
|
}
|
|
|
|
ProfessionalEntity 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,
|
|
int? slotDurationMinutes,
|
|
String? recordId,
|
|
}) {
|
|
return ProfessionalEntity(
|
|
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,
|
|
slotDurationMinutes: slotDurationMinutes ?? this.slotDurationMinutes,
|
|
recordId: recordId ?? this.recordId,
|
|
);
|
|
}
|
|
|
|
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(),
|
|
'slot_duration_minutes': slotDurationMinutes,
|
|
};
|
|
}
|
|
|
|
@override
|
|
List<Object?> get props => [
|
|
id,
|
|
identification,
|
|
address,
|
|
aditionalAddress,
|
|
profession,
|
|
ratePreferences,
|
|
rate,
|
|
locationPreferences,
|
|
bannerPicture,
|
|
identificationPicture,
|
|
certificatePicture,
|
|
latitude,
|
|
longitude,
|
|
specializations,
|
|
specializationsPictures,
|
|
schedules,
|
|
paymentMethods,
|
|
slotDurationMinutes,
|
|
recordId,
|
|
];
|
|
|
|
@override
|
|
String toString() {
|
|
return '''ProfessionalEntity{ {
|
|
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
|
|
}''';
|
|
}
|
|
}
|