import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_web/pages/common/bloc/project_cubit.dart'; import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.dart'; import 'package:syncrow_web/pages/space_tree/bloc/space_tree_state.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart'; import 'package:syncrow_web/services/space_mana_api.dart'; import 'package:syncrow_web/utils/constants/temp_const.dart'; class SpaceTreeBloc extends Bloc { String selectedCommunityId = 'aff21a57-2f91-4e5c-b99b-0182c3ab65a9'; String selectedSpaceId = '25c96044-fadf-44bb-93c7-3c079e527ce6'; final ProjectCubit projectCubit; SpaceTreeBloc(this.projectCubit) : super(const SpaceTreeState()) { on(_fetchSpaces); on(_onCommunityExpanded); on(_onSpaceExpanded); on(_onCommunitySelected); on(_onSpaceSelected); on(_onSearch); } _fetchSpaces(InitialEvent event, Emitter emit) async { emit(SpaceTreeLoadingState()); try { final projectUuid = projectCubit.state; List communities = await CommunitySpaceManagementApi() .fetchCommunities(projectUuid ?? TempConst.projectId); List updatedCommunities = await Future.wait( communities.map((community) async { List spaces = await CommunitySpaceManagementApi() .getSpaceHierarchy( community.uuid, projectUuid ?? TempConst.projectId); return CommunityModel( uuid: community.uuid, createdAt: community.createdAt, updatedAt: community.updatedAt, name: community.name, description: community.description, spaces: spaces, region: community.region, ); }).toList(), ); emit(state.copyWith( communitiesList: updatedCommunities, expandedCommunity: [], expandedSpaces: [])); } catch (e) { emit(SpaceTreeErrorState('Error loading communities and spaces: $e')); } } _onCommunityExpanded( OnCommunityExpanded event, Emitter emit) async { try { List updatedExpandedCommunityList = List.from(state.expandedCommunities); if (updatedExpandedCommunityList.contains(event.communityId)) { updatedExpandedCommunityList.remove(event.communityId); } else { updatedExpandedCommunityList.add(event.communityId); } emit(state.copyWith( expandedCommunity: updatedExpandedCommunityList, )); } catch (e) { emit(const SpaceTreeErrorState('Something went wrong')); } } _onSpaceExpanded(OnSpaceExpanded event, Emitter emit) async { try { List updatedExpandedSpacesList = List.from(state.expandedSpaces); if (updatedExpandedSpacesList.contains(event.spaceId)) { updatedExpandedSpacesList.remove(event.spaceId); } else { updatedExpandedSpacesList.add(event.spaceId); } emit(state.copyWith(expandedSpaces: updatedExpandedSpacesList)); } catch (e) { emit(const SpaceTreeErrorState('Something went wrong')); } } _onCommunitySelected( OnCommunitySelected event, Emitter emit) async { try { List updatedSelectedCommunities = List.from(state.selectedCommunities.toSet().toList()); List updatedSelectedSpaces = List.from(state.selectedSpaces.toSet().toList()); List updatedSoldChecks = List.from(state.soldCheck.toSet().toList()); Map> communityAndSpaces = Map.from(state.selectedCommunityAndSpaces); List childrenIds = _getAllChildIds(event.children); if (!updatedSelectedCommunities.contains(event.communityId)) { // Select the community and all its children updatedSelectedCommunities.add(event.communityId); updatedSelectedSpaces.addAll(childrenIds); } else { // Unselect the community and all its children updatedSelectedCommunities.remove(event.communityId); updatedSelectedSpaces.removeWhere(childrenIds.contains); updatedSoldChecks.removeWhere(childrenIds.contains); } communityAndSpaces[event.communityId] = updatedSelectedSpaces; emit(state.copyWith( selectedCommunities: updatedSelectedCommunities, selectedSpaces: updatedSelectedSpaces, soldCheck: updatedSoldChecks, selectedCommunityAndSpaces: communityAndSpaces)); } catch (e) { emit(const SpaceTreeErrorState('Something went wrong')); } } _onSpaceSelected(OnSpaceSelected event, Emitter emit) async { try { List updatedSelectedCommunities = List.from(state.selectedCommunities.toSet().toList()); List updatedSelectedSpaces = List.from(state.selectedSpaces.toSet().toList()); List updatedSoldChecks = List.from(state.soldCheck.toSet().toList()); Map> communityAndSpaces = Map.from(state.selectedCommunityAndSpaces); List childrenIds = _getAllChildIds(event.children); bool isChildSelected = false; for (String id in childrenIds) { if (updatedSelectedSpaces.contains(id)) { isChildSelected = true; } } if (!updatedSelectedSpaces.contains(event.spaceId) && !updatedSoldChecks.contains(event.spaceId)) { // First click: Select the space and all its children updatedSelectedSpaces.add(event.spaceId); updatedSelectedCommunities.add(event.communityId); if (childrenIds.isNotEmpty) { updatedSelectedSpaces.addAll(childrenIds); } List spaces = _getThePathToChild(event.communityId, event.spaceId); for (String space in spaces) { if (!updatedSelectedSpaces.contains(space) && !updatedSoldChecks.contains(space)) { updatedSoldChecks.add(space); } } } else if (!updatedSoldChecks.contains(event.spaceId) && childrenIds.isNotEmpty && isChildSelected) { // Second click: Unselect space but keep children updatedSelectedSpaces.remove(event.spaceId); updatedSoldChecks.add(event.spaceId); } else { // Third click: Unselect space and all its children updatedSelectedSpaces.remove(event.spaceId); if (childrenIds.isNotEmpty) { updatedSelectedSpaces.removeWhere(childrenIds.contains); updatedSoldChecks.removeWhere(childrenIds.contains); } updatedSoldChecks.remove(event.spaceId); List parents = _getThePathToChild(event.communityId, event.spaceId); if (!_parentSelected(parents, updatedSelectedSpaces)) { updatedSoldChecks.removeWhere(parents.contains); } if (!_anySpacesSelectedInCommunity( event.communityId, updatedSelectedSpaces, updatedSoldChecks)) { updatedSelectedCommunities.remove(event.communityId); } } communityAndSpaces[event.communityId] = updatedSelectedSpaces; emit(state.copyWith( selectedCommunities: updatedSelectedCommunities, selectedSpaces: updatedSelectedSpaces, soldCheck: updatedSoldChecks, selectedCommunityAndSpaces: communityAndSpaces)); emit(state.copyWith(selectedSpaces: updatedSelectedSpaces)); } catch (e) { emit(const SpaceTreeErrorState('Something went wrong')); } } _parentSelected(List parents, List selectedSpaces) { for (String space in parents) { if (selectedSpaces.contains(space)) { return true; } } return false; } _onSearch(SearchQueryEvent event, Emitter emit) async { try { List communities = List.from(state.communityList); List filteredCommunity = []; // Filter communities and expand only those that match the query filteredCommunity = communities.where((community) { final containsQueryInCommunity = community.name .toLowerCase() .contains(event.searchQuery.toLowerCase()); final containsQueryInSpaces = community.spaces.any( (space) => _containsQuery(space, event.searchQuery.toLowerCase())); return containsQueryInCommunity || containsQueryInSpaces; }).toList(); emit(state.copyWith( filteredCommunity: filteredCommunity, isSearching: event.searchQuery.isNotEmpty)); } catch (e) { emit(const SpaceTreeErrorState('Something went wrong')); } } // Helper function to determine if any space or its children match the search query bool _containsQuery(SpaceModel space, String query) { final matchesSpace = space.name.toLowerCase().contains(query); final matchesChildren = space.children.any((child) => _containsQuery(child, query)); // Recursive check for children return matchesSpace || matchesChildren; } List _getAllChildIds(List spaces) { List ids = []; for (var child in spaces) { ids.add(child.uuid!); ids.addAll(_getAllChildIds(child.children)); } return ids; } bool _anySpacesSelectedInCommunity(String communityId, List selectedSpaces, List partialCheckedList) { bool result = false; for (var community in state.communityList) { if (community.uuid == communityId) { List ids = _getAllChildIds(community.spaces); for (var id in ids) { result = selectedSpaces.contains(id) || partialCheckedList.contains(id); if (result) { return result; } } } } return result; } List _getThePathToChild(String communityId, String selectedSpaceId) { List ids = []; for (var community in state.communityList) { if (community.uuid == communityId) { for (var space in community.spaces) { List list = []; list.add(space.uuid!); ids = _getAllParentsIds(space, selectedSpaceId, List.from(list)); if (ids.isNotEmpty) { return ids; } } } } return ids; } List _getAllParentsIds( SpaceModel child, String spaceId, List listIds) { List ids = listIds; ids.add(child.uuid ?? ''); if (child.uuid == spaceId) { return ids; } if (child.children.isNotEmpty) { for (var space in child.children) { var result = _getAllParentsIds(space, spaceId, List.from(ids)); if (result.isNotEmpty) { return result; } } } ids.removeLast(); return []; } }