cofounderella/lib/services/user_service.dart

347 lines
11 KiB
Dart

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:collection/collection.dart';
import 'package:firebase_auth/firebase_auth.dart';
import '../constants.dart';
import '../enumerations.dart';
import '../models/language.dart';
import '../models/location.dart';
import '../models/user_profile.dart';
class UserService {
UserService._(); // Private constructor to prevent instantiation
static Future<void> saveUserRegistrationData(UserCredential userCredential,
String email, String firstname, String lastname) async {
// create full name
String fullName = (firstname.isNotEmpty && lastname.isNotEmpty)
? '$firstname $lastname'
: (firstname.isNotEmpty
? firstname
: (lastname.isNotEmpty ? lastname : ''));
// save user info to users document
await FirebaseFirestore.instance
.collection(Constants.dbCollectionUsers)
.doc(userCredential.user!.uid)
.set(
{
Constants.dbFieldUsersID: userCredential.user!.uid,
Constants.dbFieldUsersEmail: email,
Constants.dbFieldUsersFirstName: firstname,
Constants.dbFieldUsersLastName: lastname,
Constants.dbFieldUsersName: fullName,
},
);
}
static Future<List<SkillOption>> getSkillsFromFirebase(
bool skillsSought, String userId) async {
// Fetch skills from Firestore
DocumentSnapshot userDoc = await FirebaseFirestore.instance
.collection(Constants.dbCollectionUsers)
.doc(userId)
.get();
if (userDoc.exists && userDoc.data() != null) {
Map<String, dynamic> userData = userDoc.data()! as Map<String, dynamic>;
List<dynamic>? skills;
if (skillsSought) {
skills = userData[Constants.dbFieldUsersSkillsSought];
} else {
skills = userData[Constants.dbFieldUsersSkills];
}
return convertSkillStringToEnum(skills);
}
return [];
}
static List<SkillOption> convertSkillStringToEnum(List<dynamic>? skills) {
List<SkillOption> userSkills = [];
if (skills != null && skills.isNotEmpty) {
// Convert skills from strings to enum values
for (var skill in skills) {
try {
SkillOption skillOption = SkillOption.values.firstWhere(
(x) => x.toString() == 'SkillOption.$skill',
);
userSkills.add(skillOption);
} catch (e) {
// Ignore invalid values
continue;
}
}
}
return userSkills;
}
static List<SectorOption> convertSectorStringToEnum(List<dynamic>? sectors) {
if (sectors != null && sectors.isNotEmpty) {
List<SectorOption> userSectors = sectors
.map((sector) =>
SectorOption.values.firstWhere((x) => x.toString() == sector))
.toList();
return userSectors;
}
return [];
}
static List<VisionOption> convertVisionStringToEnum(List<dynamic>? visions) {
if (visions != null && visions.isNotEmpty) {
List<VisionOption> userVisions = visions
.map((vision) =>
VisionOption.values.firstWhere((x) => x.toString() == vision))
.toList();
return userVisions;
}
return [];
}
static List<WorkValueOption> convertWorkValuesStringToEnum(
List<dynamic>? values) {
if (values != null && values.isNotEmpty) {
List<WorkValueOption> userWorkValues = values
.map((workValue) => WorkValueOption.values
.firstWhere((x) => x.toString() == workValue))
.toList();
return userWorkValues;
}
return [];
}
static Future<bool> saveSkillsToFirebase(List<SkillOption> selectedOptions,
bool skillsSought, String userId) async {
try {
// Convert enum values to strings, removing leading EnumType with split
List<String> skills = selectedOptions
.map((option) => option.toString().split('.').last)
.toList();
// Update the corresponding 'skills' field in the user's document
String keyToUpdate = skillsSought
? Constants.dbFieldUsersSkillsSought
: Constants.dbFieldUsersSkills;
FirebaseFirestore.instance
.collection(Constants.dbCollectionUsers)
.doc(userId)
.update({keyToUpdate: skills});
return true;
} catch (e) {
return false;
}
}
/// Get UserProfile from Document
static Future<UserProfile> getUserProfileFromDocument(
DocumentSnapshot userDoc) async {
Map<String, dynamic> data = userDoc.data() as Map<String, dynamic>;
List<SkillOption> skillsOffered = UserService.convertSkillStringToEnum(
data[Constants.dbFieldUsersSkills]);
List<SkillOption> skillsSought = UserService.convertSkillStringToEnum(
data[Constants.dbFieldUsersSkillsSought]);
List<SectorOption> sectors = UserService.convertSectorStringToEnum(
data[Constants.dbFieldUsersSectors]);
List<VisionOption> visions = UserService.convertVisionStringToEnum(
data[Constants.dbFieldUsersVisions]);
List<WorkValueOption> works = UserService.convertWorkValuesStringToEnum(
data[Constants.dbFieldUsersWorkValues]);
RiskTolerance risk =
RiskTolerance.fromString(data[Constants.dbFieldUsersRiskTolerance]);
AvailabilityOption availability =
AvailabilityOption.fromString(data[Constants.dbFieldUsersAvailability]);
CultureOption culture =
CultureOption.fromString(data[Constants.dbFieldUsersCorpCulture]);
CommunicationPreference communication = CommunicationPreference.fromString(
data[Constants.dbFieldUsersCommunication]);
// Retrieve sub collections
QuerySnapshot languagesSnapshot = await userDoc.reference
.collection(Constants.dbCollectionLanguages)
.get();
List<Language> languages = languagesSnapshot.docs
.map((doc) => Language.fromDocument(doc))
.toList();
QuerySnapshot locationsSnapshot = await userDoc.reference
.collection(Constants.dbCollectionLocations)
.get();
final mainDoc = locationsSnapshot.docs
.firstWhereOrNull((doc) => doc.id == Constants.dbDocMainLocation);
final secondaryDoc = locationsSnapshot.docs
.firstWhereOrNull((doc) => doc.id == Constants.dbDocSecondLocation);
final locations = {
Constants.dbDocMainLocation:
mainDoc != null ? MyLocation.fromDocument(mainDoc) : null,
};
if (secondaryDoc != null) {
locations.addAll({
Constants.dbDocSecondLocation: MyLocation.fromDocument(secondaryDoc)
});
}
// Map<String, MyLocation?> locations = {
// for (var doc in locationsSnapshot.docs)
// doc.id: MyLocation.fromDocument(doc)
// };
return UserProfile(
id: userDoc.id,
uid: data[Constants.dbFieldUsersID] ?? '',
email: data[Constants.dbFieldUsersEmail] ?? '',
name: data[Constants.dbFieldUsersName] ?? '',
firstName: data[Constants.dbFieldUsersFirstName] ?? '',
lastName: data[Constants.dbFieldUsersLastName] ?? '',
skills: skillsOffered,
skillsSought: skillsSought,
sectors: sectors,
visions: visions,
risk: risk,
availability: availability,
culture: culture,
communication: communication,
workValues: works,
profilePictureUrl: data[Constants.dbFieldUsersProfilePic],
bio: data[Constants.dbFieldUsersBio],
gender: Gender.values[data[Constants.dbFieldUsersGender] ?? 0],
born: data[Constants.dbFieldUsersYearBorn],
languages: languages,
locations: locations,
);
}
/// Get UserProfile for given [userId]
static Future<UserProfile> getUserProfileById(String userId) async {
FirebaseFirestore firestore = FirebaseFirestore.instance;
DocumentSnapshot userDoc = await firestore
.collection(Constants.dbCollectionUsers)
.doc(userId)
.get();
UserProfile result = await getUserProfileFromDocument(userDoc);
return result;
}
/// Get users stream
static Stream<List<Map<String, dynamic>>> getUsersStream() {
return FirebaseFirestore.instance
.collection(Constants.dbCollectionUsers)
.snapshots()
.map((snapshot) {
return snapshot.docs.map((doc) {
// iterate and return each user
final user = doc.data();
return user;
}).toList();
});
}
/// Get list of matched user ids for a given [userId]
static Future<List<String>> getMatchedUserIds(String userId) async {
List<String> matchedUserIds = [];
final snapshot = await FirebaseFirestore.instance
.collection(Constants.dbCollectionUsers)
.doc(userId)
.collection(Constants.dbCollectionMatches)
.get();
for (var doc in snapshot.docs) {
final data = doc.data();
String? otherUserId = data['otherUserId'];
if (otherUserId != null && otherUserId.isNotEmpty) {
matchedUserIds.add(otherUserId);
}
}
return matchedUserIds;
}
/// Get matched users data for a given [userId] as stream
static Stream<List<Map<String, dynamic>>> getMatchedUsersStream(
String userId) {
return FirebaseFirestore.instance
.collection(Constants.dbCollectionUsers)
.doc(userId)
.collection(Constants.dbCollectionMatches)
.snapshots()
.asyncMap((snapshot) async {
final matchedUserIds = snapshot.docs
.map((doc) => doc.data()['otherUserId'] as String?)
.where((otherUserId) => otherUserId != null && otherUserId.isNotEmpty)
.toList();
if (matchedUserIds.isEmpty) {
return [];
}
final matchedUsersSnapshot = await FirebaseFirestore.instance
.collection(Constants.dbCollectionUsers)
.where(FieldPath.documentId, whereIn: matchedUserIds)
.get();
return matchedUsersSnapshot.docs.map((doc) => doc.data()).toList();
});
}
/// Checks if a match between currentUser and [userId] exists.
/// Returns false in case of an error.
static Future<bool> hasMatch(String currentUserId, String userId) async {
try {
DocumentSnapshot matchDoc = await FirebaseFirestore.instance
.collection(Constants.dbCollectionUsers)
.doc(currentUserId)
.collection(Constants.dbCollectionMatches)
.doc(userId)
.get();
return matchDoc.exists;
} catch (e) {
return false;
}
}
static Future<bool> saveSectorsToFirebase(
List<SectorOption> sectors, String userId) async {
try {
List<String> sectorStrings = sectors.map((x) => x.toString()).toList();
await FirebaseFirestore.instance
.collection(Constants.dbCollectionUsers)
.doc(userId)
.update({
Constants.dbFieldUsersSectors: sectorStrings,
});
return true;
} catch (e) {
return false;
}
}
static Future<List<SectorOption>> getSectorsFromFirebase(
String userId) async {
try {
DocumentSnapshot userDoc = await FirebaseFirestore.instance
.collection(Constants.dbCollectionUsers)
.doc(userId)
.get();
if (userDoc.exists && userDoc.data() != null) {
var data = userDoc.data() as Map<String, dynamic>;
List<dynamic> sectors = data[Constants.dbFieldUsersSectors] ?? [];
return sectors
.map((x) => SectorOption.values
.firstWhere((option) => option.toString() == x))
.toList();
} else {
return [];
}
} catch (e) {
throw Exception('Error fetching sectors from Firebase: $e');
}
}
}