50e4f43738
Implement company AI onboarding/recommendation models, services, repository, and tender UI integration with supporting tests. Co-authored-by: Cursor <cursoragent@cursor.com>
142 lines
4.2 KiB
Dart
142 lines
4.2 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:tm_app/data/repositories/auth_repository.dart';
|
|
import 'package:tm_app/data/repositories/company_ai_repository.dart';
|
|
import 'package:tm_app/data/services/model/company_profile_data/company_profile_data.dart';
|
|
import 'package:tm_app/data/services/model/company_profile_response/company_profile_response.dart';
|
|
import 'package:tm_app/data/services/model/profile_data/profile_data.dart';
|
|
|
|
import '../core/utils/result.dart';
|
|
import '../data/repositories/profile_repository.dart';
|
|
import '../data/services/model/logout_response/logout_response.dart';
|
|
import '../data/services/model/profile_response/profile_response.dart';
|
|
|
|
class ProfileViewModel with ChangeNotifier {
|
|
final ProfileRepository _profileRepository;
|
|
final AuthRepository _authRepository;
|
|
final CompanyAiRepository _companyAiRepository;
|
|
|
|
ProfileViewModel({
|
|
required ProfileRepository profileRepository,
|
|
required AuthRepository authRepository,
|
|
required CompanyAiRepository companyAiRepository,
|
|
}) : _profileRepository = profileRepository,
|
|
_authRepository = authRepository,
|
|
_companyAiRepository = companyAiRepository;
|
|
|
|
bool _isLoading = false;
|
|
String? _errorMessage;
|
|
ProfileData? _profileData;
|
|
CompanyProfileData? _companyProfileData;
|
|
bool _loggedOut = false;
|
|
|
|
bool get isLoading => _isLoading;
|
|
bool get loggedOut => _loggedOut;
|
|
String? get errorMessage => _errorMessage;
|
|
ProfileData? get profileData => _profileData;
|
|
CompanyProfileData? get companyProfileData => _companyProfileData;
|
|
|
|
Future<void> getProfile() async {
|
|
_isLoading = true;
|
|
_errorMessage = null;
|
|
notifyListeners();
|
|
|
|
final result = await _profileRepository.getProfile();
|
|
|
|
switch (result) {
|
|
case Ok<ProfileResponse>():
|
|
_profileData = result.value.data;
|
|
break;
|
|
case Error<ProfileResponse>():
|
|
_errorMessage = result.error.toString();
|
|
break;
|
|
}
|
|
_isLoading = false;
|
|
notifyListeners();
|
|
_errorMessage = null;
|
|
notifyListeners();
|
|
}
|
|
|
|
Future<void> getCompanyProfile() async {
|
|
_isLoading = true;
|
|
_errorMessage = null;
|
|
notifyListeners();
|
|
|
|
final result = await _profileRepository.getCompanyProfile();
|
|
|
|
switch (result) {
|
|
case Ok<CompanyProfileResponse>():
|
|
_companyProfileData = result.value.data;
|
|
_maybeStartAiOnboarding(_companyProfileData);
|
|
break;
|
|
case Error<CompanyProfileResponse>():
|
|
_errorMessage = result.error.toString();
|
|
break;
|
|
}
|
|
_isLoading = false;
|
|
notifyListeners();
|
|
_errorMessage = null;
|
|
notifyListeners();
|
|
}
|
|
|
|
/// Best-effort AI onboarding once the company profile is ready. Fire-and-
|
|
/// forget: onboarding is asynchronous on the AI side and the fingerprint
|
|
/// guard in [CompanyAiRepository] keeps it from re-running unnecessarily, so
|
|
/// the profile screen never blocks or surfaces errors for it.
|
|
void _maybeStartAiOnboarding(CompanyProfileData? company) {
|
|
if (company == null) {
|
|
return;
|
|
}
|
|
unawaited(
|
|
_companyAiRepository.maybeStartOnboarding(
|
|
documentFileIds: company.documentFileIds ?? const [],
|
|
website: company.website,
|
|
),
|
|
);
|
|
}
|
|
|
|
Future<void> logout() async {
|
|
_errorMessage = null;
|
|
notifyListeners();
|
|
|
|
final result = await _authRepository.logout();
|
|
|
|
switch (result) {
|
|
case Ok<LogoutResponse>():
|
|
await _authRepository.localLogout();
|
|
_loggedOut = true;
|
|
break;
|
|
case Error<LogoutResponse>():
|
|
_errorMessage = result.error.toString();
|
|
break;
|
|
}
|
|
|
|
notifyListeners();
|
|
_errorMessage = null;
|
|
_loggedOut = false;
|
|
notifyListeners();
|
|
}
|
|
|
|
Future<void> updateProfileKeyWords({required List<String> keyWords}) async {
|
|
_isLoading = true;
|
|
_errorMessage = null;
|
|
notifyListeners();
|
|
final result = await _profileRepository.updateProfileKeyWords(
|
|
keyWords: keyWords,
|
|
);
|
|
switch (result) {
|
|
case Ok<ProfileResponse>():
|
|
_profileData = result.value.data;
|
|
break;
|
|
case Error<ProfileResponse>():
|
|
_errorMessage = result.error.toString();
|
|
break;
|
|
}
|
|
_isLoading = false;
|
|
notifyListeners();
|
|
_errorMessage = null;
|
|
notifyListeners();
|
|
}
|
|
}
|