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 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> 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 userData = userDoc.data()! as Map; List? skills; if (skillsSought) { skills = userData[Constants.dbFieldUsersSkillsSought]; } else { skills = userData[Constants.dbFieldUsersSkills]; } return convertSkillStringToEnum(skills); } return []; } static List convertSkillStringToEnum(List? skills) { if (skills != null && skills.isNotEmpty) { // Convert skills from strings to enum values List userSkills = skills .map((skill) => SkillOption.values .firstWhere((x) => x.toString() == 'SkillOption.$skill')) .toList(); return userSkills; } return []; } static List convertVisionStringToEnum(List? visions) { if (visions != null && visions.isNotEmpty) { List userVisions = visions .map((vision) => VisionOption.values.firstWhere((x) => x.toString() == vision)) .toList(); return userVisions; } return []; } static List convertWorkValuesStringToEnum( List? values) { if (values != null && values.isNotEmpty) { List userWorkValues = values .map((workValue) => WorkValueOption.values .firstWhere((x) => x.toString() == workValue)) .toList(); return userWorkValues; } return []; } static Future saveSkillsToFirebase(List selectedOptions, bool skillsSought, String userId) async { try { // Convert enum values to strings, removing leading EnumType with split List 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 getUserProfileFromDocument( DocumentSnapshot userDoc) async { Map data = userDoc.data() as Map; List skillsOffered = UserService.convertSkillStringToEnum( data[Constants.dbFieldUsersSkills]); List skillsSought = UserService.convertSkillStringToEnum( data[Constants.dbFieldUsersSkillsSought]); List visions = UserService.convertVisionStringToEnum( data[Constants.dbFieldUsersVisions]); List 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 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 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, 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 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>> getUsersStream() { return FirebaseFirestore.instance .collection(Constants.dbCollectionUsers) .snapshots() .map((snapshot) { return snapshot.docs.map((doc) { // iterate each user final user = doc.data(); //return user return user; }).toList(); }); } // Get list of matched user ids for a given user static Future> getMatchedUserIds(String userId) async { List 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(); final otherUserId = data['otherUserId'] as String?; if (otherUserId != null && otherUserId.isNotEmpty) { matchedUserIds.add(otherUserId); } // assuming the match document ID is the matched user's ID // it would just be an one liner: // matchedUserIds.add(doc.id); } return matchedUserIds; } // Get matched users data for a given user as stream static Stream>> 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(); }); } }