fix: port 7 web features and repair the endless-loading screens
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>
This commit is contained in:
co-authored by
Claude Opus 5
parent
06a89df690
commit
8631e6f729
@@ -0,0 +1,36 @@
|
||||
import 'dart:convert';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
const _kHttpTimeout = Duration(seconds: 20);
|
||||
|
||||
const _base = 'https://backend.prosapp.co/api/v1';
|
||||
|
||||
class ApiSuggestionRepository {
|
||||
String? _token;
|
||||
|
||||
Future<String?> _getToken() async {
|
||||
if (_token != null) return _token;
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
return _token = prefs.getString('token');
|
||||
}
|
||||
|
||||
Future<Map<String, String>> _headers() async {
|
||||
final t = await _getToken();
|
||||
return {
|
||||
'Content-Type': 'application/json',
|
||||
if (t != null) 'Authorization': 'Bearer $t',
|
||||
};
|
||||
}
|
||||
|
||||
Future<void> createSuggestion(String message) async {
|
||||
final res = await http.post(
|
||||
Uri.parse('$_base/suggestions'),
|
||||
headers: await _headers(),
|
||||
body: jsonEncode({'message': message}),
|
||||
).timeout(_kHttpTimeout);
|
||||
if (res.statusCode >= 400) {
|
||||
throw Exception('No se pudo enviar la sugerencia (${res.statusCode})');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
library suggestion_repository;
|
||||
|
||||
export 'src/repositories/api_suggestion_repository.dart';
|
||||
@@ -0,0 +1,24 @@
|
||||
name: suggestion_repository
|
||||
description: Dart package for the suggestion repository.
|
||||
publish_to: 'none'
|
||||
|
||||
version: 1.0.0+1
|
||||
|
||||
environment:
|
||||
sdk: ">=2.19.3 <3.0.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
equatable: ^2.0.5
|
||||
http: ^1.1.0
|
||||
shared_preferences: ^2.0.10
|
||||
|
||||
|
||||
dev_dependencies:
|
||||
flutter_lints: ^2.0.0
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
|
||||
flutter:
|
||||
uses-material-design: true
|
||||
Reference in New Issue
Block a user