fix: align route DTOs and field names with NestJS backend

- event_model: snake_case fields, status translation map (es→en), public-calendar route
- chat_model: both roles use GET /chat/my (JWT identifies user)
- score: correct POST /comments DTO (destination_id, service_id, content, score, is_from_user)
- horario: PATCH /professionals/me/schedules with array format instead of /users/me

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lizandro Guarnizo
2026-06-18 12:09:42 -05:00
co-authored by Claude Sonnet 4.6
parent b95e0630de
commit ce11aa813e
4 changed files with 150 additions and 88 deletions
+105 -60
View File
@@ -4,6 +4,16 @@ import 'package:prosappco/src/services/api_service.dart';
final uid = AuthenticationRepository.instance.getCurrentUserUid();
// Backend status strings
const _statusMap = {
'pendiente': 'pending',
'aprobado': 'accepted',
'negado': 'denied',
'activo': 'active',
'cancelado': 'cancelled',
'completado': 'completed',
};
class EventoService {
Future<String?> createEvent(
String title,
@@ -22,22 +32,32 @@ class EventoService {
bool userScored,
) async {
try {
final Map<String, dynamic> result = await ApiService.instance.post('/services', {
'user_id': uid,
'title': title,
'description': description,
'day': day,
'range1Hour1': range1Hour1,
'range1Hour2': range1Hour2,
String fmt(String t) {
// Normalize "8:30 AM" / "08:30" → "HH:MM"
try {
final parts = t.replaceAll(RegExp(r'[APM ]'), '').split(':');
final h = int.parse(parts[0]).toString().padLeft(2, '0');
final m = (parts.length > 1 ? int.parse(parts[1]) : 0)
.toString()
.padLeft(2, '0');
return '$h:$m';
} catch (_) {
return '00:00';
}
}
final Map<String, dynamic> result =
await ApiService.instance.post('/services', {
'professional_id': professionalId,
'ubicacion': ubicacion,
'day': day,
'description': description,
'rate': tarifa ?? 0,
'range1_hour1': fmt(range1Hour1),
'range1_hour2': fmt(range1Hour2),
'address': address,
'latitude': latitude,
'longitude': longitude,
'status': status,
'tarifa': tarifa ?? 0,
'professional_scored': professionalScored,
'user_scored': userScored,
'location_preference': ubicacion == 'domicilio' ? 'delivery' : 'office',
});
return result['id']?.toString();
} catch (e) {
@@ -47,54 +67,53 @@ class EventoService {
}
}
// Calendar for logged-in professional — uses JWT, ignores day filter on backend
Future<List<Event>> getByProId(String day) async {
try {
final List<dynamic> data = await ApiService.instance
.get('/services?day=$day&status=aprobado');
List<Event> eventos = [];
for (var element in data) {
final event = Event.fromJson(element as Map<String, dynamic>);
event.scoresModel =
await ScoresModel.scoreTo(event.userId, false, false);
eventos.add(event);
}
return eventos;
final data = await ApiService.instance.get('/services/professional/calendar');
final List raw = data is List ? data : (data['data'] ?? []);
return raw
.map((e) => Event.fromJson(e as Map<String, dynamic>))
.where((e) => e.day.startsWith(day.substring(0, 10)))
.toList();
} catch (e) {
print('Error getByProId $e');
return [];
}
}
// Active/accepted services for logged-in professional
Future<List<Event>> getByProIdAll(String state1, String state2) async {
try {
final List<dynamic> data = await ApiService.instance
.get('/services?professionalId=$uid&status=$state1,$state2');
List<Event> eventos = [];
for (var element in data) {
final event = Event.fromJson(element as Map<String, dynamic>);
event.scoresModel =
await ScoresModel.scoreTo(event.userId, false, false);
eventos.add(event);
}
return eventos;
final data = await ApiService.instance.get('/services/professional');
final List raw = data is Map ? (data['data'] ?? []) : (data as List);
final allowed = {
_statusMap[state1] ?? state1,
_statusMap[state2] ?? state2,
};
return raw
.map((e) => Event.fromJson(e as Map<String, dynamic>))
.where((e) => allowed.contains(e.status))
.toList();
} catch (e) {
print('Error getByProIdAll $e');
return [];
}
}
// Active/accepted services for logged-in user
Future<List<Event>> getByUserIdAll(String state1, String state2) async {
try {
final List<dynamic> data = await ApiService.instance
.get('/services?userId=$uid&status=$state1,$state2');
List<Event> eventos = [];
for (var element in data) {
final event = Event.fromJson(element as Map<String, dynamic>);
event.scoresModel =
await ScoresModel.scoreTo(event.userId, false, false);
eventos.add(event);
}
return eventos;
final data = await ApiService.instance.get('/services/me');
final List raw = data is Map ? (data['data'] ?? []) : (data as List);
final allowed = {
_statusMap[state1] ?? state1,
_statusMap[state2] ?? state2,
};
return raw
.map((e) => Event.fromJson(e as Map<String, dynamic>))
.where((e) => allowed.contains(e.status))
.toList();
} catch (e) {
print('Error getByUserIdAll $e');
return [];
@@ -134,7 +153,7 @@ class Event {
this.address,
this.longitud,
this.latitud,
this.status = 'pendiente',
this.status = 'pending',
this.timeStamp,
this.tarifa,
this.professionalScored = false,
@@ -143,25 +162,44 @@ class Event {
factory Event.fromJson(Map<String, dynamic> json) {
DateTime? ts;
final raw = json['Timestamp'] ?? json['created_at'];
final raw = json['created_at'] ?? json['Timestamp'];
if (raw is String) ts = DateTime.tryParse(raw);
// Backend sends ISO date for range times; extract HH:MM
String parseTime(dynamic v) {
if (v == null) return '';
final s = v.toString();
if (s.contains('T')) {
final dt = DateTime.tryParse(s);
if (dt != null) {
return '${dt.hour.toString().padLeft(2, '0')}:${dt.minute.toString().padLeft(2, '0')}';
}
}
return s;
}
// Nested professional user_id takes priority as professionalId
final nestedPro = json['professionals'];
final professionalId = (nestedPro is Map)
? (nestedPro['user_id']?.toString() ?? json['professional_id']?.toString() ?? '')
: json['professional_id']?.toString() ?? '';
return Event(
id: json['id']?.toString() ?? '',
title: json['title'] ?? '',
title: json['description'] ?? json['title'] ?? '',
description: json['description'],
day: json['day'] ?? '',
range1Hour1: json['range1Hour1'] ?? '',
range1Hour2: json['range1Hour2'],
range1Hour1: parseTime(json['range1_hour1'] ?? json['range1Hour1']),
range1Hour2: parseTime(json['range1_hour2'] ?? json['range1Hour2']),
userId: json['user_id'] ?? '',
professionalId: json['professional_id'] ?? '',
ubicacion: json['ubicacion'] ?? '',
professionalId: professionalId,
ubicacion: json['location_preference'] ?? json['ubicacion'] ?? '',
address: json['address'] ?? '',
longitud: (json['longitude'] ?? 0).toDouble(),
latitud: (json['latitude'] ?? 0).toDouble(),
status: json['status'] ?? 'pendiente',
status: json['status'] ?? 'pending',
timeStamp: ts,
tarifa: json['tarifa'] ?? json['tarifas'] ?? 0,
tarifa: (json['rate'] as num?)?.toInt() ?? json['tarifa'] ?? 0,
professionalScored: json['professional_scored'] ?? false,
userScored: json['user_scored'] ?? false,
);
@@ -179,11 +217,13 @@ class Event {
}
}
// All services for a given professional (by user_id) — uses public calendar
static Future<List<Event>> getEventsAllById(String proId) async {
try {
final List<dynamic> data =
await ApiService.instance.get('/services?professionalId=$proId');
return data
final data =
await ApiService.instance.get('/services/public-calendar/$proId');
final List raw = (data is Map ? data['services'] : data) ?? [];
return raw
.map((e) => Event.fromJson(e as Map<String, dynamic>))
.toList();
} catch (e) {
@@ -194,10 +234,12 @@ class Event {
static Future<List<Event>> getEventsAllByIdAndStatus(String proId) async {
try {
final List<dynamic> data = await ApiService.instance
.get('/services?professionalId=$proId&status=aprobado,pendiente');
return data
final data =
await ApiService.instance.get('/services/public-calendar/$proId');
final List raw = (data is Map ? data['services'] : data) ?? [];
return raw
.map((e) => Event.fromJson(e as Map<String, dynamic>))
.where((e) => e.status == 'accepted' || e.status == 'pending')
.toList();
} catch (e) {
print('Error getEventsAllByIdAndStatus $e');
@@ -208,10 +250,13 @@ class Event {
static Future<List<Event>> getEventsAllByIdStatus(
String proId, String state) async {
try {
final List<dynamic> data = await ApiService.instance
.get('/services?professionalId=$proId&status=$state');
return data
final backendStatus = _statusMap[state] ?? state;
final data =
await ApiService.instance.get('/services/professional/calendar');
final List raw = data is List ? data : [];
return raw
.map((e) => Event.fromJson(e as Map<String, dynamic>))
.where((e) => e.status == backendStatus)
.toList();
} catch (e) {
print('Error getEventsAllByIdStatus $e');