feat: migrate prosappco from Firebase to NestJS REST API (Fase 2)

- Replace all Firebase* repositories with Api* repositories using HTTP + SharedPreferences JWT
- Remove Firebase.initializeApp() and firebase_messaging background handler from main.dart
- Update DI (app_di.dart) to inject Api* repositories instead of Firebase* ones
- Replace all Timestamp/cloud_firestore usage with ISO 8601 String dates
- Stub PhoneVerificationService (Firebase phone OTP → backend OTP when implemented)
- Add ApiService singleton with JWT management in lib/services/
- Legacy firebase_*_repository.dart files preserved for Fase 4 cleanup

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lizandro Guarnizo
2026-06-17 16:53:11 -05:00
co-authored by Claude Sonnet 4.6
parent 726cf12fd2
commit 733384091c
65 changed files with 1404 additions and 389 deletions
+6 -7
View File
@@ -1,5 +1,4 @@
import 'package:chat_repository/chat_repository.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -111,7 +110,7 @@ class _ChatScreenState extends State<ChatScreen> {
),
),
subtitle: widget.service.userId ==
FirebaseAuth.instance.currentUser!.uid
ApiUserRepository.currentUserId ?? ''
? GeneralReputation(
userId: widget.service.professionalId,
builder: (context, reputation) {
@@ -229,7 +228,7 @@ class _ChatScreenState extends State<ChatScreen> {
MessageEntity message = MessageEntity(
ownerId:
FirebaseAuth.instance.currentUser!.uid,
ApiUserRepository.currentUserId ?? '',
content: _messageController.text.trim(),
createdAt: DateTime.now(),
);
@@ -272,7 +271,7 @@ class _ChatScreenState extends State<ChatScreen> {
}
MessageEntity message = MessageEntity(
ownerId: FirebaseAuth.instance.currentUser!.uid,
ownerId: ApiUserRepository.currentUserId ?? '',
content: _messageController.text.trim(),
createdAt: DateTime.now(),
);
@@ -340,7 +339,7 @@ class _ChatScreenState extends State<ChatScreen> {
List<Widget> _messagesList(List<MessageEntity> messages) {
return messages
.map(
(e) => e.ownerId != FirebaseAuth.instance.currentUser!.uid
(e) => e.ownerId != ApiUserRepository.currentUserId ?? ''
? ListTile(
title: Column(
mainAxisAlignment: MainAxisAlignment.start,
@@ -437,12 +436,12 @@ class _ChatScreenState extends State<ChatScreen> {
Future<List<dynamic>> _getUserAndProfessionalInfo(
ServiceEntity service) async {
final userRepo = FirebaseUserRepository(FirebaseAuth.instance);
final userRepo = Injector.appInstance.get<UserRepository>();
final MyUser? userInfo;
final MyUser? myInfo;
if (FirebaseAuth.instance.currentUser!.uid == service.userId) {
if ((ApiUserRepository.currentUserId ?? '') == service.userId) {
userInfo = await userRepo.getMyUser(service.professionalId);
myInfo = await userRepo.getMyUser(service.userId);
} else {
@@ -1,4 +1,5 @@
import 'package:firebase_auth/firebase_auth.dart';
import 'package:user_repository/user_repository.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -173,13 +174,13 @@ class _ProfessionalListScreenState extends State<ProfessionalListScreen> {
.toLowerCase()
.contains(removeDiacritics(_searchController.text.toLowerCase())))
.where((user) =>
user.myUser.id != FirebaseAuth.instance.currentUser!.uid)
user.myUser.id != ApiUserRepository.currentUserId ?? '')
.where(
(user) => user.professionalInfo.profession == _selectedProfession)
.toList();
// } else {
// filteredUsers = state.users
// // .where((user) => user.myUser.id != FirebaseAuth.instance.currentUser!.uid)
// // .where((user) => user.myUser.id != ApiUserRepository.currentUserId ?? '')
// .toList();
// }
@@ -1,4 +1,5 @@
import 'package:firebase_auth/firebase_auth.dart';
import 'package:user_repository/user_repository.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -28,7 +29,7 @@ class _ProfessionalPendingServiceListScreenState
serviceBloc = Injector.appInstance.get<ServiceBloc>();
serviceBloc.add(LoadPendingServicesForProfessional(FirebaseAuth.instance.currentUser!.uid));
serviceBloc.add(LoadPendingServicesForProfessional(ApiUserRepository.currentUserId ?? ''));
}
@override
@@ -1,4 +1,5 @@
import 'package:firebase_auth/firebase_auth.dart';
import 'package:user_repository/user_repository.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -25,7 +26,7 @@ class _ProfessionalScoreListScreenState
scoreBloc = Injector.appInstance.get<ScoreBloc>();
scoreBloc.add(LoadScoresForProfessionalEvent(
userId: FirebaseAuth.instance.currentUser!.uid));
userId: ApiUserRepository.currentUserId ?? ''));
}
@override
@@ -1,4 +1,5 @@
import 'package:firebase_auth/firebase_auth.dart';
import 'package:user_repository/user_repository.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -29,7 +30,7 @@ class _ProfessionalServiceHistoryListScreenState
serviceBloc = Injector.appInstance.get<ServiceBloc>();
serviceBloc.add(LoadServicesHistoryForProfessional(
FirebaseAuth.instance.currentUser!.uid));
ApiUserRepository.currentUserId ?? ''));
}
@override
@@ -1,4 +1,5 @@
import 'package:firebase_auth/firebase_auth.dart';
import 'package:user_repository/user_repository.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -28,7 +29,7 @@ class _ProfessionalServiceListScreenState
serviceBloc = Injector.appInstance.get<ServiceBloc>();
serviceBloc.add(LoadServicesForProfessional(FirebaseAuth.instance.currentUser!.uid));
serviceBloc.add(LoadServicesForProfessional(ApiUserRepository.currentUserId ?? ''));
}
@override
@@ -1,4 +1,5 @@
import 'package:firebase_auth/firebase_auth.dart';
import 'package:user_repository/user_repository.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -24,7 +25,7 @@ class _UserScoreListScreenState extends State<UserScoreListScreen> {
scoreBloc = Injector.appInstance.get<ScoreBloc>();
scoreBloc.add(
LoadScoresForUserEvent(userId: FirebaseAuth.instance.currentUser!.uid));
LoadScoresForUserEvent(userId: ApiUserRepository.currentUserId ?? ''));
}
@override
@@ -1,4 +1,5 @@
import 'package:firebase_auth/firebase_auth.dart';
import 'package:user_repository/user_repository.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -29,7 +30,7 @@ class _UserServiceHistoryListScreenState
serviceBloc = Injector.appInstance.get<ServiceBloc>();
serviceBloc.add(
LoadServicesHistoryForUser(FirebaseAuth.instance.currentUser!.uid));
LoadServicesHistoryForUser(ApiUserRepository.currentUserId ?? ''));
}
@override
@@ -1,4 +1,5 @@
import 'package:firebase_auth/firebase_auth.dart';
import 'package:user_repository/user_repository.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -27,7 +28,7 @@ class _UserServiceListScreenState extends State<UserServiceListScreen> {
serviceBloc = Injector.appInstance.get<ServiceBloc>();
serviceBloc
.add(LoadServicesForUser(FirebaseAuth.instance.currentUser!.uid));
.add(LoadServicesForUser(ApiUserRepository.currentUserId ?? ''));
}
@override
@@ -1,4 +1,3 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
@@ -28,7 +27,7 @@ class ProfessionalCalendarScreen extends StatefulWidget {
class _ProfessionalCalendarScreenState extends State<ProfessionalCalendarScreen> {
final settingRepository = Injector.appInstance.get<SettingRepository>();
final serviceRepository =
Injector.appInstance.get<FirebaseServiceRepository>();
Injector.appInstance.get<ApiServiceRepository>();
SettingEntity? settings;
DateTime today = DateTime.now();
@@ -352,7 +351,7 @@ class _ProfessionalCalendarScreenState extends State<ProfessionalCalendarScreen>
latitude: 0,
longitude: 0,
day: today.toString(),
createdAt: Timestamp.now(),
createdAt: DateTime.now().toIso8601String(),
description: '',
range1Hour1: time,
range1Hour2: time.add(hour: 2),
+9 -11
View File
@@ -1,5 +1,3 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -33,7 +31,7 @@ class _ScoreScreenState extends State<ScoreScreen> {
super.initState();
_userInfoFuture = _getUserAndProfessionalInfo(widget.service);
isProfessional =
FirebaseAuth.instance.currentUser!.uid == widget.service.userId
ApiUserRepository.currentUserId ?? '' == widget.service.userId
? true
: false;
@@ -304,33 +302,33 @@ class _ScoreScreenState extends State<ScoreScreen> {
return FilledButton(
onPressed: () {
final CommentEntity comment = widget.service.userId ==
FirebaseAuth.instance.currentUser!.uid
ApiUserRepository.currentUserId ?? ''
? CommentEntity(
serviceId: widget.service.id!,
authorId:
FirebaseAuth.instance.currentUser!.uid,
ApiUserRepository.currentUserId ?? '',
isFromUser: true,
score: _rating,
destinationId: widget.service.professionalId,
content: commentController.text.trim(),
createdAt: Timestamp.now(),
createdAt: DateTime.now().toIso8601String(),
)
: CommentEntity(
serviceId: widget.service.id!,
authorId:
FirebaseAuth.instance.currentUser!.uid,
ApiUserRepository.currentUserId ?? '',
isFromUser: false,
score: _rating,
destinationId: widget.service.userId,
content: commentController.text.trim(),
createdAt: Timestamp.now(),
createdAt: DateTime.now().toIso8601String(),
);
BlocProvider.of<ScoreBloc>(context)
.add(SendScoreEvent(comment: comment));
if (widget.service.userId ==
FirebaseAuth.instance.currentUser!.uid) {
ApiUserRepository.currentUserId ?? '') {
context.read<ServiceBloc>().add(
UpdateProfessionalScored(widget.service.id!));
} else {
@@ -392,11 +390,11 @@ class _ScoreScreenState extends State<ScoreScreen> {
Future<List<dynamic>> _getUserAndProfessionalInfo(
ServiceEntity service) async {
final userRepo = FirebaseUserRepository(FirebaseAuth.instance);
final userRepo = Injector.appInstance.get<UserRepository>();
final MyUser? userInfo;
if (FirebaseAuth.instance.currentUser!.uid == service.userId) {
if (ApiUserRepository.currentUserId ?? '' == service.userId) {
userInfo = await userRepo.getMyUser(service.professionalId);
} else {
userInfo = await userRepo.getMyUser(service.userId);
@@ -1,6 +1,5 @@
import 'dart:async';
import 'package:community_material_icon/community_material_icon.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -848,7 +847,7 @@ class _ProfessionalServiceScreenState extends State<ProfessionalServiceScreen> {
Future<List<dynamic>> _getUserAndProfessionalInfo(
ServiceEntity service) async {
final userRepo = FirebaseUserRepository(FirebaseAuth.instance);
final userRepo = Injector.appInstance.get<UserRepository>();
final userInfo = await userRepo.getMyUser(service.userId);
return [userInfo];
+3 -5
View File
@@ -1,6 +1,5 @@
import 'dart:async';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -484,16 +483,15 @@ class _ServiceScreenState extends State<ServiceScreen> {
Future<List<dynamic>> _getUserAndProfessionalInfo(
ServiceEntity service) async {
final userRepo = FirebaseUserRepository(FirebaseAuth.instance);
final professionalRepo = FirebaseProfessionalRepository();
if (FirebaseAuth.instance.currentUser!.uid == service.professionalId) {
final userRepo = Injector.appInstance.get<UserRepository>();
final professionalRepo = Injector.appInstance.get<ApiProfessionalRepository>();
if ((ApiUserRepository.currentUserId ?? '') == service.professionalId) {
final userInfo = await userRepo.getMyUser(service.userId);
final professionalInfo =
await professionalRepo.getProInfo(service.professionalId);
return [userInfo, professionalInfo];
} else {
final userRepo = FirebaseUserRepository(FirebaseAuth.instance);
final userInfo = await userRepo.getMyUser(service.professionalId);
final professionalInfo =
+2 -3
View File
@@ -1,6 +1,5 @@
import 'dart:async';
import 'package:community_material_icon/community_material_icon.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -975,8 +974,8 @@ class _UserServiceScreenState extends State<UserServiceScreen> {
Future<List<dynamic>> _getUserAndProfessionalInfo(
ServiceEntity service) async {
final userRepo = FirebaseUserRepository(FirebaseAuth.instance);
final professionalRepo = FirebaseProfessionalRepository();
final userRepo = Injector.appInstance.get<UserRepository>();
final professionalRepo = Injector.appInstance.get<ApiProfessionalRepository>();
final userInfo = await userRepo.getMyUser(service.professionalId);
final professionalInfo =
+1 -1
View File
@@ -22,7 +22,7 @@ class UserCalendarScreen extends StatefulWidget {
class UserCalendarScreenState extends State<UserCalendarScreen> {
final settingRepository = Injector.appInstance.get<SettingRepository>();
final serviceRepository =
Injector.appInstance.get<FirebaseServiceRepository>();
Injector.appInstance.get<ApiServiceRepository>();
SettingEntity? settings;
DateTime today = DateTime.now();
+4 -5
View File
@@ -1,7 +1,6 @@
import 'dart:async';
import 'dart:developer';
import 'dart:io';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -549,7 +548,7 @@ class _UserMapScreenState extends State<UserMapScreen> {
longitude: profesionalSeleccionado!
.professionalInfo.longitude,
day: fechaSeleccionada.toString(),
createdAt: Timestamp.now(),
createdAt: DateTime.now().toIso8601String(),
description: _observationController.text,
range1Hour1: horaSeleccionada!,
range1Hour2:
@@ -574,7 +573,7 @@ class _UserMapScreenState extends State<UserMapScreen> {
longitude: profesionalSeleccionado!
.professionalInfo.longitude,
day: fechaSeleccionada.toString(),
createdAt: Timestamp.now(),
createdAt: DateTime.now().toIso8601String(),
description: _observationController.text,
range1Hour1: horaSeleccionada!,
range1Hour2:
@@ -597,7 +596,7 @@ class _UserMapScreenState extends State<UserMapScreen> {
latitude: 0,
longitude: 0,
day: fechaSeleccionada.toString(),
createdAt: Timestamp.now(),
createdAt: DateTime.now().toIso8601String(),
description: _observationController.text,
range1Hour1: horaSeleccionada!,
range1Hour2:
@@ -617,7 +616,7 @@ class _UserMapScreenState extends State<UserMapScreen> {
latitude: 0,
longitude: 0,
day: fechaSeleccionada.toString(),
createdAt: Timestamp.now(),
createdAt: DateTime.now().toIso8601String(),
description: _observationController.text,
range1Hour1: horaSeleccionada!,
range1Hour2:
+2 -3
View File
@@ -1,5 +1,4 @@
import 'dart:async';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -618,10 +617,10 @@ class _UserServiceScreenState extends State<UserServiceScreen> {
Future<List<dynamic>> _getUserAndProfessionalInfo(
ServiceEntity service) async {
final userRepo = FirebaseUserRepository(FirebaseAuth.instance);
final userRepo = Injector.appInstance.get<UserRepository>();
final userInfo = await userRepo.getMyUser(service.professionalId);
final professionalRepo = FirebaseProfessionalRepository();
final professionalRepo = Injector.appInstance.get<ApiProfessionalRepository>();
final professionalInfo =
await professionalRepo.getProInfo(service.professionalId);