added tags and subspace to update space

This commit is contained in:
hannathkadher
2025-01-29 09:55:36 +04:00
parent 45b0b67fe0
commit 9331193e90
4 changed files with 205 additions and 37 deletions

View File

@ -5,12 +5,15 @@ import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_mod
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/bloc/space_management_event.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_event.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_state.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_state.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/subspace_model.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.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/services/product_api.dart'; import 'package:syncrow_web/services/product_api.dart';
import 'package:syncrow_web/services/space_mana_api.dart'; import 'package:syncrow_web/services/space_mana_api.dart';
import 'package:syncrow_web/services/space_model_mang_api.dart'; import 'package:syncrow_web/services/space_model_mang_api.dart';
import 'package:syncrow_web/utils/constants/action_enum.dart';
class SpaceManagementBloc class SpaceManagementBloc
extends Bloc<SpaceManagementEvent, SpaceManagementState> { extends Bloc<SpaceManagementEvent, SpaceManagementState> {
@ -341,7 +344,7 @@ class SpaceManagementBloc
products: _cachedProducts ?? [], products: _cachedProducts ?? [],
selectedCommunity: selectedCommunity, selectedCommunity: selectedCommunity,
selectedSpace: selectedSpace, selectedSpace: selectedSpace,
spaceModels: spaceModels ?? [])); spaceModels: spaceModels));
} }
} catch (e) { } catch (e) {
emit(SpaceManagementError('Error updating state: $e')); emit(SpaceManagementError('Error updating state: $e'));
@ -428,16 +431,72 @@ class SpaceManagementBloc
for (var space in orderedSpaces) { for (var space in orderedSpaces) {
try { try {
if (space.uuid != null && space.uuid!.isNotEmpty) { if (space.uuid != null && space.uuid!.isNotEmpty) {
final response = await _api.updateSpace( final prevSpace = await _api.getSpace(communityUuid, space.uuid!);
communityId: communityUuid, final List<UpdateSubspaceTemplateModel> subspaceUpdates = [];
spaceId: space.uuid!, final List<SubspaceModel>? prevSubspaces = prevSpace?.subspaces;
name: space.name, final List<SubspaceModel>? newSubspaces = space.subspaces;
parentId: space.parent?.uuid,
isPrivate: space.isPrivate, if (prevSubspaces != null || newSubspaces != null) {
position: space.position, if (prevSubspaces != null && newSubspaces != null) {
icon: space.icon, for (var prevSubspace in prevSubspaces) {
direction: space.incomingConnection?.direction, final existsInNew = newSubspaces
); .any((subspace) => subspace.uuid == prevSubspace.uuid);
if (!existsInNew) {
subspaceUpdates.add(UpdateSubspaceTemplateModel(
action: Action.delete, uuid: prevSubspace.uuid));
}
}
} else if (prevSubspaces != null && newSubspaces == null) {
for (var prevSubspace in prevSubspaces) {
subspaceUpdates.add(UpdateSubspaceTemplateModel(
action: Action.delete, uuid: prevSubspace.uuid));
}
}
if (newSubspaces != null) {
for (var newSubspace in newSubspaces) {
// Tag without UUID
if ((newSubspace.uuid == null || newSubspace.uuid!.isEmpty)) {
final List<TagModelUpdate> tagUpdates = [];
if (newSubspace.tags != null) {
for (var tag in newSubspace.tags!) {
tagUpdates.add(TagModelUpdate(
action: Action.add,
uuid: tag.uuid == '' ? null : tag.uuid,
tag: tag.tag,
productUuid: tag.product?.uuid));
}
}
subspaceUpdates.add(UpdateSubspaceTemplateModel(
action: Action.add,
subspaceName: newSubspace.subspaceName,
tags: tagUpdates));
}
}
}
if (prevSubspaces != null && newSubspaces != null) {
final newSubspaceMap = {
for (var subspace in newSubspaces) subspace.uuid: subspace
};
for (var prevSubspace in prevSubspaces) {
final newSubspace = newSubspaceMap[prevSubspace.uuid];
if (newSubspace != null) {
final List<TagModelUpdate> tagSubspaceUpdates =
processTagUpdates(prevSubspace.tags, newSubspace.tags);
subspaceUpdates.add(UpdateSubspaceTemplateModel(
action: Action.update,
uuid: newSubspace.uuid,
subspaceName: newSubspace.subspaceName,
tags: tagSubspaceUpdates));
}
}
}
}
} else { } else {
// Call create if the space does not have a UUID // Call create if the space does not have a UUID
final List<CreateTagBodyModel> tagBodyModels = space.tags != null final List<CreateTagBodyModel> tagBodyModels = space.tags != null
@ -455,6 +514,7 @@ class SpaceManagementBloc
}).toList() ?? }).toList() ??
[]; [];
final response = await _api.createSpace( final response = await _api.createSpace(
communityId: communityUuid, communityId: communityUuid,
name: space.name, name: space.name,
@ -535,4 +595,80 @@ class SpaceManagementBloc
emit(SpaceManagementError('Error loading communities and spaces: $e')); emit(SpaceManagementError('Error loading communities and spaces: $e'));
} }
} }
List<TagModelUpdate> processTagUpdates(
List<Tag>? prevTags,
List<Tag>? newTags,
) {
final List<TagModelUpdate> tagUpdates = [];
final processedTags = <String?>{};
if (prevTags == null && newTags != null) {
for (var newTag in newTags) {
tagUpdates.add(TagModelUpdate(
action: Action.add,
tag: newTag.tag,
uuid: newTag.uuid,
productUuid: newTag.product?.uuid,
));
}
return tagUpdates;
}
if (newTags != null || prevTags != null) {
// Case 1: Tags deleted
if (prevTags != null && newTags != null) {
for (var prevTag in prevTags) {
final existsInNew =
newTags.any((newTag) => newTag.uuid == prevTag.uuid);
if (!existsInNew) {
tagUpdates
.add(TagModelUpdate(action: Action.delete, uuid: prevTag.uuid));
}
}
} else if (prevTags != null && newTags == null) {
for (var prevTag in prevTags) {
tagUpdates
.add(TagModelUpdate(action: Action.delete, uuid: prevTag.uuid));
}
}
// Case 2: Tags added
if (newTags != null) {
final prevTagUuids = prevTags?.map((t) => t.uuid).toSet() ?? {};
for (var newTag in newTags) {
// Tag without UUID
if ((newTag.uuid == null || !prevTagUuids.contains(newTag.uuid)) &&
!processedTags.contains(newTag.tag)) {
tagUpdates.add(TagModelUpdate(
action: Action.add,
tag: newTag.tag,
uuid: newTag.uuid == '' ? null : newTag.uuid,
productUuid: newTag.product?.uuid));
processedTags.add(newTag.tag);
}
}
}
// Case 3: Tags updated
if (prevTags != null && newTags != null) {
final newTagMap = {for (var tag in newTags) tag.uuid: tag};
for (var prevTag in prevTags) {
final newTag = newTagMap[prevTag.uuid];
if (newTag != null) {
tagUpdates.add(TagModelUpdate(
action: Action.update,
uuid: newTag.uuid,
tag: newTag.tag,
));
} else {}
}
}
}
return tagUpdates;
}
} }

View File

@ -79,6 +79,8 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
widget.selectedProducts.isNotEmpty ? widget.selectedProducts : []; widget.selectedProducts.isNotEmpty ? widget.selectedProducts : [];
isOkButtonEnabled = isOkButtonEnabled =
enteredName.isNotEmpty || nameController.text.isNotEmpty; enteredName.isNotEmpty || nameController.text.isNotEmpty;
tags = widget.tags ?? [];
subspaces = widget.subspaces ?? [];
} }
@override @override
@ -237,7 +239,7 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
), ),
) )
: Container( : Container(
width: screenWidth * 0.35, width: screenWidth * 0.25,
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
vertical: 10.0, horizontal: 16.0), vertical: 10.0, horizontal: 16.0),
decoration: BoxDecoration( decoration: BoxDecoration(
@ -312,7 +314,7 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
], ],
), ),
const SizedBox(height: 25), const SizedBox(height: 25),
subspaces == null subspaces == null || subspaces!.isEmpty
? TextButton( ? TextButton(
style: TextButton.styleFrom( style: TextButton.styleFrom(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
@ -344,21 +346,29 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
runSpacing: 8.0, runSpacing: 8.0,
children: [ children: [
if (subspaces != null) if (subspaces != null)
...subspaces!.map((subspace) => ...subspaces!.map((subspace) {
return Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
SubspaceNameDisplayWidget( SubspaceNameDisplayWidget(
validateName: (updatedName) {
return !subspaces!.any((s) =>
s != subspace &&
s.subspaceName == updatedName);
},
text: subspace.subspaceName, text: subspace.subspaceName,
validateName: (updatedName) {
return subspaces!.any((s) =>
s != subspace &&
s.subspaceName ==
updatedName);
},
onNameChanged: (updatedName) { onNameChanged: (updatedName) {
setState(() { setState(() {
subspace.subspaceName = subspace.subspaceName =
updatedName; updatedName;
}); });
}, },
)), ),
],
);
}),
EditChip( EditChip(
onTap: () async { onTap: () async {
_showSubSpaceDialog(context, enteredName, _showSubSpaceDialog(context, enteredName,
@ -425,14 +435,29 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
), ),
EditChip(onTap: () async { EditChip(onTap: () async {
_showTagCreateDialog( final result = await showDialog(
context, context: context,
enteredName, builder: (context) => AssignTagDialog(
widget.isEdit, products: widget.products,
widget.products, subspaces: widget.subspaces,
subspaces, addedProducts: TagHelper
.createInitialSelectedProductsForTags(
tags ?? [], subspaces),
title: 'Edit Device',
initialTags:
TagHelper.generateInitialForTags(
spaceTags: tags,
subspaces: subspaces),
spaceName: widget.name ?? '',
onSave:
(updatedTags, updatedSubspaces) {
setState(() {
tags = updatedTags;
subspaces = updatedSubspaces;
});
},
),
); );
// Edit action
}) })
], ],
), ),
@ -547,6 +572,7 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
setState(() { setState(() {
selectedSpaceModel = selectedModel; selectedSpaceModel = selectedModel;
subspaces = null; subspaces = null;
tags = null;
}); });
} }
}, },
@ -610,6 +636,7 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
products: products, products: products,
subspaces: subspaces, subspaces: subspaces,
spaceTags: tags, spaceTags: tags,
isCreate: true,
allTags: [], allTags: [],
initialSelectedProducts: initialSelectedProducts:
TagHelper.createInitialSelectedProductsForTags( TagHelper.createInitialSelectedProductsForTags(

View File

@ -82,7 +82,6 @@ class SubSpaceBloc extends Bloc<SubSpaceEvent, SubSpaceState> {
)); ));
}); });
on<UpdateSubSpace>((event, emit) { on<UpdateSubSpace>((event, emit) {
final updatedSubSpaces = state.subSpaces.map((subSpace) { final updatedSubSpaces = state.subSpaces.map((subSpace) {
if (subSpace.uuid == event.updatedSubSpace.uuid) { if (subSpace.uuid == event.updatedSubSpace.uuid) {

View File

@ -4,7 +4,9 @@ import 'package:syncrow_web/pages/spaces_management/all_spaces/model/create_subs
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/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/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/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'; import 'package:syncrow_web/utils/constants/temp_const.dart';
@ -219,6 +221,8 @@ class CommunitySpaceManagementApi {
String? direction, String? direction,
bool isPrivate = false, bool isPrivate = false,
required Offset position, required Offset position,
List<TagModelUpdate>? tags,
List<UpdateSubspaceTemplateModel>? subspaces,
}) async { }) async {
try { try {
final body = { final body = {
@ -228,6 +232,8 @@ class CommunitySpaceManagementApi {
'y': position.dy, 'y': position.dy,
'direction': direction, 'direction': direction,
'icon': icon, 'icon': icon,
'subspace':subspaces,
'tags':tags,
}; };
if (parentId != null) { if (parentId != null) {
body['parentUuid'] = parentId; body['parentUuid'] = parentId;