Compare commits

..

9 Commits

4 changed files with 150 additions and 201 deletions

View File

@ -12,77 +12,89 @@ class DeviceSearchFilters extends StatefulWidget {
State<DeviceSearchFilters> createState() => _DeviceSearchFiltersState(); State<DeviceSearchFilters> createState() => _DeviceSearchFiltersState();
} }
class _DeviceSearchFiltersState extends State<DeviceSearchFilters> with HelperResponsiveLayout { class _DeviceSearchFiltersState extends State<DeviceSearchFilters>
final TextEditingController communityController = TextEditingController(); with HelperResponsiveLayout {
final TextEditingController unitNameController = TextEditingController(); late final TextEditingController _unitNameController;
final TextEditingController productNameController = TextEditingController(); late final TextEditingController _productNameController;
@override
void initState() {
_unitNameController = TextEditingController();
_productNameController = TextEditingController();
super.initState();
}
@override
void dispose() {
_unitNameController.dispose();
_productNameController.dispose();
super.dispose();
}
List<Widget> get _widgets => [
_buildSearchField(
"Space Name",
_unitNameController,
200,
),
_buildSearchField(
"Device Name / Product Name",
_productNameController,
300,
),
_buildSearchResetButtons(),
];
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return isExtraLargeScreenSize(context) if (isExtraLargeScreenSize(context)) {
? Row( return Row(
children: [ spacing: 20,
_buildSearchField("Community", communityController, 200), children: _widgets,
const SizedBox(width: 20), );
_buildSearchField("Space Name", unitNameController, 200), }
const SizedBox(width: 20),
_buildSearchField("Device Name / Product Name", productNameController, 300), return Wrap(
const SizedBox(width: 20), spacing: 20,
_buildSearchResetButtons(), runSpacing: 10,
], children: _widgets,
) );
: Wrap(
spacing: 20,
runSpacing: 10,
children: [
_buildSearchField(
"Community",
communityController,
200,
),
_buildSearchField("Space Name", unitNameController, 200),
_buildSearchField(
"Device Name / Product Name",
productNameController,
300,
),
_buildSearchResetButtons(),
],
);
} }
Widget _buildSearchField(String title, TextEditingController controller, double width) { Widget _buildSearchField(
return Container( String title,
child: StatefulTextField( TextEditingController controller,
title: title, double width,
width: width, ) {
elevation: 2, return StatefulTextField(
controller: controller, title: title,
onSubmitted: () { width: width,
context.read<DeviceManagementBloc>().add(SearchDevices( elevation: 2,
productName: productNameController.text, controller: controller,
unitName: unitNameController.text, onSubmitted: () {
community: communityController.text, final searchDevicesEvent = SearchDevices(
searchField: true)); productName: _productNameController.text,
}, unitName: _unitNameController.text,
onChanged: (p0) {}, searchField: true,
), );
context.read<DeviceManagementBloc>().add(searchDevicesEvent);
},
onChanged: (p0) {},
); );
} }
Widget _buildSearchResetButtons() { Widget _buildSearchResetButtons() {
return SearchResetButtons( return SearchResetButtons(
onSearch: () { onSearch: () => context.read<DeviceManagementBloc>().add(
context.read<DeviceManagementBloc>().add(SearchDevices( SearchDevices(
community: communityController.text, unitName: _unitNameController.text,
unitName: unitNameController.text, productName: _productNameController.text,
productName: productNameController.text, searchField: true,
searchField: true)); ),
}, ),
onReset: () { onReset: () {
communityController.clear(); _unitNameController.clear();
unitNameController.clear(); _productNameController.clear();
productNameController.clear();
context.read<DeviceManagementBloc>() context.read<DeviceManagementBloc>()
..add(ResetFilters()) ..add(ResetFilters())
..add(FetchDevices(context)); ..add(FetchDevices(context));

View File

@ -28,11 +28,10 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
try { try {
final updatedCommunity = event.updatedCommunity; final updatedCommunity = event.updatedCommunity;
final updatedCommunities = final updatedCommunities = List<CommunityModel>.from(state.communityList);
List<CommunityModel>.from(state.communityList);
final index = updatedCommunities final index =
.indexWhere((community) => community.uuid == updatedCommunity.uuid); updatedCommunities.indexWhere((community) => community.uuid == updatedCommunity.uuid);
if (index != -1) { if (index != -1) {
updatedCommunities[index] = updatedCommunity; updatedCommunities[index] = updatedCommunity;
@ -51,47 +50,41 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
final projectUuid = await ProjectManager.getProjectUUID() ?? ''; final projectUuid = await ProjectManager.getProjectUUID() ?? '';
List<CommunityModel> communities = List<CommunityModel> communities =
await CommunitySpaceManagementApi().fetchCommunities(projectUuid); await CommunitySpaceManagementApi().fetchCommunities(projectUuid, includeSpaces: true);
List<CommunityModel> updatedCommunities = await Future.wait( // List<CommunityModel> updatedCommunities = await Future.wait(
communities.map((community) async { // communities.map((community) async {
List<SpaceModel> spaces = await CommunitySpaceManagementApi() // List<SpaceModel> spaces =
.getSpaceHierarchy(community.uuid, projectUuid); // await CommunitySpaceManagementApi().getSpaceHierarchy(community.uuid, projectUuid);
return CommunityModel( // return CommunityModel(
uuid: community.uuid, // uuid: community.uuid,
createdAt: community.createdAt, // createdAt: community.createdAt,
updatedAt: community.updatedAt, // updatedAt: community.updatedAt,
name: community.name, // name: community.name,
description: community.description, // description: community.description,
spaces: spaces, // spaces: spaces,
region: community.region, // region: community.region,
); // );
}).toList(), // }).toList(),
); // );
emit(state.copyWith( emit(state.copyWith(communitiesList: communities, expandedCommunity: [], expandedSpaces: []));
communitiesList: updatedCommunities,
expandedCommunity: [],
expandedSpaces: []));
} catch (e) { } catch (e) {
emit(SpaceTreeErrorState('Error loading communities and spaces: $e')); emit(SpaceTreeErrorState('Error loading communities and spaces: $e'));
} }
} }
void _onCommunityAdded( void _onCommunityAdded(OnCommunityAdded event, Emitter<SpaceTreeState> emit) async {
OnCommunityAdded event, Emitter<SpaceTreeState> emit) async {
final updatedCommunities = List<CommunityModel>.from(state.communityList); final updatedCommunities = List<CommunityModel>.from(state.communityList);
updatedCommunities.add(event.newCommunity); updatedCommunities.add(event.newCommunity);
emit(state.copyWith(communitiesList: updatedCommunities)); emit(state.copyWith(communitiesList: updatedCommunities));
} }
_onCommunityExpanded( _onCommunityExpanded(OnCommunityExpanded event, Emitter<SpaceTreeState> emit) async {
OnCommunityExpanded event, Emitter<SpaceTreeState> emit) async {
try { try {
List<String> updatedExpandedCommunityList = List<String> updatedExpandedCommunityList = List.from(state.expandedCommunities);
List.from(state.expandedCommunities);
if (updatedExpandedCommunityList.contains(event.communityId)) { if (updatedExpandedCommunityList.contains(event.communityId)) {
updatedExpandedCommunityList.remove(event.communityId); updatedExpandedCommunityList.remove(event.communityId);
@ -123,19 +116,14 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
} }
} }
_onCommunitySelected( _onCommunitySelected(OnCommunitySelected event, Emitter<SpaceTreeState> emit) async {
OnCommunitySelected event, Emitter<SpaceTreeState> emit) async {
try { try {
List<String> updatedSelectedCommunities = List<String> updatedSelectedCommunities =
List.from(state.selectedCommunities.toSet().toList()); List.from(state.selectedCommunities.toSet().toList());
List<String> updatedSelectedSpaces = List<String> updatedSelectedSpaces = List.from(state.selectedSpaces.toSet().toList());
List.from(state.selectedSpaces.toSet().toList()); List<String> updatedSoldChecks = List.from(state.soldCheck.toSet().toList());
List<String> updatedSoldChecks = Map<String, List<String>> communityAndSpaces = Map.from(state.selectedCommunityAndSpaces);
List.from(state.soldCheck.toSet().toList()); List<String> selectedSpacesInCommunity = communityAndSpaces[event.communityId] ?? [];
Map<String, List<String>> communityAndSpaces =
Map.from(state.selectedCommunityAndSpaces);
List<String> selectedSpacesInCommunity =
communityAndSpaces[event.communityId] ?? [];
List<String> childrenIds = _getAllChildIds(event.children); List<String> childrenIds = _getAllChildIds(event.children);
@ -168,15 +156,11 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
try { try {
List<String> updatedSelectedCommunities = List<String> updatedSelectedCommunities =
List.from(state.selectedCommunities.toSet().toList()); List.from(state.selectedCommunities.toSet().toList());
List<String> updatedSelectedSpaces = List<String> updatedSelectedSpaces = List.from(state.selectedSpaces.toSet().toList());
List.from(state.selectedSpaces.toSet().toList()); List<String> updatedSoldChecks = List.from(state.soldCheck.toSet().toList());
List<String> updatedSoldChecks = Map<String, List<String>> communityAndSpaces = Map.from(state.selectedCommunityAndSpaces);
List.from(state.soldCheck.toSet().toList());
Map<String, List<String>> communityAndSpaces =
Map.from(state.selectedCommunityAndSpaces);
List<String> selectedSpacesInCommunity = List<String> selectedSpacesInCommunity = communityAndSpaces[event.communityModel.uuid] ?? [];
communityAndSpaces[event.communityModel.uuid] ?? [];
List<String> childrenIds = _getAllChildIds(event.children); List<String> childrenIds = _getAllChildIds(event.children);
bool isChildSelected = false; bool isChildSelected = false;
@ -199,11 +183,9 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
selectedSpacesInCommunity.addAll(childrenIds); selectedSpacesInCommunity.addAll(childrenIds);
} }
List<String> spaces = List<String> spaces = _getThePathToChild(event.communityModel.uuid, event.spaceId);
_getThePathToChild(event.communityModel.uuid, event.spaceId);
for (String space in spaces) { for (String space in spaces) {
if (!updatedSelectedSpaces.contains(space) && if (!updatedSelectedSpaces.contains(space) && !updatedSoldChecks.contains(space)) {
!updatedSoldChecks.contains(space)) {
updatedSoldChecks.add(space); updatedSoldChecks.add(space);
} }
} }
@ -226,9 +208,7 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
updatedSoldChecks.remove(event.spaceId); updatedSoldChecks.remove(event.spaceId);
List<String> parents = List<String> parents =
_getThePathToChild(event.communityModel.uuid, event.spaceId) _getThePathToChild(event.communityModel.uuid, event.spaceId).toSet().toList();
.toSet()
.toList();
if (updatedSelectedSpaces.isEmpty) { if (updatedSelectedSpaces.isEmpty) {
updatedSoldChecks.removeWhere(parents.contains); updatedSoldChecks.removeWhere(parents.contains);
@ -236,8 +216,7 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
} else { } else {
// Check if any parent has selected children // Check if any parent has selected children
for (String space in parents) { for (String space in parents) {
if (!_noChildrenSelected( if (!_noChildrenSelected(event.communityModel, space, updatedSelectedSpaces, parents)) {
event.communityModel, space, updatedSelectedSpaces, parents)) {
updatedSoldChecks.remove(space); updatedSoldChecks.remove(space);
} }
} }
@ -262,8 +241,8 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
} }
} }
_noChildrenSelected(CommunityModel community, String spaceId, _noChildrenSelected(
List<String> selectedSpaces, List<String> parents) { CommunityModel community, String spaceId, List<String> selectedSpaces, List<String> parents) {
if (selectedSpaces.contains(spaceId)) { if (selectedSpaces.contains(spaceId)) {
return true; return true;
} }
@ -290,11 +269,10 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
// Filter communities and expand only those that match the query // Filter communities and expand only those that match the query
filteredCommunity = communities.where((community) { filteredCommunity = communities.where((community) {
final containsQueryInCommunity = community.name final containsQueryInCommunity =
.toLowerCase() community.name.toLowerCase().contains(event.searchQuery.toLowerCase());
.contains(event.searchQuery.toLowerCase()); final containsQueryInSpaces =
final containsQueryInSpaces = community.spaces.any( community.spaces.any((space) => _containsQuery(space, event.searchQuery.toLowerCase()));
(space) => _containsQuery(space, event.searchQuery.toLowerCase()));
return containsQueryInCommunity || containsQueryInSpaces; return containsQueryInCommunity || containsQueryInSpaces;
}).toList(); }).toList();
@ -347,8 +325,8 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
// Helper function to determine if any space or its children match the search query // Helper function to determine if any space or its children match the search query
bool _containsQuery(SpaceModel space, String query) { bool _containsQuery(SpaceModel space, String query) {
final matchesSpace = space.name.toLowerCase().contains(query); final matchesSpace = space.name.toLowerCase().contains(query);
final matchesChildren = space.children.any((child) => final matchesChildren =
_containsQuery(child, query)); // Recursive check for children space.children.any((child) => _containsQuery(child, query)); // Recursive check for children
return matchesSpace || matchesChildren; return matchesSpace || matchesChildren;
} }
@ -371,8 +349,8 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
return children; return children;
} }
bool _anySpacesSelectedInCommunity(CommunityModel community, bool _anySpacesSelectedInCommunity(
List<String> selectedSpaces, List<String> partialCheckedList) { CommunityModel community, List<String> selectedSpaces, List<String> partialCheckedList) {
bool result = false; bool result = false;
List<String> ids = _getAllChildIds(community.spaces); List<String> ids = _getAllChildIds(community.spaces);
for (var id in ids) { for (var id in ids) {
@ -401,8 +379,7 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
return ids; return ids;
} }
List<String> _getAllParentsIds( List<String> _getAllParentsIds(SpaceModel child, String spaceId, List<String> listIds) {
SpaceModel child, String spaceId, List<String> listIds) {
List<String> ids = listIds; List<String> ids = listIds;
ids.add(child.uuid ?? ''); ids.add(child.uuid ?? '');

View File

@ -262,27 +262,6 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
return; return;
} }
if (communities.isEmpty) {
communities = await _api.fetchCommunities(projectUuid);
List<CommunityModel> updatedCommunities = await Future.wait(
communities.map((community) async {
List<SpaceModel> spaces = await _fetchSpacesForCommunity(community.uuid);
return CommunityModel(
uuid: community.uuid,
createdAt: community.createdAt,
updatedAt: community.updatedAt,
name: community.name,
description: community.description,
spaces: spaces,
region: community.region,
);
}).toList(),
);
communities = updatedCommunities;
}
emit(BlankState( emit(BlankState(
spaceModels: prevSpaceModels, spaceModels: prevSpaceModels,
communities: communities, communities: communities,
@ -540,7 +519,7 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
List<TagModelUpdate> tagUpdates = []; List<TagModelUpdate> tagUpdates = [];
List<SpaceModel> matchedSpaces = List<SpaceModel> matchedSpaces =
selectedCommunity.spaces.where((space) => space.uuid == space.uuid).toList(); findMatchingSpaces(selectedCommunity.spaces, space.uuid!);
if (matchedSpaces.isEmpty) continue; if (matchedSpaces.isEmpty) continue;
@ -696,27 +675,6 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
var prevSpaceModels = await fetchSpaceModels(); var prevSpaceModels = await fetchSpaceModels();
if (communities.isEmpty) {
communities = await _api.fetchCommunities(projectUuid);
List<CommunityModel> updatedCommunities = await Future.wait(
communities.map((community) async {
List<SpaceModel> spaces = await _fetchSpacesForCommunity(community.uuid);
return CommunityModel(
uuid: community.uuid,
createdAt: community.createdAt,
updatedAt: community.updatedAt,
name: community.name,
description: community.description,
spaces: spaces,
region: community.region,
);
}).toList(),
);
communities = updatedCommunities;
}
emit(SpaceModelLoaded( emit(SpaceModelLoaded(
communities: communities, communities: communities,
products: _cachedProducts ?? [], products: _cachedProducts ?? [],
@ -799,4 +757,18 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
return tagUpdates; return tagUpdates;
} }
List<SpaceModel> findMatchingSpaces(List<SpaceModel> spaces, String targetUuid) {
List<SpaceModel> matched = [];
for (var space in spaces) {
if (space.uuid == targetUuid) {
matched.add(space);
}
matched
.addAll(findMatchingSpaces(space.children, targetUuid)); // Recursively search in children
}
return matched;
}
} }

View File

@ -3,27 +3,24 @@ import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_m
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/create_subspace_model.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/create_subspace_model.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_response_model.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_response_model.dart';
import 'package:syncrow_web/pages/spaces_management/space_model/models/create_space_template_body_model.dart';
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_body_model.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_body_model.dart';
import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_update_model.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_update_model.dart';
import 'package:syncrow_web/services/api/http_service.dart'; import 'package:syncrow_web/services/api/http_service.dart';
import 'package:syncrow_web/utils/constants/api_const.dart'; import 'package:syncrow_web/utils/constants/api_const.dart';
import 'package:syncrow_web/utils/constants/temp_const.dart';
class CommunitySpaceManagementApi { class CommunitySpaceManagementApi {
// Community Management APIs // Community Management APIs
Future<List<CommunityModel>> fetchCommunities(String projectId, Future<List<CommunityModel>> fetchCommunities(String projectId,
{int page = 1}) async { {int page = 1, bool includeSpaces = false}) async {
try { try {
List<CommunityModel> allCommunities = []; List<CommunityModel> allCommunities = [];
bool hasNext = true; bool hasNext = true;
while (hasNext) { while (hasNext) {
await HTTPService().get( await HTTPService().get(
path: ApiEndpoints.getCommunityList path: ApiEndpoints.getCommunityList.replaceAll('{projectId}', projectId),
.replaceAll('{projectId}', projectId), queryParameters: {'page': page, 'includeSpaces': includeSpaces},
queryParameters: {'page': page},
expectedResponseModel: (json) { expectedResponseModel: (json) {
try { try {
List<dynamic> jsonData = json['data'] ?? []; List<dynamic> jsonData = json['data'] ?? [];
@ -52,8 +49,7 @@ class CommunitySpaceManagementApi {
Future<CommunityModel?> getCommunityById(String communityId) async { Future<CommunityModel?> getCommunityById(String communityId) async {
try { try {
final response = await HTTPService().get( final response = await HTTPService().get(
path: ApiEndpoints.getCommunityById path: ApiEndpoints.getCommunityById.replaceAll('{communityId}', communityId),
.replaceAll('{communityId}', communityId),
expectedResponseModel: (json) { expectedResponseModel: (json) {
return CommunityModel.fromJson(json['data']); return CommunityModel.fromJson(json['data']);
}, },
@ -65,8 +61,7 @@ class CommunitySpaceManagementApi {
} }
} }
Future<CommunityModel?> createCommunity( Future<CommunityModel?> createCommunity(String name, String description, String projectId) async {
String name, String description, String projectId) async {
try { try {
final response = await HTTPService().post( final response = await HTTPService().post(
path: ApiEndpoints.createCommunity.replaceAll('{projectId}', projectId), path: ApiEndpoints.createCommunity.replaceAll('{projectId}', projectId),
@ -85,8 +80,7 @@ class CommunitySpaceManagementApi {
} }
} }
Future<bool> updateCommunity( Future<bool> updateCommunity(String communityId, String name, String projectId) async {
String communityId, String name, String projectId) async {
try { try {
final response = await HTTPService().put( final response = await HTTPService().put(
path: ApiEndpoints.updateCommunity path: ApiEndpoints.updateCommunity
@ -123,8 +117,7 @@ class CommunitySpaceManagementApi {
} }
} }
Future<SpacesResponse> fetchSpaces( Future<SpacesResponse> fetchSpaces(String communityId, String projectId) async {
String communityId, String projectId) async {
try { try {
final response = await HTTPService().get( final response = await HTTPService().get(
path: ApiEndpoints.listSpaces path: ApiEndpoints.listSpaces
@ -150,8 +143,7 @@ class CommunitySpaceManagementApi {
} }
} }
Future<SpaceModel?> getSpace( Future<SpaceModel?> getSpace(String communityId, String spaceId, String projectId) async {
String communityId, String spaceId, String projectId) async {
try { try {
final response = await HTTPService().get( final response = await HTTPService().get(
path: ApiEndpoints.getSpace path: ApiEndpoints.getSpace
@ -262,8 +254,7 @@ class CommunitySpaceManagementApi {
} }
} }
Future<bool> deleteSpace( Future<bool> deleteSpace(String communityId, String spaceId, String projectId) async {
String communityId, String spaceId, String projectId) async {
try { try {
final response = await HTTPService().delete( final response = await HTTPService().delete(
path: ApiEndpoints.deleteSpace path: ApiEndpoints.deleteSpace
@ -281,17 +272,15 @@ class CommunitySpaceManagementApi {
} }
} }
Future<List<SpaceModel>> getSpaceHierarchy( Future<List<SpaceModel>> getSpaceHierarchy(String communityId, String projectId) async {
String communityId, String projectId) async {
try { try {
final response = await HTTPService().get( final response = await HTTPService().get(
path: ApiEndpoints.getSpaceHierarchy path: ApiEndpoints.getSpaceHierarchy
.replaceAll('{communityId}', communityId) .replaceAll('{communityId}', communityId)
.replaceAll('{projectId}', projectId), .replaceAll('{projectId}', projectId),
expectedResponseModel: (json) { expectedResponseModel: (json) {
final spaceModels = (json['data'] as List) final spaceModels =
.map((spaceJson) => SpaceModel.fromJson(spaceJson)) (json['data'] as List).map((spaceJson) => SpaceModel.fromJson(spaceJson)).toList();
.toList();
return spaceModels; return spaceModels;
}, },
@ -302,17 +291,16 @@ class CommunitySpaceManagementApi {
return []; return [];
} }
} }
Future<List<SpaceModel>> getSpaceOnlyWithDevices(
{String? communityId, String? projectId}) async { Future<List<SpaceModel>> getSpaceOnlyWithDevices({String? communityId, String? projectId}) async {
try { try {
final response = await HTTPService().get( final response = await HTTPService().get(
path: ApiEndpoints.spaceOnlyWithDevices path: ApiEndpoints.spaceOnlyWithDevices
.replaceAll('{communityId}', communityId!) .replaceAll('{communityId}', communityId!)
.replaceAll('{projectId}', projectId!), .replaceAll('{projectId}', projectId!),
expectedResponseModel: (json) { expectedResponseModel: (json) {
final spaceModels = (json['data'] as List) final spaceModels =
.map((spaceJson) => SpaceModel.fromJson(spaceJson)) (json['data'] as List).map((spaceJson) => SpaceModel.fromJson(spaceJson)).toList();
.toList();
return spaceModels; return spaceModels;
}, },
); );