2026-01-13 11:36:24 +05:30

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 [];
}
}
}