MIF_E31222656/lib/screens/community/services/group_service.dart

302 lines
8.3 KiB
Dart

import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:tugas_akhir_supabase/screens/community/models/group.dart';
import 'package:tugas_akhir_supabase/screens/community/models/group_member.dart';
class GroupService {
final _supabase = Supabase.instance.client;
// Cache
final Map<String, Group> _groupCache = {};
// Get current user ID
String? get currentUserId => _supabase.auth.currentUser?.id;
// Load all groups that the current user is a member of
Future<List<Group>> getUserGroups() async {
if (currentUserId == null) {
print('[ERROR] getUserGroups: currentUserId is null');
return [];
}
try {
print(
'[DEBUG] getUserGroups: Querying group_members for user: $currentUserId',
);
// Join group_members with groups to get all groups for current user
final response = await _supabase
.from('group_members')
.select('groups(*)')
.eq('user_id', currentUserId!)
.eq('is_active', true)
.order('joined_at');
print('[DEBUG] getUserGroups: Raw response: $response');
if (response.isEmpty) {
print(
'[DEBUG] getUserGroups: No groups found in response, trying fallback',
);
// Fallback: Try to get default group directly
return await _getDefaultGroup();
}
final List<Group> groups = [];
for (final item in response) {
if (item['groups'] == null) {
print('[WARNING] getUserGroups: Null groups data in item: $item');
continue;
}
final groupData = item['groups'] as Map<String, dynamic>;
print('[DEBUG] getUserGroups: Processing group: ${groupData['name']}');
final group = Group.fromMap(groupData);
// Update cache
_groupCache[group.id] = group;
groups.add(group);
}
print('[INFO] getUserGroups: Found ${groups.length} groups for user');
if (groups.isEmpty) {
// If no groups found via membership, try to get default group
print(
'[DEBUG] getUserGroups: No groups found via membership, trying to get default group',
);
return await _getDefaultGroup();
}
return groups;
} catch (e) {
print('[ERROR] Failed to load user groups: $e');
// Try fallback on error
return await _getDefaultGroup();
}
}
// Fallback method to get at least the default group
Future<List<Group>> _getDefaultGroup() async {
try {
print('[DEBUG] Trying to get default group directly');
final response = await _supabase
.from('groups')
.select('*')
.eq('is_default', true)
.limit(1);
print('[DEBUG] Default group response: $response');
if (response.isNotEmpty) {
final groupData = response[0];
final group = Group.fromMap(groupData);
print('[INFO] Found default group: ${group.name}');
// Auto-join user to this group if needed
if (currentUserId != null) {
_joinGroupIfNotMember(group.id);
}
// Update cache
_groupCache[group.id] = group;
return [group];
}
print('[WARNING] No default group found');
return [];
} catch (e) {
print('[ERROR] Failed to get default group: $e');
return [];
}
}
// Utility to join user to group if not already a member
Future<void> _joinGroupIfNotMember(String groupId) async {
try {
final isMember = await isUserGroupMember(groupId);
if (!isMember && currentUserId != null) {
print('[INFO] Auto-joining user to group: $groupId');
final member = GroupMember(groupId: groupId, userId: currentUserId!);
await _supabase.from('group_members').insert(member.toMap());
}
} catch (e) {
print('[ERROR] Failed to auto-join group: $e');
}
}
// Get details of a specific group
Future<Group?> getGroupDetails(String groupId) async {
// Try cache first
if (_groupCache.containsKey(groupId)) {
return _groupCache[groupId];
}
try {
final response =
await _supabase
.from('groups')
.select('*, group_members(count)')
.eq('id', groupId)
.single();
final memberCount = response['group_members']?[0]?['count'] ?? 0;
final groupData = Map<String, dynamic>.from(response);
groupData['member_count'] = memberCount;
final group = Group.fromMap(groupData);
// Update cache
_groupCache[group.id] = group;
return group;
} catch (e) {
print('[ERROR] Failed to get group details: $e');
return null;
}
}
// Check if user is a member of a group
Future<bool> isUserGroupMember(String groupId, {String? userId}) async {
final targetUserId = userId ?? currentUserId;
if (targetUserId == null) return false;
try {
final response =
await _supabase
.from('group_members')
.select('id')
.eq('group_id', groupId)
.eq('user_id', targetUserId)
.eq('is_active', true)
.maybeSingle();
return response != null;
} catch (e) {
print('[ERROR] Failed to check group membership: $e');
return false;
}
}
// Join a group
Future<bool> joinGroup(String groupId) async {
if (currentUserId == null) return false;
// Check if already a member
final isMember = await isUserGroupMember(groupId);
if (isMember) return true; // Already a member
try {
// Create new group member
final member = GroupMember(groupId: groupId, userId: currentUserId!);
await _supabase.from('group_members').insert(member.toMap());
// Clear cache for this group to refresh member count
_groupCache.remove(groupId);
return true;
} catch (e) {
print('[ERROR] Failed to join group: $e');
return false;
}
}
// Leave a group
Future<bool> leaveGroup(String groupId) async {
if (currentUserId == null) return false;
try {
// Check if this is the default group
final group = await getGroupDetails(groupId);
if (group?.isDefault == true) {
// Can't leave default group
return false;
}
// Mark as inactive instead of deleting
await _supabase
.from('group_members')
.update({'is_active': false})
.eq('group_id', groupId)
.eq('user_id', currentUserId!);
// Clear cache for this group
_groupCache.remove(groupId);
return true;
} catch (e) {
print('[ERROR] Failed to leave group: $e');
return false;
}
}
// Get all public groups
Future<List<Group>> getPublicGroups() async {
try {
final response = await _supabase
.from('groups')
.select('*, group_members(count)')
.eq('is_public', true)
.order('created_at');
final List<Group> groups = [];
for (final item in response) {
final memberCount = item['group_members']?[0]?['count'] ?? 0;
final groupData = Map<String, dynamic>.from(item);
groupData['member_count'] = memberCount;
final group = Group.fromMap(groupData);
// Update cache
_groupCache[group.id] = group;
groups.add(group);
}
return groups;
} catch (e) {
print('[ERROR] Failed to load public groups: $e');
return [];
}
}
// Get group member role for current user
Future<String> getUserRole(String groupId) async {
if (currentUserId == null) return 'none';
try {
final response =
await _supabase
.from('group_members')
.select('role')
.eq('group_id', groupId)
.eq('user_id', currentUserId!)
.eq('is_active', true)
.maybeSingle();
if (response == null) return 'none';
return response['role'] as String? ?? 'member';
} catch (e) {
print('[ERROR] Failed to get user role: $e');
return 'none';
}
}
// Check if user has admin permissions
Future<bool> isGroupAdmin(String groupId) async {
final role = await getUserRole(groupId);
return role == 'admin';
}
// Check if user has moderator permissions
Future<bool> isGroupModerator(String groupId) async {
final role = await getUserRole(groupId);
return role == 'admin' || role == 'moderator';
}
}