import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_web/common/widgets/empty_search_result_widget.dart'; import 'package:syncrow_web/common/widgets/search_bar.dart'; import 'package:syncrow_web/common/widgets/sidebar_communities_list.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_bloc.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_event.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/pages/spaces_management/all_spaces/widgets/community_tile.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/sidebar_header.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/space_tile_widget.dart'; import 'package:syncrow_web/pages/spaces_management/create_community/view/create_community_dialog.dart'; import 'package:syncrow_web/pages/spaces_management/structure_selector/bloc/center_body_bloc.dart'; import 'package:syncrow_web/pages/spaces_management/structure_selector/bloc/center_body_event.dart'; import 'package:syncrow_web/utils/style.dart'; class SidebarWidget extends StatefulWidget { final List communities; final String? selectedSpaceUuid; final void Function(String name, String description) onCreateCommunity; const SidebarWidget({ required this.communities, required this.onCreateCommunity, this.selectedSpaceUuid, super.key, }); @override State createState() => _SidebarWidgetState(); } class _SidebarWidgetState extends State { late final ScrollController _scrollController; String _searchQuery = ''; String? _selectedSpaceUuid; String? _selectedId; @override void initState() { _selectedId = widget.selectedSpaceUuid; _scrollController = ScrollController(); super.initState(); } @override void dispose() { _scrollController.dispose(); super.dispose(); } @override void didUpdateWidget(covariant SidebarWidget oldWidget) { if (widget.selectedSpaceUuid != oldWidget.selectedSpaceUuid) { setState(() => _selectedId = widget.selectedSpaceUuid); } super.didUpdateWidget(oldWidget); } List _filteredCommunities() { if (_searchQuery.isEmpty) { _selectedSpaceUuid = null; return widget.communities; } return widget.communities.where((community) { final containsQueryInCommunity = community.name.toLowerCase().contains(_searchQuery.toLowerCase()); final containsQueryInSpaces = community.spaces.any((space) => _containsQuery(space: space, query: _searchQuery.toLowerCase())); return containsQueryInCommunity || containsQueryInSpaces; }).toList(); } bool _containsQuery({ required SpaceModel space, required String query, }) { final matchesSpace = space.name.toLowerCase().contains(query); final matchesChildren = space.children.any( (child) => _containsQuery(space: child, query: query), ); if (matchesSpace || matchesChildren) { _selectedSpaceUuid = space.uuid; } return matchesSpace || matchesChildren; } bool _isSpaceOrChildSelected(SpaceModel space) { final isSpaceSelected = _selectedSpaceUuid == space.uuid; final anySubSpaceIsSelected = space.children.any(_isSpaceOrChildSelected); return isSpaceSelected || anySubSpaceIsSelected; } static const _width = 300.0; @override Widget build(BuildContext context) { final filteredCommunities = _filteredCommunities(); return Container( width: _width, decoration: subSectionContainerDecoration, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ SidebarHeader(onAddCommunity: _onAddCommunity), CustomSearchBar( onSearchChanged: (query) => setState(() => _searchQuery = query), ), const SizedBox(height: 16), Expanded( child: Visibility( visible: filteredCommunities.isNotEmpty, replacement: const EmptySearchResultWidget(), child: SidebarCommunitiesList( scrollController: _scrollController, onScrollToEnd: () {}, communities: filteredCommunities, itemBuilder: (context, index) => _buildCommunityTile( context, filteredCommunities[index], ), ), ), ), ], ), ); } Widget _buildCommunityTile(BuildContext context, CommunityModel community) { return CommunityTile( title: community.name, key: ValueKey(community.uuid), isSelected: _selectedId == community.uuid, isExpanded: false, onItemSelected: () { setState(() { _selectedId = community.uuid; _selectedSpaceUuid = null; }); context.read().add(CommunitySelectedEvent()); context.read().add( SelectCommunityEvent(selectedCommunity: community), ); }, onExpansionChanged: (title, expanded) {}, children: community.spaces .where( (space) => { SpaceStatus.deleted, SpaceStatus.parentDeleted, }.contains(space.status), ) .map((space) => _buildSpaceTile(space: space, community: community)) .toList(), ); } Widget _buildSpaceTile({ required SpaceModel space, required CommunityModel community, }) { final spaceIsExpanded = _isSpaceOrChildSelected(space); final isSelected = _selectedId == space.uuid; return Padding( padding: const EdgeInsetsDirectional.only(start: 16.0), child: SpaceTile( title: space.name, key: ValueKey(space.uuid), isSelected: isSelected, initiallyExpanded: spaceIsExpanded, onExpansionChanged: (expanded) {}, onItemSelected: () { setState(() { _selectedId = space.uuid; _selectedSpaceUuid = space.uuid; }); context.read().add( SelectSpaceEvent(selectedCommunity: community, selectedSpace: space), ); }, children: space.children .map( (childSpace) => _buildSpaceTile( space: childSpace, community: community, ), ) .toList(), ), ); } void _onAddCommunity() => _selectedId?.isNotEmpty ?? true ? _clearSelection() : _showCreateCommunityDialog(); void _clearSelection() { setState(() => _selectedId = ''); context.read().add( NewCommunityEvent(communities: widget.communities), ); } void _showCreateCommunityDialog() { showDialog( context: context, builder: (context) => CreateCommunityDialog( isEditMode: false, existingCommunityNames: widget.communities.map((e) => e.name).toList(), onCreateCommunity: widget.onCreateCommunity, ), ); } }