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>
117 lines
3.9 KiB
Dart
117 lines
3.9 KiB
Dart
import 'package:equatable/equatable.dart';
|
|
|
|
class SettingEntity extends Equatable {
|
|
final bool? tarifas;
|
|
final bool? domicilios;
|
|
final bool? google;
|
|
final String? versionIos;
|
|
final String? versionAndroid;
|
|
final String? horaNotificacion;
|
|
final String? tituloSoporte;
|
|
final String? parrafoSoporte;
|
|
final String? numeroSoporte;
|
|
final String? emailSoporte;
|
|
final String? diasSoporte;
|
|
final String? horasSoporte;
|
|
final String? politicasPrivacidad;
|
|
final String? politicasPrivacidadTitle;
|
|
final String? politicasPrivacidadBody;
|
|
final String? terminosCondiciones;
|
|
final String? terminosCondicionesTitle;
|
|
final String? terminosCondicionesBody;
|
|
final num? rejectionWaitDays;
|
|
|
|
const SettingEntity({
|
|
required this.tarifas,
|
|
required this.domicilios,
|
|
required this.google,
|
|
required this.versionIos,
|
|
required this.versionAndroid,
|
|
required this.horaNotificacion,
|
|
required this.tituloSoporte,
|
|
required this.parrafoSoporte,
|
|
required this.numeroSoporte,
|
|
required this.emailSoporte,
|
|
required this.diasSoporte,
|
|
required this.horasSoporte,
|
|
required this.politicasPrivacidad,
|
|
required this.politicasPrivacidadTitle,
|
|
required this.politicasPrivacidadBody,
|
|
required this.terminosCondiciones,
|
|
required this.terminosCondicionesTitle,
|
|
required this.terminosCondicionesBody,
|
|
this.rejectionWaitDays,
|
|
});
|
|
|
|
static SettingEntity fromDocument(Map<String, dynamic> doc) {
|
|
return SettingEntity(
|
|
tarifas: doc['tarifas'] as bool?,
|
|
domicilios: doc['domicilios'] as bool?,
|
|
google: doc['google'] as bool?,
|
|
versionIos: doc['version_ios'] as String?,
|
|
versionAndroid: doc['version_android'] as String?,
|
|
horaNotificacion: doc['hora_notificacion'] as String?,
|
|
tituloSoporte: doc['titulo_soporte'] as String?,
|
|
parrafoSoporte: doc['parrafo_soporte'] as String?,
|
|
numeroSoporte: doc['numero_soporte'] as String?,
|
|
emailSoporte: doc['email_soporte'] as String?,
|
|
diasSoporte: doc['dias_soporte'] as String?,
|
|
horasSoporte: doc['horas_soporte'] as String?,
|
|
politicasPrivacidad: doc['politicas_privacidad'] as String?,
|
|
politicasPrivacidadTitle: doc['politicas_privacidad_title'] as String?,
|
|
politicasPrivacidadBody: doc['politicas_privacidad_body'] as String?,
|
|
terminosCondiciones: doc['terminos_condiciones'] as String?,
|
|
terminosCondicionesTitle: doc['terminos_condiciones_title'] as String?,
|
|
terminosCondicionesBody: doc['terminos_condiciones_body'] as String?,
|
|
rejectionWaitDays: doc['rejection_wait_days'] as num?,
|
|
);
|
|
}
|
|
|
|
@override
|
|
List<Object?> get props => [
|
|
tarifas,
|
|
domicilios,
|
|
google,
|
|
versionIos,
|
|
versionAndroid,
|
|
horaNotificacion,
|
|
tituloSoporte,
|
|
parrafoSoporte,
|
|
numeroSoporte,
|
|
emailSoporte,
|
|
diasSoporte,
|
|
horasSoporte,
|
|
politicasPrivacidad,
|
|
politicasPrivacidadTitle,
|
|
politicasPrivacidadBody,
|
|
terminosCondiciones,
|
|
terminosCondicionesTitle,
|
|
terminosCondicionesBody,
|
|
rejectionWaitDays,
|
|
];
|
|
|
|
@override
|
|
String toString() {
|
|
return '''SettingEntity {
|
|
tarifas: $tarifas
|
|
domicilios: $domicilios
|
|
google: $google
|
|
versionIos: $versionIos
|
|
versionAndroid: $versionAndroid
|
|
horaNotificacion: $horaNotificacion
|
|
tituloSoporte: $tituloSoporte
|
|
parrafoSoporte: $parrafoSoporte
|
|
numeroSoporte: $numeroSoporte
|
|
emailSoporte: $emailSoporte
|
|
diasSoporte: $diasSoporte
|
|
horasSoporte: $horasSoporte
|
|
politicasPrivacidad: $politicasPrivacidad
|
|
politicasPrivacidadTitle: $politicasPrivacidadTitle
|
|
politicasPrivacidadBody: $politicasPrivacidadBody
|
|
terminosCondiciones: $terminosCondiciones
|
|
terminosCondicionesTitle: $terminosCondicionesTitle
|
|
terminosCondicionesBody: $terminosCondicionesBody
|
|
}''';
|
|
}
|
|
}
|