Compare commits

..
Author SHA1 Message Date
hannathkadher 42c7577b35 validity for space name 2024-11-29 19:03:27 +04:00
hannathkadher ae2b4b9b06 border 2024-11-29 17:31:37 +04:00
hannathkadher 98faef2bde typo 2024-11-29 17:30:03 +04:00
hannathkadher edf297c569 border 2024-11-29 17:29:18 +04:00
hannathkadher 2cd850b66f border color change to red 2024-11-29 17:26:57 +04:00
hannathkadher 3c543b2e0f added validation for community name 2024-11-29 17:22:00 +04:00
hannathkadher a3c6421b0d updated flow for create community 2024-11-29 16:50:49 +04:00
hannathkadher 51402720dd space load on space save 2024-11-28 22:50:05 +04:00
hannathkadher 123291fd89 parse incoming connection 2024-11-28 20:31:19 +04:00
hannathkadher 69e3f50269 reduced width of text controller 2024-11-28 20:11:16 +04:00
hannathkadher bd78c8c1cc format 2024-11-28 20:09:28 +04:00
hannathkadher 4047664c59 create community should move back to blank page 2024-11-28 20:07:18 +04:00
hannathkadher 084f4fbda8 updated highlighted space 2024-11-28 20:02:41 +04:00
hannathkadher 817671dbeb updated deselect on structure 2024-11-28 20:01:14 +04:00
hannathkadher 660b5aaf6c remove unused code 2024-11-28 19:56:40 +04:00
hannathkadher 0f500a4efa remove unused state functions 2024-11-28 19:55:45 +04:00
hannathkadher 0b2d44fc2b updated LoadedSpaceView 2024-11-28 19:54:04 +04:00
hannathkadher b75f8a3440 side bar widget uses context 2024-11-28 19:52:20 +04:00
hannathkadher d02d680520 add events for select space and community 2024-11-28 19:45:24 +04:00
hannathkadher 68ae992963 added select space and select community event 2024-11-28 19:40:44 +04:00
hannathkadher ea20afd34e fixed issue of not recursively calling communtiy list 2024-11-28 15:16:07 +04:00
Abdullah b0f0a91cda Merge pull request #49 from SyncrowIOT/feature/space-management
Feature/space management
2024-11-28 12:15:06 +03:00
13 changed files with 519 additions and 286 deletions
@@ -7,20 +7,25 @@ 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<SpaceManagementEvent, SpaceManagementState> {
class SpaceManagementBloc
extends Bloc<SpaceManagementEvent, SpaceManagementState> {
final CommunitySpaceManagementApi _api;
final ProductApi _productApi;
List<ProductModel>? _cachedProducts;
SpaceManagementBloc(this._api, this._productApi) : super(SpaceManagementInitial()) {
SpaceManagementBloc(this._api, this._productApi)
: super(SpaceManagementInitial()) {
on<LoadCommunityAndSpacesEvent>(_onLoadCommunityAndSpaces);
on<UpdateSpacePositionEvent>(_onUpdateSpacePosition);
on<CreateCommunityEvent>(_onCreateCommunity);
on<SaveSpacesEvent>(_onSaveSpaces);
on<FetchProductsEvent>(_onFetchProducts);
on<SelectCommunityEvent>(_onSelectCommunity);
on<DeleteCommunityEvent>(_onCommunityDelete);
on<UpdateCommunityEvent>(_onUpdateCommunity);
on<SaveSpacesEvent>(_onSaveSpaces);
on<FetchProductsEvent>(_onFetchProducts);
on<SelectSpaceEvent>(_onSelectSpace);
on<NewCommunityEvent>(_onNewCommunity);
}
void _onUpdateCommunity(
@@ -30,22 +35,23 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
final previousState = state;
try {
emit(SpaceManagementLoading());
final success = await _api.updateCommunity(event.communityUuid, event.name);
final success =
await _api.updateCommunity(event.communityUuid, event.name);
if (success) {
if (previousState is SpaceManagementLoaded) {
final updatedCommunities = List<CommunityModel>.from(previousState.communities);
for(var community in updatedCommunities){
if(community.uuid == event.communityUuid){
final updatedCommunities =
List<CommunityModel>.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 +61,61 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
}
}
void _onloadProducts() async {
if (_cachedProducts == null) {
final products = await _productApi.fetchProducts();
_cachedProducts = products;
}
}
void _onFetchProducts(
FetchProductsEvent event,
Emitter<SpaceManagementState> 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<List<SpaceModel>> _fetchSpacesForCommunity(
String communityUuid) async {
return await _api.getSpaceHierarchy(communityUuid);
}
void _onNewCommunity(
NewCommunityEvent event,
Emitter<SpaceManagementState> emit,
) {
try {
if (event.communities.isEmpty) {
emit(const SpaceManagementError('No communities provided.'));
return;
}
emit(BlankState(
communities: event.communities,
products: _cachedProducts ?? [],
));
} catch (error) {
emit(SpaceManagementError('Error loading communities: $error'));
}
}
void _onLoadCommunityAndSpaces(
LoadCommunityAndSpacesEvent event,
Emitter<SpaceManagementState> emit,
) async {
emit(SpaceManagementLoading());
try {
if (_cachedProducts == null) {
final products = await _productApi.fetchProducts();
_cachedProducts = products;
}
// Fetch all communities
_onloadProducts();
List<CommunityModel> communities = await _api.fetchCommunities();
List<CommunityModel> updatedCommunities = await Future.wait(
communities.map((community) async {
List<SpaceModel> spaces = await _api.getSpaceHierarchy(community.uuid);
List<SpaceModel> spaces =
await _fetchSpacesForCommunity(community.uuid);
return CommunityModel(
uuid: community.uuid,
createdAt: community.createdAt,
@@ -101,7 +128,8 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
}).toList(),
);
emit(SpaceManagementLoaded(communities: updatedCommunities, products: _cachedProducts ?? []));
emit(SpaceManagementLoaded(
communities: updatedCommunities, products: _cachedProducts ?? []));
} catch (e) {
emit(SpaceManagementError('Error loading communities and spaces: $e'));
}
@@ -139,16 +167,21 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
emit(SpaceManagementLoading());
try {
CommunityModel? newCommunity = await _api.createCommunity(event.name, event.description);
CommunityModel? newCommunity =
await _api.createCommunity(event.name, event.description);
if (newCommunity != null) {
if (previousState is SpaceManagementLoaded) {
final updatedCommunities = List<CommunityModel>.from(previousState.communities)
..add(newCommunity);
if (previousState is SpaceManagementLoaded ||
previousState is BlankState) {
final prevCommunities = List<CommunityModel>.from(
(previousState as dynamic).communities,
);
final updatedCommunities = prevCommunities..add(newCommunity);
emit(SpaceManagementLoaded(
communities: updatedCommunities,
products: _cachedProducts ?? [],
selectedCommunity: newCommunity));
selectedCommunity: newCommunity,
selectedSpace: null));
}
} else {
emit(const SpaceManagementError('Error creating community'));
@@ -158,6 +191,54 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
}
}
void _onSelectCommunity(
SelectCommunityEvent event,
Emitter<SpaceManagementState> emit,
) async {
_handleCommunitySpaceStateUpdate(
emit: emit,
selectedCommunity: event.selectedCommunity,
selectedSpace: null,
);
}
void _onSelectSpace(
SelectSpaceEvent event,
Emitter<SpaceManagementState> emit,
) {
_handleCommunitySpaceStateUpdate(
emit: emit,
selectedCommunity: event.selectedCommunity,
selectedSpace: event.selectedSpace,
);
}
void _handleCommunitySpaceStateUpdate({
required Emitter<SpaceManagementState> emit,
CommunityModel? selectedCommunity,
SpaceModel? selectedSpace,
}) {
final previousState = state;
emit(SpaceManagementLoading());
try {
if (previousState is SpaceManagementLoaded ||
previousState is BlankState) {
final communities = List<CommunityModel>.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<SpaceManagementState> emit,
@@ -166,17 +247,54 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
emit(SpaceManagementLoading());
try {
final updatedSpaces = await saveSpacesHierarchically(event.spaces, event.communityUuid);
final updatedSpaces =
await saveSpacesHierarchically(event.spaces, event.communityUuid);
final allSpaces = await _fetchSpacesForCommunity(event.communityUuid);
emit(SpaceCreationSuccess(spaces: updatedSpaces));
add(LoadCommunityAndSpacesEvent());
if (previousState is SpaceManagementLoaded) {
_updateLoadedState(
previousState,
allSpaces,
event.communityUuid,
emit,
);
} else {
add(LoadCommunityAndSpacesEvent());
}
} catch (e) {
emit(SpaceManagementError('Error saving spaces: $e'));
if (previousState is SpaceManagementLoaded) {
emit(previousState);
}
}
}
void _updateLoadedState(
SpaceManagementLoaded previousState,
List<SpaceModel> allSpaces,
String communityUuid,
Emitter<SpaceManagementState> emit,
) {
final communities = List<CommunityModel>.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<List<SpaceModel>> saveSpacesHierarchically(
List<SpaceModel> spaces, String communityUuid) async {
final orderedSpaces = flattenHierarchy(spaces);
@@ -187,7 +305,6 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
for (var parent in parentsToDelete) {
try {
// Ensure parent.uuid is not null before calling the API
if (parent.uuid != null) {
await _api.deleteSpace(communityUuid, parent.uuid!);
}
@@ -1,5 +1,6 @@
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:syncrow_web/pages/spaces_management/model/community_model.dart';
import 'package:syncrow_web/pages/spaces_management/model/space_model.dart'; // Import for Offset
abstract class SpaceManagementEvent extends Equatable {
@@ -83,17 +84,6 @@ class CreateCommunityEvent extends SpaceManagementEvent {
List<Object> get props => [name, description];
}
class FetchProductsEvent extends SpaceManagementEvent {}
class LoadSpaceHierarchyEvent extends SpaceManagementEvent {
final String communityId;
const LoadSpaceHierarchyEvent({required this.communityId});
@override
List<Object> get props => [communityId];
}
class UpdateCommunityEvent extends SpaceManagementEvent {
final String communityUuid;
final String name;
@@ -106,3 +96,47 @@ class UpdateCommunityEvent extends SpaceManagementEvent {
@override
List<Object> get props => [communityUuid, name];
}
class SelectCommunityEvent extends SpaceManagementEvent {
final CommunityModel? selectedCommunity;
const SelectCommunityEvent({
required this.selectedCommunity,
});
@override
List<Object> get props => [];
}
class NewCommunityEvent extends SpaceManagementEvent {
final List<CommunityModel> communities;
const NewCommunityEvent({required this.communities});
@override
List<Object> get props => [communities];
}
class SelectSpaceEvent extends SpaceManagementEvent {
final CommunityModel? selectedCommunity;
final SpaceModel? selectedSpace;
const SelectSpaceEvent({
required this.selectedCommunity,
required this.selectedSpace,
});
@override
List<Object> get props => [];
}
class FetchProductsEvent extends SpaceManagementEvent {}
class LoadSpaceHierarchyEvent extends SpaceManagementEvent {
final String communityId;
const LoadSpaceHierarchyEvent({required this.communityId});
@override
List<Object> get props => [communityId];
}
@@ -17,10 +17,24 @@ class SpaceManagementLoading extends SpaceManagementState {}
class SpaceManagementLoaded extends SpaceManagementState {
final List<CommunityModel> communities;
final List<ProductModel> 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 BlankState extends SpaceManagementState {
final List<CommunityModel> communities;
final List<ProductModel> products;
BlankState({
required this.communities,
required this.products,
});
}
class SpaceCreationSuccess extends SpaceManagementState {
@@ -44,7 +44,8 @@ class SpaceModel {
this.selectedProducts = const [],
}) : internalId = internalId ?? const Uuid().v4();
factory SpaceModel.fromJson(Map<String, dynamic> json, {String? parentInternalId}) {
factory SpaceModel.fromJson(Map<String, dynamic> json,
{String? parentInternalId}) {
final String internalId = json['internalId'] ?? const Uuid().v4();
final List<SpaceModel> 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<String, dynamic> toMap() {
@@ -20,8 +20,6 @@ class SpaceManagementPage extends StatefulWidget {
}
class SpaceManagementPageState extends State<SpaceManagementPage> {
CommunityModel? selectedCommunity;
SpaceModel? selectedSpace;
final CommunitySpaceManagementApi _api = CommunitySpaceManagementApi();
final ProductApi _productApi = ProductApi();
Map<String, List<SpaceModel>> communitySpaces = {};
@@ -36,43 +34,30 @@ class SpaceManagementPageState extends State<SpaceManagementPage> {
@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<SpaceManagementBloc, SpaceManagementState>(builder: (context, state) {
scaffoldBody: BlocBuilder<SpaceManagementBloc, SpaceManagementState>(
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;
}
} else if (state is BlankState) {
return LoadedSpaceView(
communities: state.communities,
selectedCommunity: selectedCommunity,
selectedSpace: selectedSpace,
selectedCommunity: null,
selectedSpace: null,
products: state.products,
);
} else if (state is SpaceManagementLoaded) {
return LoadedSpaceView(
communities: state.communities,
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}'));
@@ -2,31 +2,41 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/spaces_management/bloc/space_management_bloc.dart';
import 'package:syncrow_web/pages/spaces_management/bloc/space_management_event.dart';
import 'package:syncrow_web/pages/spaces_management/model/community_model.dart';
import 'package:syncrow_web/pages/spaces_management/widgets/dialogs/create_community_dialog.dart';
import 'package:syncrow_web/utils/color_manager.dart';
class BlankCommunityWidget extends StatelessWidget {
const BlankCommunityWidget({Key? key}) : super(key: key);
class BlankCommunityWidget extends StatefulWidget {
final List<CommunityModel> communities;
BlankCommunityWidget({required this.communities});
@override
_BlankCommunityWidgetState createState() => _BlankCommunityWidgetState();
}
class _BlankCommunityWidgetState extends State<BlankCommunityWidget> {
@override
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(
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)
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 400,
mainAxisSpacing: 10,
crossAxisSpacing: 10,
childAspectRatio: 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 +44,7 @@ class BlankCommunityWidget extends StatelessWidget {
child: Container(
decoration: ShapeDecoration(
shape: RoundedRectangleBorder(
side: BorderSide(
side: const BorderSide(
width: 4,
strokeAlign: BorderSide.strokeAlignOutside,
color: ColorsManager.borderColor,
@@ -45,9 +55,8 @@ class BlankCommunityWidget extends StatelessWidget {
),
),
),
const SizedBox(height: 9), // Space between item and text
Text('Blank', // Text below the item
const SizedBox(height: 9),
Text('Blank',
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
color: ColorsManager.blackColor,
)),
@@ -63,6 +72,7 @@ class BlankCommunityWidget extends StatelessWidget {
showDialog(
context: parentContext,
builder: (context) => CreateCommunityDialog(
communities: widget.communities,
onCreateCommunity: (String communityName, String description) {
parentContext.read<SpaceManagementBloc>().add(
CreateCommunityEvent(
@@ -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(
@@ -24,12 +24,13 @@ class CommunityStructureArea extends StatefulWidget {
SpaceModel? selectedSpace;
final List<ProductModel>? products;
final ValueChanged<SpaceModel?>? onSpaceSelected;
final List<CommunityModel> communities;
final List<SpaceModel> spaces;
CommunityStructureArea({
this.selectedCommunity,
this.selectedSpace,
required this.communities,
this.products,
required this.spaces,
this.onSpaceSelected,
@@ -52,7 +53,8 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
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 +81,14 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
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!);
});
@@ -94,14 +98,16 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
@override
Widget build(BuildContext context) {
if (widget.selectedCommunity == null) {
return BlankCommunityWidget();
return BlankCommunityWidget(
communities: widget.communities,
);
}
Size screenSize = MediaQuery.of(context).size;
return Expanded(
child: GestureDetector(
onTap: () {
_deselectSpace();
_deselectSpace(context);
},
child: Container(
decoration: const BoxDecoration(
@@ -156,9 +162,11 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
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 +175,12 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
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 +193,8 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
_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 +204,7 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
_showEditSpaceDialog(spaces[index]);
},
onTap: () {
_selectSpace(spaces[index]);
_selectSpace(context, spaces[index]);
},
icon: spaces[index].icon ?? '',
name: spaces[index].name,
@@ -210,7 +221,8 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
child: AddSpaceButton(
onTap: () {
_showCreateSpaceDialog(screenSize,
canvasHeight: canvasHeight, canvasWidth: canvasWidth);
canvasHeight: canvasHeight,
canvasWidth: canvasWidth);
},
),
),
@@ -270,12 +282,14 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
builder: (BuildContext context) {
return CreateSpaceDialog(
products: widget.products,
parentSpace: parentIndex != null? spaces[parentIndex] : null,
onCreateSpace: (String name, String icon, List<SelectedProduct> selectedProducts) {
parentSpace: parentIndex != null ? spaces[parentIndex] : null,
onCreateSpace: (String name, String icon,
List<SelectedProduct> 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,
@@ -317,9 +331,11 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
products: widget.products,
name: space.name,
icon: space.icon,
editSpace: space,
isEdit: true,
selectedProducts: space.selectedProducts,
onCreateSpace: (String name, String icon, List<SelectedProduct> selectedProducts) {
onCreateSpace: (String name, String icon,
List<SelectedProduct> selectedProducts) {
setState(() {
// Update the space's properties
space.name = name;
@@ -331,8 +347,7 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
}
});
},
// 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 +480,30 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
..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<SpaceManagementBloc>().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<SpaceManagementBloc>().add(
SelectSpaceEvent(
selectedCommunity: widget.selectedCommunity, selectedSpace: null),
);
}
bool _isHighlightedConnection(Connection connection) {
@@ -1,37 +1,47 @@
import 'package:flutter/material.dart';
import 'package:syncrow_web/pages/common/buttons/cancel_button.dart';
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
import 'package:syncrow_web/pages/spaces_management/model/community_model.dart';
import 'package:syncrow_web/utils/color_manager.dart';
class CreateCommunityDialog extends StatefulWidget {
final Function(String name, String description) onCreateCommunity;
final List<CommunityModel> communities;
const CreateCommunityDialog({super.key, required this.onCreateCommunity});
const CreateCommunityDialog(
{super.key, required this.onCreateCommunity, required this.communities});
@override
CreateCommunityDialogState createState() => CreateCommunityDialogState();
}
class CreateCommunityDialogState extends State<CreateCommunityDialog> {
String enteredName = ''; // Store the entered community name
String enteredName = '';
bool isNameFieldExist = false;
bool isNameEmpty = false;
@override
Widget build(BuildContext context) {
final screenWidth = MediaQuery.of(context).size.width;
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
backgroundColor: Colors.transparent, // Transparent for shadow effect
backgroundColor:
ColorsManager.transparentColor, // Transparent for shadow effect
child: Stack(
children: [
// Background container with shadow and rounded corners
Container(
width: 490,
width: screenWidth * 0.3,
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.white,
color: ColorsManager.whiteColors,
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.25),
color: ColorsManager.blackColor.withOpacity(0.25),
blurRadius: 20,
spreadRadius: 5,
offset: const Offset(0, 5),
@@ -53,10 +63,20 @@ class CreateCommunityDialogState extends State<CreateCommunityDialog> {
// Input field for the community name
TextField(
onChanged: (value) {
enteredName = value; // Capture entered name
setState(() {
enteredName = value.trim();
isNameFieldExist = widget.communities.any(
(community) => community.name == enteredName,
);
if (value.isEmpty) {
isNameEmpty = true;
} else {
isNameEmpty = false;
}
});
},
style: const TextStyle(
color: Colors.black,
color: ColorsManager.blackColor,
),
decoration: InputDecoration(
hintText: 'Please enter the community name',
@@ -68,45 +88,68 @@ class CreateCommunityDialogState extends State<CreateCommunityDialog> {
fontWeight: FontWeight.w400,
),
border: OutlineInputBorder(
borderSide: const BorderSide(color: ColorsManager.boxColor, width: 1),
borderSide: BorderSide(
color: isNameFieldExist || isNameEmpty
? ColorsManager.red
: ColorsManager.boxColor,
width: 1),
borderRadius: BorderRadius.circular(10),
),
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(color: ColorsManager.boxColor, width: 1),
borderSide: BorderSide(
color: isNameFieldExist || isNameEmpty
? ColorsManager.red
: ColorsManager.boxColor, width: 1),
borderRadius: BorderRadius.circular(10),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: const BorderSide(color: ColorsManager.boxColor, width: 1),
borderSide: BorderSide(
color: isNameFieldExist || isNameEmpty
? ColorsManager.red
: ColorsManager.boxColor,
width: 1),
),
),
),
if (isNameFieldExist)
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
'*Name already exists.',
style: Theme.of(context)
.textTheme
.bodySmall
?.copyWith(color: ColorsManager.red),
),
),
if (isNameEmpty)
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
'*Name should not be empty.',
style: Theme.of(context)
.textTheme
.bodySmall
?.copyWith(color: ColorsManager.red),
),
),
const SizedBox(height: 24),
// Action buttons
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: TextButton(
child: CancelButton(
label: 'Cancel',
onPressed: () => Navigator.of(context).pop(),
style: TextButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 16),
backgroundColor: ColorsManager.boxColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
child: const Text(
'Cancel',
style: TextStyle(color: Colors.black),
),
),
),
const SizedBox(width: 16),
Expanded(
child: ElevatedButton(
child: DefaultButton(
onPressed: () {
if (enteredName.isNotEmpty) {
if (enteredName.isNotEmpty && !isNameFieldExist) {
widget.onCreateCommunity(
enteredName,
"",
@@ -114,14 +157,11 @@ class CreateCommunityDialogState extends State<CreateCommunityDialog> {
Navigator.of(context).pop();
}
},
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 16),
backgroundColor: ColorsManager.secondaryColor,
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
backgroundColor: isNameFieldExist || isNameEmpty
? ColorsManager.lightGrayColor
: ColorsManager.secondaryColor,
borderRadius: 10,
foregroundColor: ColorsManager.whiteColors,
child: const Text('OK'),
),
),
@@ -13,13 +13,15 @@ import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/constants/space_icon_const.dart';
class CreateSpaceDialog extends StatefulWidget {
final Function(String, String, List<SelectedProduct> selectedProducts) onCreateSpace;
final Function(String, String, List<SelectedProduct> selectedProducts)
onCreateSpace;
final List<ProductModel>? products;
final String? name;
final String? icon;
final bool isEdit;
final List<SelectedProduct> selectedProducts;
final SpaceModel? parentSpace;
final SpaceModel? editSpace;
const CreateSpaceDialog(
{super.key,
@@ -29,6 +31,7 @@ class CreateSpaceDialog extends StatefulWidget {
this.name,
this.icon,
this.isEdit = false,
this.editSpace,
this.selectedProducts = const []});
@override
@@ -49,8 +52,10 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
super.initState();
selectedIcon = widget.icon ?? Assets.location;
nameController = TextEditingController(text: widget.name ?? '');
selectedProducts = widget.selectedProducts.isNotEmpty ? widget.selectedProducts : [];
isOkButtonEnabled = enteredName.isNotEmpty || nameController.text.isNotEmpty;
selectedProducts =
widget.selectedProducts.isNotEmpty ? widget.selectedProducts : [];
isOkButtonEnabled =
enteredName.isNotEmpty || nameController.text.isNotEmpty;
}
@override
@@ -59,7 +64,9 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
final screenWidth = MediaQuery.of(context).size.width;
return AlertDialog(
title: widget.isEdit ? const Text('Edit Space') : const Text('Create New Space'),
title: widget.isEdit
? const Text('Edit Space')
: const Text('Create New Space'),
backgroundColor: ColorsManager.whiteColors,
content: SizedBox(
width: screenWidth * 0.5, // Limit dialog width
@@ -126,11 +133,17 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
isNameFieldInvalid = value.isEmpty;
if (!isNameFieldInvalid) {
if (widget.parentSpace?.children
.any((child) => child.name == value) ??
false) {
if ((widget.parentSpace?.children.any(
(child) => child.name == value) ??
false) ||
(widget.parentSpace?.name == value) ||
(widget.editSpace?.children.any(
(child) => child.name == value) ??
false)) {
isNameFieldExist = true;
isOkButtonEnabled = false;
} else {
isNameFieldExist = false;
isOkButtonEnabled = true;
}
}
@@ -218,7 +231,8 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
padding: const EdgeInsets.only(left: 6.0),
child: SvgPicture.asset(
Assets.addIcon,
width: screenWidth * 0.015, // Adjust icon size
width: screenWidth *
0.015, // Adjust icon size
height: screenWidth * 0.015,
),
),
@@ -226,8 +240,11 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
Flexible(
child: Text(
'Add devices / Assign a space model',
overflow: TextOverflow.ellipsis, // Prevent overflow
style: Theme.of(context).textTheme.bodyMedium,
overflow: TextOverflow
.ellipsis, // Prevent overflow
style: Theme.of(context)
.textTheme
.bodyMedium,
),
),
],
@@ -262,16 +279,20 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
});
return;
} else {
String newName = enteredName.isNotEmpty ? enteredName : (widget.name ?? '');
String newName = enteredName.isNotEmpty
? enteredName
: (widget.name ?? '');
if (newName.isNotEmpty) {
widget.onCreateSpace(newName, selectedIcon, selectedProducts);
widget.onCreateSpace(
newName, selectedIcon, selectedProducts);
Navigator.of(context).pop();
}
}
},
borderRadius: 10,
backgroundColor:
isOkButtonEnabled ? ColorsManager.secondaryColor : ColorsManager.grayColor,
backgroundColor: isOkButtonEnabled
? ColorsManager.secondaryColor
: ColorsManager.grayColor,
foregroundColor: ColorsManager.whiteColors,
child: const Text('OK'),
),
@@ -318,7 +339,8 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
children: [
for (var i = 0; i < selectedProducts.length; i++) ...[
HoverableButton(
iconPath: _mapIconToProduct(selectedProducts[i].productId, products),
iconPath:
_mapIconToProduct(selectedProducts[i].productId, products),
text: 'x${selectedProducts[i].count}',
onTap: () {
setState(() {
@@ -328,7 +350,8 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
},
),
if (i < selectedProducts.length - 1)
const SizedBox(width: 2), // Add space except after the last button
const SizedBox(
width: 2), // Add space except after the last button
],
const SizedBox(width: 2),
GestureDetector(
@@ -364,6 +387,8 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
);
}
String _mapIconToProduct(String uuid, List<ProductModel> products) {
// Find the product with the matching UUID
final product = products.firstWhere(
@@ -10,8 +10,6 @@ class LoadedSpaceView extends StatefulWidget {
final List<CommunityModel> communities;
final CommunityModel? selectedCommunity;
final SpaceModel? selectedSpace;
final ValueChanged<CommunityModel>? onCommunitySelected;
final ValueChanged<SpaceModel?>? onSpaceSelected;
final List<ProductModel>? 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,17 @@ class _LoadedStateViewState extends State<LoadedSpaceView> {
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 ??
widget.selectedCommunity?.uuid ??
'',
),
CommunityStructureArea(
selectedCommunity: widget.selectedCommunity,
selectedSpace: widget.selectedSpace,
spaces: widget.selectedCommunity?.spaces ?? [],
products: widget.products,
onSpaceSelected: (SpaceModel? space) {
setState(() {
widget.onSpaceSelected!(space);
});
},
communities: widget.communities,
),
],
),
@@ -7,25 +7,17 @@ import 'package:syncrow_web/pages/spaces_management/bloc/space_management_event.
import 'package:syncrow_web/pages/spaces_management/model/community_model.dart';
import 'package:syncrow_web/pages/spaces_management/model/space_model.dart';
import 'package:syncrow_web/pages/spaces_management/widgets/community_tile.dart';
import 'package:syncrow_web/pages/spaces_management/widgets/dialogs/create_community_dialog.dart';
import 'package:syncrow_web/pages/spaces_management/widgets/space_tile_widget.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/style.dart';
class SidebarWidget extends StatefulWidget {
final Function(CommunityModel)? onCommunitySelected;
final Function(SpaceModel?)? onSpaceSelected;
final List<CommunityModel> communities;
final Function(String?)? onSelectedSpaceChanged; // New callback
final String? selectedSpaceUuid;
const SidebarWidget({
super.key,
this.onCommunitySelected,
this.onSpaceSelected,
this.onSelectedSpaceChanged,
required this.communities,
this.selectedSpaceUuid,
});
@@ -42,7 +34,8 @@ class _SidebarWidgetState extends State<SidebarWidget> {
@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
@@ -55,22 +48,6 @@ class _SidebarWidgetState extends State<SidebarWidget> {
}
}
void _showCreateCommunityDialog(BuildContext parentContext) {
showDialog(
context: parentContext,
builder: (context) => CreateCommunityDialog(
onCreateCommunity: (String communityName, String description) {
parentContext.read<SpaceManagementBloc>().add(
CreateCommunityEvent(
name: communityName,
description: description,
),
);
},
),
);
}
// Function to filter communities based on the search query
List<CommunityModel> _filterCommunities() {
if (_searchQuery.isEmpty) {
@@ -83,8 +60,8 @@ class _SidebarWidgetState extends State<SidebarWidget> {
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 +70,8 @@ class _SidebarWidgetState extends State<SidebarWidget> {
// 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 +105,8 @@ class _SidebarWidgetState extends State<SidebarWidget> {
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
@@ -143,7 +121,7 @@ class _SidebarWidgetState extends State<SidebarWidget> {
color: Colors.black,
)),
GestureDetector(
onTap: () => _showCreateCommunityDialog(context),
onTap: () => _navigateToBlank(context),
child: Container(
width: 30,
height: 30,
@@ -176,7 +154,7 @@ class _SidebarWidgetState extends State<SidebarWidget> {
Expanded(
child: ListView(
children: filteredCommunities.map((community) {
return _buildCommunityTile(community);
return _buildCommunityTile(context, community);
}).toList(),
),
),
@@ -185,7 +163,16 @@ class _SidebarWidgetState extends State<SidebarWidget> {
);
}
Widget _buildCommunityTile(CommunityModel community) {
void _navigateToBlank(BuildContext context) {
setState(() {
_selectedId = '';
});
context.read<SpaceManagementBloc>().add(
NewCommunityEvent(communities: widget.communities),
);
}
Widget _buildCommunityTile(BuildContext context, CommunityModel community) {
bool hasChildren = community.spaces.isNotEmpty;
return CommunityTile(
@@ -199,23 +186,23 @@ class _SidebarWidgetState extends State<SidebarWidget> {
_selectedSpaceUuid = null; // Update the selected community
});
if (widget.onCommunitySelected != null) {
widget.onCommunitySelected!(community);
widget.onSpaceSelected!(null); // Pass the entire community
}
context.read<SpaceManagementBloc>().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
);
}
Widget _buildSpaceTile(SpaceModel space, CommunityModel community) {
bool isExpandedSpace = _isSpaceOrChildSelected(space);
// Check if space should be expanded
return SpaceTile(
title: space.name,
key: ValueKey(space.uuid),
@@ -230,17 +217,15 @@ class _SidebarWidgetState extends State<SidebarWidget> {
_selectedSpaceUuid = space.uuid;
});
if (widget.onSpaceSelected != null) {
widget.onCommunitySelected!(community);
widget.onSpaceSelected!(space);
}
if (widget.onSelectedSpaceChanged != null) {
widget.onSelectedSpaceChanged!(space.uuid);
}
context.read<SpaceManagementBloc>().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
);
}
+36 -21
View File
@@ -8,22 +8,31 @@ import 'package:syncrow_web/utils/constants/api_const.dart';
class CommunitySpaceManagementApi {
// Community Management APIs
Future<List<CommunityModel>> fetchCommunities() async {
Future<List<CommunityModel>> fetchCommunities({int page = 1}) async {
try {
final response = await HTTPService().get(
path: ApiEndpoints.getCommunityList,
expectedResponseModel: (json) {
// Access the 'data' key from the response
List<dynamic> jsonData = json['data'];
List<CommunityModel> allCommunities = [];
bool hasNext = true;
// Check if jsonData is actually a List
List<CommunityModel> 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<dynamic> jsonData = json['data'];
hasNext = json['hasNext'] ?? false;
int currentPage = json['page'] ?? 1;
List<CommunityModel> 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<CommunityModel?> 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<CommunityModel?> createCommunity(String name, String description) async {
Future<CommunityModel?> createCommunity(
String name, String description) async {
try {
final response = await HTTPService().post(
path: ApiEndpoints.createCommunity,
@@ -67,7 +78,8 @@ class CommunitySpaceManagementApi {
Future<bool> 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<bool> 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<List<SpaceModel>> 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;
},