diff --git a/lib/pages/spaces_management/bloc/space_management_bloc.dart b/lib/pages/spaces_management/bloc/space_management_bloc.dart index f178dd3a..fefbc849 100644 --- a/lib/pages/spaces_management/bloc/space_management_bloc.dart +++ b/lib/pages/spaces_management/bloc/space_management_bloc.dart @@ -7,20 +7,24 @@ import 'package:syncrow_web/pages/spaces_management/bloc/space_management_state. import 'package:syncrow_web/services/product_api.dart'; import 'package:syncrow_web/services/space_mana_api.dart'; -class SpaceManagementBloc extends Bloc { +class SpaceManagementBloc + extends Bloc { final CommunitySpaceManagementApi _api; final ProductApi _productApi; List? _cachedProducts; - SpaceManagementBloc(this._api, this._productApi) : super(SpaceManagementInitial()) { + SpaceManagementBloc(this._api, this._productApi) + : super(SpaceManagementInitial()) { on(_onLoadCommunityAndSpaces); on(_onUpdateSpacePosition); on(_onCreateCommunity); - on(_onSaveSpaces); - on(_onFetchProducts); + on(_onSelectCommunity); on(_onCommunityDelete); on(_onUpdateCommunity); + on(_onSaveSpaces); + on(_onFetchProducts); + on(_onSelectSpace); } void _onUpdateCommunity( @@ -30,22 +34,23 @@ class SpaceManagementBloc extends Bloc.from(previousState.communities); - for(var community in updatedCommunities){ - if(community.uuid == event.communityUuid){ + final updatedCommunities = + List.from(previousState.communities); + for (var community in updatedCommunities) { + if (community.uuid == event.communityUuid) { community.name = event.name; break; } } emit(SpaceManagementLoaded( - communities: updatedCommunities, - products: previousState.products, - selectedCommunity: previousState.selectedCommunity, - )); - + communities: updatedCommunities, + products: previousState.products, + selectedCommunity: previousState.selectedCommunity, + )); } } else { emit(const SpaceManagementError('Failed to update the community.')); @@ -55,40 +60,42 @@ class SpaceManagementBloc extends Bloc emit, ) async { - if (_cachedProducts != null) { - // Products are already cached, no need to fetch again - return; - } - try { - final products = await _productApi.fetchProducts(); - _cachedProducts = products; // Cache the products locally + _onloadProducts(); } catch (e) { emit(SpaceManagementError('Error fetching products: $e')); } } + Future> _fetchSpacesForCommunity( + String communityUuid) async { + return await _api.getSpaceHierarchy(communityUuid); + } + void _onLoadCommunityAndSpaces( LoadCommunityAndSpacesEvent event, Emitter emit, ) async { emit(SpaceManagementLoading()); try { - if (_cachedProducts == null) { - final products = await _productApi.fetchProducts(); - _cachedProducts = products; - } - - // Fetch all communities + _onloadProducts(); List communities = await _api.fetchCommunities(); List updatedCommunities = await Future.wait( communities.map((community) async { - List spaces = await _api.getSpaceHierarchy(community.uuid); + List spaces = + await _fetchSpacesForCommunity(community.uuid); return CommunityModel( uuid: community.uuid, createdAt: community.createdAt, @@ -101,7 +108,8 @@ class SpaceManagementBloc extends Bloc.from(previousState.communities) - ..add(newCommunity); + final updatedCommunities = + List.from(previousState.communities) + ..add(newCommunity); emit(SpaceManagementLoaded( communities: updatedCommunities, products: _cachedProducts ?? [], - selectedCommunity: newCommunity)); + selectedCommunity: null, + selectedSpace: null)); } } else { emit(const SpaceManagementError('Error creating community')); @@ -158,6 +169,53 @@ class SpaceManagementBloc extends Bloc emit, + ) async { + _handleCommunitySpaceStateUpdate( + emit: emit, + selectedCommunity: event.selectedCommunity, + selectedSpace: null, + ); + } + + void _onSelectSpace( + SelectSpaceEvent event, + Emitter emit, + ) { + _handleCommunitySpaceStateUpdate( + emit: emit, + selectedCommunity: event.selectedCommunity, + selectedSpace: event.selectedSpace, + ); + } + + void _handleCommunitySpaceStateUpdate({ + required Emitter emit, + CommunityModel? selectedCommunity, + SpaceModel? selectedSpace, + }) { + final previousState = state; + emit(SpaceManagementLoading()); + + try { + if (previousState is SpaceManagementLoaded) { + final communities = List.from( + (previousState as dynamic).communities, + ); + emit(SpaceManagementLoaded( + communities: communities, + products: _cachedProducts ?? [], + selectedCommunity: selectedCommunity, + selectedSpace: selectedSpace, + )); + } + } catch (e) { + emit(SpaceManagementError('Error updating state: $e')); + } + } + void _onSaveSpaces( SaveSpacesEvent event, Emitter emit, @@ -166,17 +224,54 @@ class SpaceManagementBloc extends Bloc allSpaces, + String communityUuid, + Emitter emit, + ) { + final communities = List.from(previousState.communities); + + for (var community in communities) { + if (community.uuid == communityUuid) { + community.spaces = allSpaces; + emit(SpaceManagementLoaded( + communities: communities, + products: _cachedProducts ?? [], + selectedCommunity: community, + selectedSpace: null, + )); + return; + } + } + } + Future> saveSpacesHierarchically( List spaces, String communityUuid) async { final orderedSpaces = flattenHierarchy(spaces); @@ -187,7 +282,6 @@ class SpaceManagementBloc extends Bloc get props => [name, description]; } -class FetchProductsEvent extends SpaceManagementEvent {} - -class LoadSpaceHierarchyEvent extends SpaceManagementEvent { - final String communityId; - - const LoadSpaceHierarchyEvent({required this.communityId}); - - @override - List get props => [communityId]; -} - class UpdateCommunityEvent extends SpaceManagementEvent { final String communityUuid; final String name; @@ -106,3 +96,38 @@ class UpdateCommunityEvent extends SpaceManagementEvent { @override List get props => [communityUuid, name]; } + +class SelectCommunityEvent extends SpaceManagementEvent { + final CommunityModel? selectedCommunity; + + const SelectCommunityEvent({ + required this.selectedCommunity, + }); + + @override + List get props => []; +} + +class SelectSpaceEvent extends SpaceManagementEvent { + final CommunityModel? selectedCommunity; + final SpaceModel? selectedSpace; + + const SelectSpaceEvent({ + required this.selectedCommunity, + required this.selectedSpace, + }); + + @override + List get props => []; +} + +class FetchProductsEvent extends SpaceManagementEvent {} + +class LoadSpaceHierarchyEvent extends SpaceManagementEvent { + final String communityId; + + const LoadSpaceHierarchyEvent({required this.communityId}); + + @override + List get props => [communityId]; +} diff --git a/lib/pages/spaces_management/bloc/space_management_state.dart b/lib/pages/spaces_management/bloc/space_management_state.dart index 0264d4e8..1885af41 100644 --- a/lib/pages/spaces_management/bloc/space_management_state.dart +++ b/lib/pages/spaces_management/bloc/space_management_state.dart @@ -17,10 +17,14 @@ class SpaceManagementLoading extends SpaceManagementState {} class SpaceManagementLoaded extends SpaceManagementState { final List communities; final List products; - CommunityModel? selectedCommunity; // Include products in the state + CommunityModel? selectedCommunity; + SpaceModel? selectedSpace; SpaceManagementLoaded( - {required this.communities, required this.products, this.selectedCommunity}); + {required this.communities, + required this.products, + this.selectedCommunity, + this.selectedSpace}); } class SpaceCreationSuccess extends SpaceManagementState { diff --git a/lib/pages/spaces_management/model/space_model.dart b/lib/pages/spaces_management/model/space_model.dart index 6efe19ec..3e38d931 100644 --- a/lib/pages/spaces_management/model/space_model.dart +++ b/lib/pages/spaces_management/model/space_model.dart @@ -44,7 +44,8 @@ class SpaceModel { this.selectedProducts = const [], }) : internalId = internalId ?? const Uuid().v4(); - factory SpaceModel.fromJson(Map json, {String? parentInternalId}) { + factory SpaceModel.fromJson(Map json, + {String? parentInternalId}) { final String internalId = json['internalId'] ?? const Uuid().v4(); final List children = json['children'] != null @@ -56,7 +57,7 @@ class SpaceModel { }).toList() : []; - return SpaceModel( + final instance = SpaceModel( internalId: internalId, uuid: json['uuid'] ?? '', spaceTuyaUuid: json['spaceTuyaUuid'], @@ -72,11 +73,14 @@ class SpaceModel { isPrivate: json['parent']?['isPrivate'] ?? false, invitationCode: json['parent']?['invitationCode'], children: [], - position: Offset(json['parent']?['x'] ?? 0, json['parent']?['y'] ?? 0), + position: + Offset(json['parent']?['x'] ?? 0, json['parent']?['y'] ?? 0), icon: json['parent']?['icon'] ?? Assets.location, ) : null, - community: json['community'] != null ? CommunityModel.fromJson(json['community']) : null, + community: json['community'] != null + ? CommunityModel.fromJson(json['community']) + : null, children: children, icon: json['icon'] ?? Assets.location, position: Offset(json['x'] ?? 0, json['y'] ?? 0), @@ -90,6 +94,20 @@ class SpaceModel { }).toList() : [], ); + + if (json['incomingConnections'] != null && + json['incomingConnections'] is List && + (json['incomingConnections'] as List).isNotEmpty && + instance.parent != null) { + final conn = json['incomingConnections'][0]; + instance.incomingConnection = Connection( + startSpace: instance.parent ?? instance, // Parent space + endSpace: instance, // This space instance + direction: conn['direction'], + ); + } + + return instance; } Map toMap() { diff --git a/lib/pages/spaces_management/view/spaces_management_page.dart b/lib/pages/spaces_management/view/spaces_management_page.dart index 54027066..a540cf3c 100644 --- a/lib/pages/spaces_management/view/spaces_management_page.dart +++ b/lib/pages/spaces_management/view/spaces_management_page.dart @@ -20,8 +20,6 @@ class SpaceManagementPage extends StatefulWidget { } class SpaceManagementPageState extends State { - CommunityModel? selectedCommunity; - SpaceModel? selectedSpace; final CommunitySpaceManagementApi _api = CommunitySpaceManagementApi(); final ProductApi _productApi = ProductApi(); Map> communitySpaces = {}; @@ -36,43 +34,23 @@ class SpaceManagementPageState extends State { @override Widget build(BuildContext context) { return BlocProvider( - create: (context) => - SpaceManagementBloc(_api, _productApi)..add(LoadCommunityAndSpacesEvent()), + create: (context) => SpaceManagementBloc(_api, _productApi) + ..add(LoadCommunityAndSpacesEvent()), child: WebScaffold( - appBarTitle: Text('Space Management', style: Theme.of(context).textTheme.headlineLarge), + appBarTitle: Text('Space Management', + style: Theme.of(context).textTheme.headlineLarge), enableMenuSidebar: false, rightBody: const NavigateHomeGridView(), - scaffoldBody: - BlocBuilder(builder: (context, state) { + scaffoldBody: BlocBuilder( + builder: (context, state) { if (state is SpaceManagementLoading) { return const Center(child: CircularProgressIndicator()); } else if (state is SpaceManagementLoaded) { - int selectedIndex = state.communities.indexWhere( - (community) => community.uuid == selectedCommunity?.uuid, - ); - if (selectedIndex != -1) { - selectedCommunity = state.communities[selectedIndex]; - } else if (state.selectedCommunity != null) { - selectedCommunity = state.selectedCommunity; - } else { - selectedCommunity = null; - selectedSpace = null; - } return LoadedSpaceView( communities: state.communities, - selectedCommunity: selectedCommunity, - selectedSpace: selectedSpace, + selectedCommunity: state.selectedCommunity, + selectedSpace: state.selectedSpace, products: state.products, - onCommunitySelected: (community) { - setState(() { - selectedCommunity = community; - }); - }, - onSpaceSelected: (space) { - setState(() { - selectedSpace = space; - }); - }, ); } else if (state is SpaceManagementError) { return Center(child: Text('Error: ${state.errorMessage}')); diff --git a/lib/pages/spaces_management/widgets/blank_community_widget.dart b/lib/pages/spaces_management/widgets/blank_community_widget.dart index 6d224562..e8ad4ddb 100644 --- a/lib/pages/spaces_management/widgets/blank_community_widget.dart +++ b/lib/pages/spaces_management/widgets/blank_community_widget.dart @@ -12,21 +12,24 @@ class BlankCommunityWidget extends StatelessWidget { Widget build(BuildContext context) { return Expanded( child: Container( - color: ColorsManager.whiteColors, // Parent container with white background + color: + ColorsManager.whiteColors, // Parent container with white background child: GridView.builder( padding: const EdgeInsets.only(left: 40.0, top: 20.0), - gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( + gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: 400, // Each item's width will be 400 or less mainAxisSpacing: 10, // Spacing between items crossAxisSpacing: 10, // Spacing between items - childAspectRatio: 2.0, // Aspect ratio for width:height (e.g., 300:150 = 2.0) + childAspectRatio: + 2.0, // Aspect ratio for width:height (e.g., 300:150 = 2.0) ), itemCount: 1, // Only one item itemBuilder: (context, index) { return GestureDetector( onTap: () => _showCreateCommunityDialog(context), child: Column( - crossAxisAlignment: CrossAxisAlignment.center, // Center align the content + crossAxisAlignment: + CrossAxisAlignment.center, // Center align the content children: [ Expanded( child: AspectRatio( @@ -34,7 +37,7 @@ class BlankCommunityWidget extends StatelessWidget { child: Container( decoration: ShapeDecoration( shape: RoundedRectangleBorder( - side: BorderSide( + side: const BorderSide( width: 4, strokeAlign: BorderSide.strokeAlignOutside, color: ColorsManager.borderColor, diff --git a/lib/pages/spaces_management/widgets/community_structure_header_widget.dart b/lib/pages/spaces_management/widgets/community_structure_header_widget.dart index 0addbe87..a940ecf6 100644 --- a/lib/pages/spaces_management/widgets/community_structure_header_widget.dart +++ b/lib/pages/spaces_management/widgets/community_structure_header_widget.dart @@ -86,7 +86,7 @@ class CommunityStructureHeader extends StatelessWidget { ), if (isEditingName) SizedBox( - width: screenWidth * 0.3, + width: screenWidth * 0.1, child: TextField( controller: nameController, decoration: const InputDecoration( diff --git a/lib/pages/spaces_management/widgets/community_structure_widget.dart b/lib/pages/spaces_management/widgets/community_structure_widget.dart index 90937f28..eedde30e 100644 --- a/lib/pages/spaces_management/widgets/community_structure_widget.dart +++ b/lib/pages/spaces_management/widgets/community_structure_widget.dart @@ -52,7 +52,8 @@ class _CommunityStructureAreaState extends State { void initState() { super.initState(); spaces = widget.spaces.isNotEmpty ? flattenSpaces(widget.spaces) : []; - connections = widget.spaces.isNotEmpty ? createConnections(widget.spaces) : []; + connections = + widget.spaces.isNotEmpty ? createConnections(widget.spaces) : []; _adjustCanvasSizeForSpaces(); _nameController = TextEditingController( text: widget.selectedCommunity?.name ?? '', @@ -79,12 +80,14 @@ class _CommunityStructureAreaState extends State { if (oldWidget.spaces != widget.spaces) { setState(() { spaces = widget.spaces.isNotEmpty ? flattenSpaces(widget.spaces) : []; - connections = widget.spaces.isNotEmpty ? createConnections(widget.spaces) : []; + connections = + widget.spaces.isNotEmpty ? createConnections(widget.spaces) : []; _adjustCanvasSizeForSpaces(); }); } - if (widget.selectedSpace != oldWidget.selectedSpace && widget.selectedSpace != null) { + if (widget.selectedSpace != oldWidget.selectedSpace && + widget.selectedSpace != null) { WidgetsBinding.instance.addPostFrameCallback((_) { _moveToSpace(widget.selectedSpace!); }); @@ -101,7 +104,7 @@ class _CommunityStructureAreaState extends State { return Expanded( child: GestureDetector( onTap: () { - _deselectSpace(); + _deselectSpace(context); }, child: Container( decoration: const BoxDecoration( @@ -156,9 +159,11 @@ class _CommunityStructureAreaState extends State { children: [ for (var connection in connections) Opacity( - opacity: - _isHighlightedConnection(connection) ? 1.0 : 0.3, // Adjust opacity - child: CustomPaint(painter: CurvedLinePainter([connection])), + opacity: _isHighlightedConnection(connection) + ? 1.0 + : 0.3, // Adjust opacity + child: CustomPaint( + painter: CurvedLinePainter([connection])), ), for (var entry in spaces.asMap().entries) if (entry.value.status != SpaceStatus.deleted) @@ -167,10 +172,12 @@ class _CommunityStructureAreaState extends State { top: entry.value.position.dy, child: SpaceCardWidget( index: entry.key, - onButtonTap: (int index, Offset newPosition, String direction) { + onButtonTap: (int index, Offset newPosition, + String direction) { _showCreateSpaceDialog( screenSize, - position: spaces[index].position + newPosition, + position: + spaces[index].position + newPosition, parentIndex: index, direction: direction, ); @@ -183,7 +190,8 @@ class _CommunityStructureAreaState extends State { _updateNodePosition(entry.value, newPosition); }, buildSpaceContainer: (int index) { - final bool isHighlighted = _isHighlightedSpace(spaces[index]); + final bool isHighlighted = + _isHighlightedSpace(spaces[index]); return Opacity( opacity: isHighlighted ? 1.0 : 0.3, @@ -193,7 +201,7 @@ class _CommunityStructureAreaState extends State { _showEditSpaceDialog(spaces[index]); }, onTap: () { - _selectSpace(spaces[index]); + _selectSpace(context, spaces[index]); }, icon: spaces[index].icon ?? '', name: spaces[index].name, @@ -210,7 +218,8 @@ class _CommunityStructureAreaState extends State { child: AddSpaceButton( onTap: () { _showCreateSpaceDialog(screenSize, - canvasHeight: canvasHeight, canvasWidth: canvasWidth); + canvasHeight: canvasHeight, + canvasWidth: canvasWidth); }, ), ), @@ -270,12 +279,14 @@ class _CommunityStructureAreaState extends State { builder: (BuildContext context) { return CreateSpaceDialog( products: widget.products, - parentSpace: parentIndex != null? spaces[parentIndex] : null, - onCreateSpace: (String name, String icon, List selectedProducts) { + parentSpace: parentIndex != null ? spaces[parentIndex] : null, + onCreateSpace: (String name, String icon, + List selectedProducts) { setState(() { // Set the first space in the center or use passed position - Offset centerPosition = position ?? _getCenterPosition(screenSize); + Offset centerPosition = + position ?? _getCenterPosition(screenSize); SpaceModel newSpace = SpaceModel( name: name, icon: icon, @@ -319,7 +330,8 @@ class _CommunityStructureAreaState extends State { icon: space.icon, isEdit: true, selectedProducts: space.selectedProducts, - onCreateSpace: (String name, String icon, List selectedProducts) { + onCreateSpace: (String name, String icon, + List selectedProducts) { setState(() { // Update the space's properties space.name = name; @@ -331,8 +343,7 @@ class _CommunityStructureAreaState extends State { } }); }, - // Pre-fill the dialog with current space data - key: Key(space.name), // Add a unique key to ensure dialog refresh + key: Key(space.name), ); }, ); @@ -465,40 +476,30 @@ class _CommunityStructureAreaState extends State { ..scale(1.2); } - void _selectSpace(SpaceModel space) { - setState(() { - widget.selectedSpace = space; - }); - - if (widget.onSpaceSelected != null) { - widget.onSpaceSelected!(space); - } + void _selectSpace(BuildContext context, SpaceModel space) { + context.read().add( + SelectSpaceEvent( + selectedCommunity: widget.selectedCommunity, + selectedSpace: space), + ); } bool _isHighlightedSpace(SpaceModel space) { - if (widget.selectedSpace == null) return true; - if (space == widget.selectedSpace) return true; - if (widget.selectedSpace?.parent?.internalId == space.internalId) return true; - if (widget.selectedSpace?.children != null) { - for (var child in widget.selectedSpace!.children) { - if (child.internalId == space.internalId) { - return true; - } - } - } - return false; + final selectedSpace = widget.selectedSpace; + if (selectedSpace == null) return true; + + return space == selectedSpace || + selectedSpace.parent?.internalId == space.internalId || + selectedSpace.children + ?.any((child) => child.internalId == space.internalId) == + true; } - void _deselectSpace() { - if (widget.selectedSpace != null) { - setState(() { - widget.selectedSpace = null; - }); - - if (widget.onSpaceSelected != null) { - widget.onSpaceSelected!(null); // Notify parent that no space is selected - } - } + void _deselectSpace(BuildContext context) { + context.read().add( + SelectSpaceEvent( + selectedCommunity: widget.selectedCommunity, selectedSpace: null), + ); } bool _isHighlightedConnection(Connection connection) { diff --git a/lib/pages/spaces_management/widgets/loaded_space_widget.dart b/lib/pages/spaces_management/widgets/loaded_space_widget.dart index aa48d323..5b340398 100644 --- a/lib/pages/spaces_management/widgets/loaded_space_widget.dart +++ b/lib/pages/spaces_management/widgets/loaded_space_widget.dart @@ -10,8 +10,6 @@ class LoadedSpaceView extends StatefulWidget { final List communities; final CommunityModel? selectedCommunity; final SpaceModel? selectedSpace; - final ValueChanged? onCommunitySelected; - final ValueChanged? onSpaceSelected; final List? products; const LoadedSpaceView({ @@ -19,8 +17,6 @@ class LoadedSpaceView extends StatefulWidget { required this.communities, this.selectedCommunity, this.selectedSpace, - required this.onCommunitySelected, - required this.onSpaceSelected, this.products, }); @@ -37,28 +33,14 @@ class _LoadedStateViewState extends State { Row( children: [ SidebarWidget( - communities: widget.communities, - onCommunitySelected: widget.onCommunitySelected, - onSpaceSelected: widget.onSpaceSelected, - selectedSpaceUuid: widget.selectedSpace?.uuid, - onSelectedSpaceChanged: (String? spaceUuid) { - setState(() { - final selectedSpace = findSpaceByUuid(spaceUuid, widget.communities); - if (selectedSpace != null) { - widget.onSpaceSelected!(selectedSpace); - } - }); - }), + communities: widget.communities, + selectedSpaceUuid: widget.selectedSpace?.uuid, + ), CommunityStructureArea( selectedCommunity: widget.selectedCommunity, selectedSpace: widget.selectedSpace, spaces: widget.selectedCommunity?.spaces ?? [], products: widget.products, - onSpaceSelected: (SpaceModel? space) { - setState(() { - widget.onSpaceSelected!(space); - }); - }, ), ], ), diff --git a/lib/pages/spaces_management/widgets/sidebar_widget.dart b/lib/pages/spaces_management/widgets/sidebar_widget.dart index 507cd703..affc3fd0 100644 --- a/lib/pages/spaces_management/widgets/sidebar_widget.dart +++ b/lib/pages/spaces_management/widgets/sidebar_widget.dart @@ -42,7 +42,8 @@ class _SidebarWidgetState extends State { @override void initState() { super.initState(); - _selectedId = widget.selectedSpaceUuid; // Initialize with the passed selected space UUID + _selectedId = widget + .selectedSpaceUuid; // Initialize with the passed selected space UUID } @override @@ -83,8 +84,8 @@ class _SidebarWidgetState extends State { return widget.communities.where((community) { final containsQueryInCommunity = community.name.toLowerCase().contains(_searchQuery.toLowerCase()); - final containsQueryInSpaces = - community.spaces.any((space) => _containsQuery(space, _searchQuery.toLowerCase())); + final containsQueryInSpaces = community.spaces + .any((space) => _containsQuery(space, _searchQuery.toLowerCase())); return containsQueryInCommunity || containsQueryInSpaces; }).toList(); @@ -93,8 +94,8 @@ class _SidebarWidgetState extends State { // 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 + final matchesChildren = space.children.any((child) => + _containsQuery(child, query)); // Recursive check for children // If the space or any of its children match the query, expand this space if (matchesSpace || matchesChildren) { @@ -128,7 +129,8 @@ class _SidebarWidgetState extends State { width: 300, decoration: subSectionContainerDecoration, child: Column( - mainAxisSize: MainAxisSize.min, // Ensures the Column only takes necessary height + mainAxisSize: + MainAxisSize.min, // Ensures the Column only takes necessary height crossAxisAlignment: CrossAxisAlignment.start, children: [ // Communities title with the add button @@ -176,7 +178,7 @@ class _SidebarWidgetState extends State { Expanded( child: ListView( children: filteredCommunities.map((community) { - return _buildCommunityTile(community); + return _buildCommunityTile(context, community); }).toList(), ), ), @@ -185,7 +187,7 @@ class _SidebarWidgetState extends State { ); } - Widget _buildCommunityTile(CommunityModel community) { + Widget _buildCommunityTile(BuildContext context, CommunityModel community) { bool hasChildren = community.spaces.isNotEmpty; return CommunityTile( @@ -199,16 +201,17 @@ class _SidebarWidgetState extends State { _selectedSpaceUuid = null; // Update the selected community }); - if (widget.onCommunitySelected != null) { - widget.onCommunitySelected!(community); - widget.onSpaceSelected!(null); // Pass the entire community - } + context.read().add( + SelectCommunityEvent(selectedCommunity: community), + ); }, onExpansionChanged: (String title, bool expanded) { _handleExpansionChange(community.uuid, expanded); }, children: hasChildren - ? community.spaces.map((space) => _buildSpaceTile(space, community)).toList() + ? community.spaces + .map((space) => _buildSpaceTile(space, community)) + .toList() : null, // Render spaces within the community ); } @@ -230,17 +233,15 @@ class _SidebarWidgetState extends State { _selectedSpaceUuid = space.uuid; }); - if (widget.onSpaceSelected != null) { - widget.onCommunitySelected!(community); - widget.onSpaceSelected!(space); - } - - if (widget.onSelectedSpaceChanged != null) { - widget.onSelectedSpaceChanged!(space.uuid); - } + context.read().add( + SelectSpaceEvent( + selectedCommunity: community, selectedSpace: space), + ); }, children: space.children.isNotEmpty - ? space.children.map((childSpace) => _buildSpaceTile(childSpace, community)).toList() + ? space.children + .map((childSpace) => _buildSpaceTile(childSpace, community)) + .toList() : [], // Recursively render child spaces if available ); } diff --git a/lib/services/space_mana_api.dart b/lib/services/space_mana_api.dart index 01248262..5d2464e6 100644 --- a/lib/services/space_mana_api.dart +++ b/lib/services/space_mana_api.dart @@ -8,22 +8,31 @@ import 'package:syncrow_web/utils/constants/api_const.dart'; class CommunitySpaceManagementApi { // Community Management APIs - Future> fetchCommunities() async { + Future> fetchCommunities({int page = 1}) async { try { - final response = await HTTPService().get( - path: ApiEndpoints.getCommunityList, - expectedResponseModel: (json) { - // Access the 'data' key from the response - List jsonData = json['data']; + List allCommunities = []; + bool hasNext = true; - // Check if jsonData is actually a List - List communityList = jsonData.map((jsonItem) { - return CommunityModel.fromJson(jsonItem); - }).toList(); - return communityList; - }, - ); - return response; + while (hasNext) { + await HTTPService().get( + path: ApiEndpoints.getCommunityList, + queryParameters: {'page': page}, + expectedResponseModel: (json) { + List jsonData = json['data']; + hasNext = json['hasNext'] ?? false; + int currentPage = json['page'] ?? 1; + List communityList = jsonData.map((jsonItem) { + return CommunityModel.fromJson(jsonItem); + }).toList(); + + allCommunities.addAll(communityList); + page = currentPage + 1; + return communityList; + }, + ); + } + + return allCommunities; } catch (e) { debugPrint('Error fetching communities: $e'); return []; @@ -33,7 +42,8 @@ class CommunitySpaceManagementApi { Future getCommunityById(String communityId) async { try { final response = await HTTPService().get( - path: ApiEndpoints.getCommunityById.replaceAll('{communityId}', communityId), + path: ApiEndpoints.getCommunityById + .replaceAll('{communityId}', communityId), expectedResponseModel: (json) { return CommunityModel.fromJson(json['data']); }, @@ -45,7 +55,8 @@ class CommunitySpaceManagementApi { } } - Future createCommunity(String name, String description) async { + Future createCommunity( + String name, String description) async { try { final response = await HTTPService().post( path: ApiEndpoints.createCommunity, @@ -67,7 +78,8 @@ class CommunitySpaceManagementApi { Future updateCommunity(String communityId, String name) async { try { final response = await HTTPService().put( - path: ApiEndpoints.updateCommunity.replaceAll('{communityId}', communityId), + path: ApiEndpoints.updateCommunity + .replaceAll('{communityId}', communityId), body: { 'name': name, }, @@ -85,7 +97,8 @@ class CommunitySpaceManagementApi { Future deleteCommunity(String communityId) async { try { final response = await HTTPService().delete( - path: ApiEndpoints.deleteCommunity.replaceAll('{communityId}', communityId), + path: ApiEndpoints.deleteCommunity + .replaceAll('{communityId}', communityId), expectedResponseModel: (json) { return json['success'] ?? false; }, @@ -236,10 +249,12 @@ class CommunitySpaceManagementApi { Future> getSpaceHierarchy(String communityId) async { try { final response = await HTTPService().get( - path: ApiEndpoints.getSpaceHierarchy.replaceAll('{communityId}', communityId), + path: ApiEndpoints.getSpaceHierarchy + .replaceAll('{communityId}', communityId), expectedResponseModel: (json) { - final spaceModels = - (json['data'] as List).map((spaceJson) => SpaceModel.fromJson(spaceJson)).toList(); + final spaceModels = (json['data'] as List) + .map((spaceJson) => SpaceModel.fromJson(spaceJson)) + .toList(); return spaceModels; },