364 lines
12 KiB
Dart
364 lines
12 KiB
Dart
import 'dart:developer';
|
|
import 'package:get/get.dart';
|
|
import 'package:onufitness/constants/api_endpoints.dart';
|
|
import 'package:onufitness/screens/echoboard/models/goal_badges_response_model.dart';
|
|
import 'package:onufitness/screens/echoboard/models/post_model.dart';
|
|
import 'package:onufitness/screens/echoboard/models/user_social_profile_response_model.dart';
|
|
import 'package:onufitness/services/api_services/base_api_services.dart';
|
|
import 'package:onufitness/utils/custom_sneakbar.dart';
|
|
|
|
class ProfileController extends GetxController {
|
|
RxBool isRecentAcrivityLoading = false.obs;
|
|
RxBool isLoadingMoreRecentActivity = false.obs;
|
|
RxBool isProfileLoading = false.obs;
|
|
RxString selectedUserId = "".obs;
|
|
|
|
// Pagination variables for recent activities
|
|
RxInt currentRecentActivityPage = 1.obs;
|
|
RxInt recentActivityPageSize = 5.obs;
|
|
RxBool hasMoreRecentActivities = true.obs;
|
|
|
|
// Response models
|
|
PostModel postModel = PostModel();
|
|
Rx<UserSocialProfileResponseModel> userSocialProfile =
|
|
UserSocialProfileResponseModel().obs;
|
|
|
|
// Cache map for storing posts with their IDs as keys
|
|
final RxMap<String, SocialPostItem> postsCache =
|
|
<String, SocialPostItem>{}.obs;
|
|
final posts = <SocialPostItem>[].obs;
|
|
|
|
Future<bool> fetchRecentActivity({bool loadMore = false}) async {
|
|
if (loadMore) {
|
|
// If already loading more or no more posts to load, return
|
|
if (isLoadingMoreRecentActivity.value || !hasMoreRecentActivities.value) {
|
|
return false;
|
|
}
|
|
isLoadingMoreRecentActivity(true);
|
|
} else {
|
|
// First load
|
|
isRecentAcrivityLoading(true);
|
|
currentRecentActivityPage.value = 1;
|
|
postsCache.value = {};
|
|
postModel = PostModel();
|
|
posts.value = [];
|
|
}
|
|
|
|
bool ret = false;
|
|
|
|
try {
|
|
final url =
|
|
"${ApiUrl.getRecentActivity}-$selectedUserId?PageNumber=${currentRecentActivityPage.value}&PageSize=${recentActivityPageSize.value}";
|
|
final response = await ApiBase.getRequest(extendedURL: url);
|
|
|
|
log("Posts API Statuscode: ${response.statusCode}");
|
|
final fetchedModel = postModelFromJson(response.body);
|
|
|
|
if (response.statusCode == 200 && fetchedModel.isSuccess == true) {
|
|
final newItems = fetchedModel.data?.items ?? [];
|
|
|
|
// Check if there are more items to load
|
|
if (newItems.length < recentActivityPageSize.value) {
|
|
hasMoreRecentActivities(false);
|
|
}
|
|
|
|
if (newItems.isNotEmpty) {
|
|
for (var post in newItems) {
|
|
if (post.postId != null) {
|
|
postsCache[post.postId.toString()] = post;
|
|
}
|
|
}
|
|
|
|
posts.addAll(newItems);
|
|
|
|
// Update page number for next request
|
|
currentRecentActivityPage.value++;
|
|
}
|
|
|
|
// Save the post model for pagination metadata
|
|
if (!loadMore) {
|
|
postModel = fetchedModel;
|
|
}
|
|
|
|
ret = true;
|
|
} else {
|
|
ret = false;
|
|
}
|
|
} catch (e) {
|
|
log("Exception in fetchPosts: $e");
|
|
customSnackbar(title: "Error", message: "Failed to fetch posts.");
|
|
ret = false;
|
|
} finally {
|
|
if (loadMore) {
|
|
isLoadingMoreRecentActivity(false);
|
|
} else {
|
|
isRecentAcrivityLoading(false);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Method to reset pagination
|
|
void resetRecentActivityPagination() {
|
|
currentRecentActivityPage.value = 1;
|
|
hasMoreRecentActivities.value = true;
|
|
}
|
|
|
|
// Get Social Profile info
|
|
Future<bool> getUserSocialProfileInfo() async {
|
|
isProfileLoading(true);
|
|
bool result = false;
|
|
|
|
try {
|
|
final response = await ApiBase.getRequest(
|
|
extendedURL: "${ApiUrl.getSocialProfileInfo}/$selectedUserId",
|
|
);
|
|
|
|
if (response.statusCode >= 200 && response.statusCode < 300) {
|
|
userSocialProfile.value = userSocialProfileResponseModelFromJson(
|
|
response.body,
|
|
);
|
|
|
|
if (userSocialProfile.value.isSuccess == true) {
|
|
log("User Social Profile fetched successfully");
|
|
result = true;
|
|
} else {
|
|
log(
|
|
"User Social Profile API returned success=false: ${userSocialProfile.value.message}",
|
|
);
|
|
result = false;
|
|
}
|
|
} else {
|
|
log(
|
|
"User Social Profile API failed with status: ${response.statusCode}",
|
|
);
|
|
result = false;
|
|
}
|
|
} catch (e) {
|
|
log("Exception in getUserSocialProfileInfo: $e");
|
|
customSnackbar(title: "Error", message: "Failed to fetch user profile.");
|
|
result = false;
|
|
} finally {
|
|
isProfileLoading(false);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// Update post reaction in ProfileController's posts
|
|
void updatePostReaction(String postId, int reactionTypeId, bool isRemove) {
|
|
log("🔄 ProfileController: Updating post reaction for postId: $postId");
|
|
|
|
final postIndex = posts.indexWhere(
|
|
(post) => post.postId.toString() == postId,
|
|
);
|
|
|
|
if (postIndex == -1) return;
|
|
final oldPost = posts[postIndex];
|
|
final currentReactions = oldPost.totalPostReactions ?? 0;
|
|
final isAlreadyLiked = oldPost.postReactionTypeId != null;
|
|
|
|
int updatedCount = currentReactions;
|
|
|
|
if (isRemove && isAlreadyLiked) {
|
|
updatedCount = (currentReactions - 1).clamp(0, double.infinity).toInt();
|
|
} else if (!isRemove && !isAlreadyLiked) {
|
|
updatedCount = currentReactions + 1;
|
|
}
|
|
|
|
final updatedPost = SocialPostItem(
|
|
postId: oldPost.postId,
|
|
userId: oldPost.userId,
|
|
content: oldPost.content,
|
|
mediaFiles: oldPost.mediaFiles,
|
|
profilePicture: oldPost.profilePicture,
|
|
fullName: oldPost.fullName,
|
|
userTypeName: oldPost.userTypeName,
|
|
createdAt: oldPost.createdAt,
|
|
totalPostComments: oldPost.totalPostComments,
|
|
postReactionTypeId: isRemove ? null : reactionTypeId,
|
|
totalPostReactions: updatedCount,
|
|
poll: oldPost.poll,
|
|
);
|
|
|
|
posts[postIndex] = updatedPost;
|
|
update();
|
|
posts.refresh();
|
|
} // Update post comment count in ProfileController's posts
|
|
|
|
void updatePostCommentCount(String postId, int increment) {
|
|
log(
|
|
"🔄 ProfileController: Updating comment count for postId: $postId by $increment",
|
|
);
|
|
|
|
final postIndex = posts.indexWhere(
|
|
(post) => post.postId.toString() == postId,
|
|
);
|
|
|
|
if (postIndex != -1) {
|
|
final currentPost = posts[postIndex];
|
|
final currentComments = currentPost.totalPostComments ?? 0;
|
|
final updatedCount =
|
|
(currentComments + increment).clamp(0, double.infinity).toInt();
|
|
|
|
final updatedPost = currentPost.copyWith(totalPostComments: updatedCount);
|
|
|
|
posts[postIndex] = updatedPost;
|
|
|
|
// Also update in cache
|
|
postsCache[postId] = updatedPost;
|
|
|
|
posts.refresh();
|
|
update();
|
|
|
|
log("✅ ProfileController: Updated comment count to: $updatedCount");
|
|
}
|
|
}
|
|
|
|
void updatePostPollResults(dynamic voteResponse) {
|
|
log("🔄 ProfileController: Updating poll results");
|
|
|
|
final pollPostId = voteResponse['pollPostID'];
|
|
if (pollPostId == null) return;
|
|
|
|
final postIndex = posts.indexWhere(
|
|
(post) => post.poll?.pollPostId == pollPostId,
|
|
);
|
|
|
|
if (postIndex != -1) {
|
|
final currentPost = posts[postIndex];
|
|
if (currentPost.poll == null) return;
|
|
|
|
final totalPollVotes = voteResponse['totalPollVotes'] as int? ?? 0;
|
|
final options = voteResponse['options'] as List<dynamic>? ?? [];
|
|
|
|
// Create updated post with new poll data
|
|
final updatedPost = SocialPostItem(
|
|
postId: currentPost.postId,
|
|
userId: currentPost.userId,
|
|
firstName: currentPost.firstName,
|
|
lastName: currentPost.lastName,
|
|
fullName: currentPost.fullName,
|
|
profilePicture: currentPost.profilePicture,
|
|
userTypeId: currentPost.userTypeId,
|
|
userTypeName: currentPost.userTypeName,
|
|
coachTypeName: currentPost.coachTypeName,
|
|
coachRequestStatus: currentPost.coachRequestStatus,
|
|
content: currentPost.content,
|
|
postTypeId: currentPost.postTypeId,
|
|
postVisibilityId: currentPost.postVisibilityId,
|
|
deviceTypeId: currentPost.deviceTypeId,
|
|
isTribe: currentPost.isTribe,
|
|
tribeId: currentPost.tribeId,
|
|
createdAt: currentPost.createdAt,
|
|
updateAt: currentPost.updateAt,
|
|
mediaFiles: currentPost.mediaFiles,
|
|
comments: currentPost.comments,
|
|
totalPostComments: currentPost.totalPostComments,
|
|
totalPostReactions: currentPost.totalPostReactions,
|
|
postReactionTypeId: currentPost.postReactionTypeId,
|
|
);
|
|
|
|
// Update poll data
|
|
updatedPost.poll = Poll(
|
|
pollPostId: currentPost.poll!.pollPostId,
|
|
question: voteResponse['question'] ?? currentPost.poll!.question,
|
|
expiryDate:
|
|
voteResponse['expiryDate'] != null
|
|
? DateTime.parse(voteResponse['expiryDate'])
|
|
: currentPost.poll!.expiryDate,
|
|
totalPollVotes: totalPollVotes,
|
|
options: [],
|
|
);
|
|
|
|
// Update poll options
|
|
for (var socketOption in options) {
|
|
final optionMap = socketOption as Map<String, dynamic>;
|
|
final originalOption = currentPost.poll!.options?.firstWhere(
|
|
(opt) => opt.optionId == optionMap['optionID'],
|
|
orElse: () => Option(),
|
|
);
|
|
|
|
updatedPost.poll!.options!.add(
|
|
Option(
|
|
optionId: optionMap['optionID'],
|
|
pollId: optionMap['pollID'],
|
|
userId: optionMap['userID'],
|
|
optionLabel:
|
|
optionMap['optionLabel'] ?? originalOption?.optionLabel,
|
|
totalOptionPollVotes: optionMap['totalOptionPollVotes'] ?? 0,
|
|
percentageOptionPollVotes:
|
|
optionMap['percentageOptionPollVotes'] ?? 0,
|
|
hasUserVoted: originalOption?.hasUserVoted ?? false,
|
|
),
|
|
);
|
|
}
|
|
|
|
// Update in ProfileController
|
|
posts[postIndex] = updatedPost;
|
|
postsCache[updatedPost.postId.toString()] = updatedPost;
|
|
|
|
posts.refresh();
|
|
update();
|
|
|
|
log(
|
|
"✅ ProfileController: Updated poll results with total votes: $totalPollVotes",
|
|
);
|
|
}
|
|
}
|
|
|
|
void syncPostFromEchoBoard(SocialPostItem updatedPost) {
|
|
if (updatedPost.postId == null) return;
|
|
|
|
final postId = updatedPost.postId.toString();
|
|
|
|
// Find and update in main posts list
|
|
final postIndex = posts.indexWhere(
|
|
(post) => post.postId.toString() == postId,
|
|
);
|
|
|
|
if (postIndex != -1) {
|
|
posts[postIndex] = updatedPost;
|
|
log(
|
|
"✅ ProfileController: Synced post at index $postIndex from EchoBoardController",
|
|
);
|
|
}
|
|
|
|
// Update in cache
|
|
postsCache[postId] = updatedPost;
|
|
|
|
// Force UI update
|
|
posts.refresh();
|
|
update();
|
|
|
|
log("✅ ProfileController: Post $postId synced from EchoBoardController");
|
|
}
|
|
|
|
//........................................................................................
|
|
//......Completed Coal Badge api call..................................................................................
|
|
//........................................................................................
|
|
Future<List<SingleGoalCompletedModel>> fetchCompletedGoalsForBadges({
|
|
required String userId,
|
|
}) async {
|
|
try {
|
|
final response = await ApiBase.getRequest(
|
|
extendedURL: "${ApiUrl.fetchCompletedGoalsForBadges}/$userId",
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final result = completedGoalForBadgesResponseModelFromJson(
|
|
response.body,
|
|
);
|
|
|
|
return result.data ?? [];
|
|
} else {
|
|
return [];
|
|
}
|
|
} catch (e) {
|
|
log("Error fetching completed goals for badges: $e");
|
|
return [];
|
|
}
|
|
}
|
|
}
|