From f35b699d4c7b2afb433e255d79db53a2ca185e46 Mon Sep 17 00:00:00 2001 From: hannathkadher Date: Wed, 22 Jan 2025 12:49:47 +0400 Subject: [PATCH] fixed the edit flow for space model --- .../widgets/device_type_tile_widget.dart | 1 + .../bloc/space_management_state.dart | 15 +- .../widgets/add_device_type_widget.dart | 1 + .../all_spaces/widgets/counter_widget.dart | 25 +- .../views/assign_tag_models_dialog.dart | 37 ++- .../views/create_subspace_model_dialog.dart | 6 +- .../spaces_management/helper/tag_helper.dart | 3 +- .../bloc/create_space_model_bloc.dart | 228 +++++++++++++++++- .../bloc/create_space_model_event.dart | 15 +- .../space_model/bloc/space_model_bloc.dart | 20 ++ .../space_model/bloc/space_model_event.dart | 18 ++ .../create_space_template_body_model.dart | 4 +- .../models/space_template_model.dart | 47 +--- .../space_model/models/tag_update_model.dart | 34 +++ .../space_model/view/space_model_page.dart | 2 +- .../dialog/create_space_model_dialog.dart | 64 ++++- .../widgets/subspace_chip_widget.dart | 3 - .../widgets/subspace_model_create_widget.dart | 34 +-- .../widgets/tag_chips_display_widget.dart | 2 + .../views/add_device_type_model_widget.dart | 47 +++- .../widgets/device_type_tile_widget.dart | 12 +- .../widgets/scrollable_grid_view_widget.dart | 5 +- lib/services/space_model_mang_api.dart | 14 ++ lib/utils/constants/api_const.dart | 7 +- 24 files changed, 517 insertions(+), 127 deletions(-) create mode 100644 lib/pages/spaces_management/space_model/models/tag_update_model.dart diff --git a/lib/pages/spaces_management/add_device_type/widgets/device_type_tile_widget.dart b/lib/pages/spaces_management/add_device_type/widgets/device_type_tile_widget.dart index 2feea7d9..08ad79ac 100644 --- a/lib/pages/spaces_management/add_device_type/widgets/device_type_tile_widget.dart +++ b/lib/pages/spaces_management/add_device_type/widgets/device_type_tile_widget.dart @@ -48,6 +48,7 @@ class DeviceTypeTileWidget extends StatelessWidget { DeviceNameWidget(name: product.name), const SizedBox(height: 4), CounterWidget( + isCreate: false, initialCount: selectedProduct.count, onCountChanged: (newCount) { context.read().add( diff --git a/lib/pages/spaces_management/all_spaces/bloc/space_management_state.dart b/lib/pages/spaces_management/all_spaces/bloc/space_management_state.dart index 635c244d..571651e5 100644 --- a/lib/pages/spaces_management/all_spaces/bloc/space_management_state.dart +++ b/lib/pages/spaces_management/all_spaces/bloc/space_management_state.dart @@ -27,8 +27,7 @@ class SpaceManagementLoaded extends SpaceManagementState { required this.products, this.selectedCommunity, this.selectedSpace, - this.spaceModels - }); + this.spaceModels}); } class SpaceModelManagenetLoaded extends SpaceManagementState { @@ -38,14 +37,10 @@ class SpaceModelManagenetLoaded extends SpaceManagementState { class BlankState extends SpaceManagementState { final List communities; final List products; - List? spaceModels; + List? spaceModels; - - BlankState({ - required this.communities, - required this.products, - this.spaceModels - }); + BlankState( + {required this.communities, required this.products, this.spaceModels}); } class SpaceCreationSuccess extends SpaceManagementState { @@ -67,7 +62,7 @@ class SpaceManagementError extends SpaceManagementState { } class SpaceModelLoaded extends SpaceManagementState { - final List spaceModels; + List spaceModels; final List products; final List communities; diff --git a/lib/pages/spaces_management/all_spaces/widgets/add_device_type_widget.dart b/lib/pages/spaces_management/all_spaces/widgets/add_device_type_widget.dart index 351eacce..0e9f4bd1 100644 --- a/lib/pages/spaces_management/all_spaces/widgets/add_device_type_widget.dart +++ b/lib/pages/spaces_management/all_spaces/widgets/add_device_type_widget.dart @@ -137,6 +137,7 @@ class _AddDeviceWidgetState extends State { _buildDeviceName(product, size), const SizedBox(height: 4), CounterWidget( + isCreate: false, initialCount: selectedProduct.count, onCountChanged: (newCount) { setState(() { diff --git a/lib/pages/spaces_management/all_spaces/widgets/counter_widget.dart b/lib/pages/spaces_management/all_spaces/widgets/counter_widget.dart index 66935b12..2289819b 100644 --- a/lib/pages/spaces_management/all_spaces/widgets/counter_widget.dart +++ b/lib/pages/spaces_management/all_spaces/widgets/counter_widget.dart @@ -4,12 +4,14 @@ import 'package:syncrow_web/utils/color_manager.dart'; class CounterWidget extends StatefulWidget { final int initialCount; final ValueChanged onCountChanged; + final bool isCreate; - const CounterWidget({ - Key? key, - this.initialCount = 0, - required this.onCountChanged, - }) : super(key: key); + const CounterWidget( + {Key? key, + this.initialCount = 0, + required this.onCountChanged, + required this.isCreate}) + : super(key: key); @override State createState() => _CounterWidgetState(); @@ -53,25 +55,26 @@ class _CounterWidgetState extends State { child: Row( mainAxisSize: MainAxisSize.min, children: [ - _buildCounterButton(Icons.remove, _decrementCounter), + _buildCounterButton(Icons.remove, _decrementCounter,!widget.isCreate ), const SizedBox(width: 8), Text( '$_counter', - style: theme.textTheme.bodyLarge?.copyWith(color: ColorsManager.spaceColor), + style: theme.textTheme.bodyLarge + ?.copyWith(color: ColorsManager.spaceColor), ), const SizedBox(width: 8), - _buildCounterButton(Icons.add, _incrementCounter), + _buildCounterButton(Icons.add, _incrementCounter, false), ], ), ); } - Widget _buildCounterButton(IconData icon, VoidCallback onPressed) { + Widget _buildCounterButton(IconData icon, VoidCallback onPressed, bool isDisabled) { return GestureDetector( - onTap: onPressed, + onTap: isDisabled? null: onPressed, child: Icon( icon, - color: ColorsManager.spaceColor, + color: isDisabled? ColorsManager.spaceColor.withOpacity(0.3): ColorsManager.spaceColor, size: 18, ), ); diff --git a/lib/pages/spaces_management/assign_tag_models/views/assign_tag_models_dialog.dart b/lib/pages/spaces_management/assign_tag_models/views/assign_tag_models_dialog.dart index d345a8c6..fc778436 100644 --- a/lib/pages/spaces_management/assign_tag_models/views/assign_tag_models_dialog.dart +++ b/lib/pages/spaces_management/assign_tag_models/views/assign_tag_models_dialog.dart @@ -19,6 +19,8 @@ import 'package:syncrow_web/utils/color_manager.dart'; class AssignTagModelsDialog extends StatelessWidget { final List? products; final List? subspaces; + final SpaceTemplateModel? spaceModel; + final List initialTags; final ValueChanged>? onTagsAssigned; final List addedProducts; @@ -39,7 +41,8 @@ class AssignTagModelsDialog extends StatelessWidget { required this.spaceName, required this.title, this.pageContext, - this.otherSpaceModels}) + this.otherSpaceModels, + this.spaceModel}) : super(key: key); @override @@ -210,7 +213,7 @@ class AssignTagModelsDialog extends StatelessWidget { child: DialogDropdown( items: locations, selectedValue: - tag.location ?? 'None', + tag.location ?? 'Main Space', onSelected: (value) { context .read< @@ -281,16 +284,23 @@ class AssignTagModelsDialog extends StatelessWidget { context: context, builder: (dialogContext) => AddDeviceTypeModelWidget( - products: products, - subspaces: subspaces, - isCreate: false, - initialSelectedProducts: addedProducts, - allTags: allTags, - spaceName: spaceName, - otherSpaceModels: otherSpaceModels, - spaceTagModels: state.tags, - pageContext: pageContext, - ), + products: products, + subspaces: subspaces, + isCreate: false, + initialSelectedProducts: + addedProducts, + allTags: allTags, + spaceName: spaceName, + otherSpaceModels: otherSpaceModels, + spaceTagModels: state.tags, + pageContext: pageContext, + spaceModel: SpaceTemplateModel( + modelName: spaceName, + tags: state.tags, + uuid: spaceModel?.uuid, + internalId: + spaceModel?.internalId, + subspaceModels: subspaces)), ); } }, @@ -348,6 +358,9 @@ class AssignTagModelsDialog extends StatelessWidget { spaceModel: SpaceTemplateModel( modelName: spaceName, tags: state.tags, + uuid: spaceModel?.uuid, + internalId: + spaceModel?.internalId, subspaceModels: subspaces), ); }, diff --git a/lib/pages/spaces_management/create_subspace_model/views/create_subspace_model_dialog.dart b/lib/pages/spaces_management/create_subspace_model/views/create_subspace_model_dialog.dart index 82aa3684..4c0cb99f 100644 --- a/lib/pages/spaces_management/create_subspace_model/views/create_subspace_model_dialog.dart +++ b/lib/pages/spaces_management/create_subspace_model/views/create_subspace_model_dialog.dart @@ -186,8 +186,7 @@ class CreateSubSpaceModelDialog extends StatelessWidget { const SizedBox(width: 10), Expanded( child: DefaultButton( - onPressed: (state.subSpaces.isEmpty || - state.errorMessage.isNotEmpty) + onPressed: (state.errorMessage.isNotEmpty) ? null : () async { final subSpaces = context @@ -201,8 +200,7 @@ class CreateSubSpaceModelDialog extends StatelessWidget { }, backgroundColor: ColorsManager.secondaryColor, borderRadius: 10, - foregroundColor: state.subSpaces.isEmpty || - state.errorMessage.isNotEmpty + foregroundColor: state.errorMessage.isNotEmpty ? ColorsManager.whiteColorsWithOpacity : ColorsManager.whiteColors, child: const Text('OK'), diff --git a/lib/pages/spaces_management/helper/tag_helper.dart b/lib/pages/spaces_management/helper/tag_helper.dart index bfff02a9..d4a0ea55 100644 --- a/lib/pages/spaces_management/helper/tag_helper.dart +++ b/lib/pages/spaces_management/helper/tag_helper.dart @@ -37,7 +37,8 @@ class TagHelper { final Map groupedTags = {}; for (var tag in tags) { if (tag.product != null) { - groupedTags[tag.product!] = (groupedTags[tag.product!] ?? 0) + 1; + final product = tag.product!; + groupedTags[product] = (groupedTags[product] ?? 0) + 1; } } return groupedTags; diff --git a/lib/pages/spaces_management/space_model/bloc/create_space_model_bloc.dart b/lib/pages/spaces_management/space_model/bloc/create_space_model_bloc.dart index 417ba1fd..40db384a 100644 --- a/lib/pages/spaces_management/space_model/bloc/create_space_model_bloc.dart +++ b/lib/pages/spaces_management/space_model/bloc/create_space_model_bloc.dart @@ -1,12 +1,12 @@ -import 'dart:math'; - import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/bloc/create_space_model_event.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/bloc/create_space_model_state.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_model.dart'; +import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_update_model.dart'; import 'package:syncrow_web/services/space_model_mang_api.dart'; +import 'package:syncrow_web/utils/constants/action_enum.dart'; class CreateSpaceModelBloc extends Bloc { @@ -193,5 +193,229 @@ class CreateSpaceModelBloc emit(CreateSpaceModelError("Space template not initialized")); } }); + + on((event, emit) async { + try { + final prevSpaceModel = event.spaceTemplate; + final newSpaceModel = event.updatedSpaceTemplate; + String? spaceModelName; + if (prevSpaceModel.modelName != newSpaceModel.modelName) { + spaceModelName = newSpaceModel.modelName; + } + List tagUpdates = []; + final List subspaceUpdates = []; + + tagUpdates = processTagUpdates(prevSpaceModel.tags, newSpaceModel.tags); + + if (prevSpaceModel.subspaceModels != null) { + for (var prevSubspace in prevSpaceModel.subspaceModels!) { + if (newSpaceModel.subspaceModels == null) { + subspaceUpdates.add(UpdateSubspaceTemplateModel( + action: Action.delete, + uuid: prevSubspace.uuid, + )); + continue; + } + + final subspaceExistsInNew = newSpaceModel.subspaceModels! + .any((newSubspace) => newSubspace.uuid == prevSubspace.uuid); + if (!subspaceExistsInNew) { + subspaceUpdates.add(UpdateSubspaceTemplateModel( + action: Action.delete, + uuid: prevSubspace.uuid, + )); + } + } + } + + if (newSpaceModel.subspaceModels != null) { + for (var newSubspaceModel in newSpaceModel.subspaceModels!) { + if (newSubspaceModel.uuid == null || + newSubspaceModel.uuid!.isEmpty) { + final List tagUpdatesInSubspace = []; + + if (newSubspaceModel.tags != null) { + for (var tag in newSubspaceModel.tags!) { + tagUpdatesInSubspace.add(TagModelUpdate( + action: Action.add, + uuid: tag.uuid, + tag: tag.tag, + productUuid: tag.product?.uuid, + )); + } + } + + subspaceUpdates.add(UpdateSubspaceTemplateModel( + action: Action.add, + subspaceName: newSubspaceModel.subspaceName, + tags: tagUpdatesInSubspace, + )); + } + } + } + + if (newSpaceModel.subspaceModels != null && + prevSpaceModel.subspaceModels != null) { + final prevSubspaceMap = { + for (var subspace in prevSpaceModel.subspaceModels!) + subspace.uuid: subspace + }; + + for (var newSubspace in newSpaceModel.subspaceModels!) { + if (newSubspace.uuid != null && + prevSubspaceMap.containsKey(newSubspace.uuid)) { + final prevSubspace = prevSubspaceMap[newSubspace.uuid]!; + + // Check if modelName has changed + if (newSubspace.subspaceName != prevSubspace.subspaceName) { + subspaceUpdates.add(UpdateSubspaceTemplateModel( + action: Action.update, + uuid: newSubspace.uuid, + subspaceName: newSubspace.subspaceName, + )); + } + + // Compare tags within the subspace + final List tagUpdatesInSubspace = []; + if (prevSubspace.tags != null && newSubspace.tags != null) { + final prevTagMap = { + for (var tag in prevSubspace.tags!) tag.uuid: tag + }; + + // Check for deleted tags + for (var prevTag in prevSubspace.tags!) { + if (!newSubspace.tags! + .any((newTag) => newTag.uuid == prevTag.uuid)) { + tagUpdatesInSubspace.add(TagModelUpdate( + action: Action.delete, + uuid: prevTag.uuid, + )); + } + } + + // Check for added tags, including those without a UUID + for (var newTag in newSubspace.tags!) { + if (newTag.uuid == null || newTag.uuid!.isEmpty) { + // Add new tag without UUID + tagUpdatesInSubspace.add(TagModelUpdate( + action: Action.add, + uuid: null, // or generate a new UUID if required + tag: newTag.tag, + productUuid: newTag.product?.uuid, + )); + } else if (!prevSubspace.tags! + .any((prevTag) => prevTag.uuid == newTag.uuid)) { + // Add new tag with UUID + tagUpdatesInSubspace.add(TagModelUpdate( + action: Action.add, + uuid: newTag.uuid, + tag: newTag.tag, + productUuid: newTag.product?.uuid, + )); + } + } + + // Check for updated tags + for (var prevTag in prevSubspace.tags!) { + final newTag = newSubspace.tags!.cast().firstWhere( + (tag) => tag?.uuid == prevTag.uuid, + orElse: () => null, + ); + if (newTag != null && newTag.tag != prevTag.tag) { + tagUpdatesInSubspace.add(TagModelUpdate( + action: Action.update, + uuid: newTag.uuid, + tag: newTag.tag, + )); + } + } + } + + // Add the subspace with updated tags if necessary + if (tagUpdatesInSubspace.isNotEmpty) { + subspaceUpdates.add(UpdateSubspaceTemplateModel( + action: Action.update, + uuid: newSubspace.uuid, + subspaceName: newSubspace.subspaceName, + tags: tagUpdatesInSubspace, + )); + } + } + } + } + + final spaceModelBody = CreateSpaceTemplateBodyModel( + modelName: spaceModelName, + tags: tagUpdates, + subspaceModels: subspaceUpdates); + + final res = await _api.updateSpaceModel( + spaceModelBody, prevSpaceModel.uuid ?? ''); + + if (res != null) { + emit(CreateSpaceModelLoaded(newSpaceModel)); + if (event.onUpdate != null) { + event.onUpdate!(event.updatedSpaceTemplate); + } + } + } catch (e) { + emit(CreateSpaceModelError('Error creating space model')); + } + }); + } + + List processTagUpdates( + List? prevTags, + List? newTags, + ) { + final List tagUpdates = []; + final processedTags = {}; + + 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)); + } + } + } + + // Case 2: Tags added + if (newTags != null) { + for (var newTag in newTags!) { + // Tag without UUID + if ((newTag.uuid == null || newTag.uuid!.isEmpty) && + !processedTags.contains(newTag.tag)) { + tagUpdates.add(TagModelUpdate( + action: Action.add, + tag: newTag.tag, + 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; } } diff --git a/lib/pages/spaces_management/space_model/bloc/create_space_model_event.dart b/lib/pages/spaces_management/space_model/bloc/create_space_model_event.dart index a78ae78f..22828941 100644 --- a/lib/pages/spaces_management/space_model/bloc/create_space_model_event.dart +++ b/lib/pages/spaces_management/space_model/bloc/create_space_model_event.dart @@ -22,7 +22,6 @@ class CreateSpaceTemplate extends CreateSpaceModelEvent { final SpaceTemplateModel spaceTemplate; final Function(SpaceTemplateModel)? onCreate; - const CreateSpaceTemplate({ required this.spaceTemplate, this.onCreate, @@ -39,7 +38,7 @@ class UpdateSpaceTemplateName extends CreateSpaceModelEvent { UpdateSpaceTemplateName({required this.name, required this.allModels}); @override - List get props => [name,allModels]; + List get props => [name, allModels]; } class AddSubspacesToSpaceTemplate extends CreateSpaceModelEvent { @@ -54,9 +53,19 @@ class AddTagsToSpaceTemplate extends CreateSpaceModelEvent { AddTagsToSpaceTemplate(this.tags); } - class ValidateSpaceTemplateName extends CreateSpaceModelEvent { final String name; ValidateSpaceTemplateName({required this.name}); } + +class ModifySpaceTemplate extends CreateSpaceModelEvent { + final SpaceTemplateModel spaceTemplate; + final SpaceTemplateModel updatedSpaceTemplate; + final Function(SpaceTemplateModel)? onUpdate; + + ModifySpaceTemplate( + {required this.spaceTemplate, + required this.updatedSpaceTemplate, + this.onUpdate}); +} diff --git a/lib/pages/spaces_management/space_model/bloc/space_model_bloc.dart b/lib/pages/spaces_management/space_model/bloc/space_model_bloc.dart index e383610d..090dfa13 100644 --- a/lib/pages/spaces_management/space_model/bloc/space_model_bloc.dart +++ b/lib/pages/spaces_management/space_model/bloc/space_model_bloc.dart @@ -12,6 +12,7 @@ class SpaceModelBloc extends Bloc { required List initialSpaceModels, }) : super(SpaceModelLoaded(spaceModels: initialSpaceModels)) { on(_onCreateSpaceModel); + on(_onUpdateSpaceModel); } Future _onCreateSpaceModel( @@ -33,4 +34,23 @@ class SpaceModelBloc extends Bloc { } } } + + Future _onUpdateSpaceModel( + UpdateSpaceModel event, Emitter emit) async { + final currentState = state; + if (currentState is SpaceModelLoaded) { + try { + final newSpaceModel = + await api.getSpaceModel(event.spaceModelUuid ?? ''); + if (newSpaceModel != null) { + final updatedSpaceModels = currentState.spaceModels.map((model) { + return model.uuid == event.spaceModelUuid ? newSpaceModel : model; + }).toList(); + emit(SpaceModelLoaded(spaceModels: updatedSpaceModels)); + } + } catch (e) { + emit(SpaceModelError(message: e.toString())); + } + } + } } diff --git a/lib/pages/spaces_management/space_model/bloc/space_model_event.dart b/lib/pages/spaces_management/space_model/bloc/space_model_event.dart index 78331f3c..8f71e611 100644 --- a/lib/pages/spaces_management/space_model/bloc/space_model_event.dart +++ b/lib/pages/spaces_management/space_model/bloc/space_model_event.dart @@ -16,3 +16,21 @@ class CreateSpaceModel extends SpaceModelEvent { @override List get props => [newSpaceModel]; } + +class GetSpaceModel extends SpaceModelEvent { + final String spaceModelUuid; + + GetSpaceModel({required this.spaceModelUuid}); + + @override + List get props => [spaceModelUuid]; +} + +class UpdateSpaceModel extends SpaceModelEvent { + final String spaceModelUuid; + + UpdateSpaceModel({required this.spaceModelUuid}); + + @override + List get props => [spaceModelUuid]; +} diff --git a/lib/pages/spaces_management/space_model/models/create_space_template_body_model.dart b/lib/pages/spaces_management/space_model/models/create_space_template_body_model.dart index e481a8b8..cb8d0aac 100644 --- a/lib/pages/spaces_management/space_model/models/create_space_template_body_model.dart +++ b/lib/pages/spaces_management/space_model/models/create_space_template_body_model.dart @@ -30,12 +30,12 @@ class CreateSubspaceTemplateModel { } class CreateSpaceTemplateBodyModel { - final String modelName; + final String? modelName; final List? tags; final List? subspaceModels; CreateSpaceTemplateBodyModel({ - required this.modelName, + this.modelName, this.tags, this.subspaceModels, }); diff --git a/lib/pages/spaces_management/space_model/models/space_template_model.dart b/lib/pages/spaces_management/space_model/models/space_template_model.dart index 84f568a5..5edf912f 100644 --- a/lib/pages/spaces_management/space_model/models/space_template_model.dart +++ b/lib/pages/spaces_management/space_model/models/space_template_model.dart @@ -2,6 +2,7 @@ import 'package:equatable/equatable.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_model.dart'; +import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_update_model.dart'; import 'package:syncrow_web/utils/constants/action_enum.dart'; import 'package:uuid/uuid.dart'; @@ -70,14 +71,14 @@ class SpaceTemplateModel extends Equatable { } class UpdateSubspaceTemplateModel { - final String uuid; + final String? uuid; final Action action; final String? subspaceName; - final List? tags; + final List? tags; UpdateSubspaceTemplateModel({ required this.action, - required this.uuid, + this.uuid, this.subspaceName, this.tags, }); @@ -88,7 +89,7 @@ class UpdateSubspaceTemplateModel { uuid: json['uuid'] ?? '', subspaceName: json['subspaceName'] ?? '', tags: (json['tags'] as List) - .map((item) => UpdateTagModel.fromJson(item)) + .map((item) => TagModelUpdate.fromJson(item)) .toList(), ); } @@ -103,44 +104,6 @@ class UpdateSubspaceTemplateModel { } } -class UpdateTagModel { - final Action action; - final String? uuid; - final String tag; - final bool disabled; - final ProductModel? product; - - UpdateTagModel({ - required this.action, - this.uuid, - required this.tag, - required this.disabled, - this.product, - }); - - factory UpdateTagModel.fromJson(Map json) { - return UpdateTagModel( - action: ActionExtension.fromValue(json['action']), - uuid: json['uuid'] ?? '', - tag: json['tag'] ?? '', - disabled: json['disabled'] ?? false, - product: json['product'] != null - ? ProductModel.fromMap(json['product']) - : null, - ); - } - - Map toJson() { - return { - 'action': action.value, - 'uuid': uuid, - 'tag': tag, - 'disabled': disabled, - 'product': product?.toMap(), - }; - } -} - extension SpaceTemplateExtensions on SpaceTemplateModel { List listAllTagValues() { final List tagValues = []; diff --git a/lib/pages/spaces_management/space_model/models/tag_update_model.dart b/lib/pages/spaces_management/space_model/models/tag_update_model.dart new file mode 100644 index 00000000..c7190dc8 --- /dev/null +++ b/lib/pages/spaces_management/space_model/models/tag_update_model.dart @@ -0,0 +1,34 @@ +import 'package:syncrow_web/utils/constants/action_enum.dart'; + +class TagModelUpdate { + final Action action; + final String? uuid; + final String? tag; + final String? productUuid; + + TagModelUpdate({ + required this.action, + this.uuid, + this.tag, + this.productUuid, + }); + + factory TagModelUpdate.fromJson(Map json) { + return TagModelUpdate( + action: json['action'], + uuid: json['uuid'], + tag: json['tag'], + productUuid: json['productUuid'], + ); + } + + // Method to convert an instance to JSON + Map toJson() { + return { + 'action': action.value, + 'uuid': uuid, // Nullable field + 'tag': tag, + 'productUuid': productUuid, + }; + } +} diff --git a/lib/pages/spaces_management/space_model/view/space_model_page.dart b/lib/pages/spaces_management/space_model/view/space_model_page.dart index 33509998..ae623e81 100644 --- a/lib/pages/spaces_management/space_model/view/space_model_page.dart +++ b/lib/pages/spaces_management/space_model/view/space_model_page.dart @@ -65,7 +65,6 @@ class SpaceModelPage extends StatelessWidget { final model = spaceModels[index]; final otherModel = List.from(allSpaceModelNames); otherModel.remove(model.modelName); - return GestureDetector( onTap: () { showDialog( @@ -76,6 +75,7 @@ class SpaceModelPage extends StatelessWidget { allTags: allTagValues, spaceModel: model, otherSpaceModels: otherModel, + pageContext: context, ); }, ); diff --git a/lib/pages/spaces_management/space_model/widgets/dialog/create_space_model_dialog.dart b/lib/pages/spaces_management/space_model/widgets/dialog/create_space_model_dialog.dart index 4c4b8a7c..c1bea0fd 100644 --- a/lib/pages/spaces_management/space_model/widgets/dialog/create_space_model_dialog.dart +++ b/lib/pages/spaces_management/space_model/widgets/dialog/create_space_model_dialog.dart @@ -6,6 +6,7 @@ import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_mod import 'package:syncrow_web/pages/spaces_management/space_model/bloc/create_space_model_bloc.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/bloc/create_space_model_event.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/bloc/create_space_model_state.dart'; +import 'package:syncrow_web/pages/spaces_management/space_model/bloc/space_model_state.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/widgets/tag_chips_display_widget.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/bloc/space_model_bloc.dart'; @@ -58,7 +59,9 @@ class CreateSpaceModelDialog extends StatelessWidget { } spaceNameController.addListener(() { - bloc.add(UpdateSpaceTemplateName(name: spaceNameController.text,allModels: otherSpaceModels ??[])); + bloc.add(UpdateSpaceTemplateName( + name: spaceNameController.text, + allModels: otherSpaceModels ?? [])); }); return bloc; @@ -153,15 +156,12 @@ class CreateSpaceModelDialog extends StatelessWidget { onPressed: state.errorMessage == null || isNameValid ? () { + final updatedSpaceTemplate = + updatedSpaceModel.copyWith( + modelName: + spaceNameController.text.trim(), + ); if (updatedSpaceModel.uuid == null) { - final updatedSpaceTemplate = - updatedSpaceModel.copyWith( - modelName: - spaceNameController.text.trim(), - ); - if (updatedSpaceTemplate.uuid != - null) {} - context .read() .add( @@ -181,6 +181,52 @@ class CreateSpaceModelDialog extends StatelessWidget { }, ), ); + } else { + if (pageContext != null) { + final currentState = pageContext! + .read() + .state; + if (currentState + is SpaceModelLoaded) { + final spaceModels = + List.from( + currentState.spaceModels); + + final SpaceTemplateModel? + currentSpaceModel = spaceModels + .cast() + .firstWhere( + (sm) => + sm?.uuid == + updatedSpaceModel + .uuid, + orElse: () => null, + ); + if (currentSpaceModel != null) { + context + .read() + .add(ModifySpaceTemplate( + spaceTemplate: + currentSpaceModel, + updatedSpaceTemplate: + updatedSpaceTemplate, + onUpdate: (newModel) { + if (pageContext != + null) { + pageContext! + .read< + SpaceModelBloc>() + .add(UpdateSpaceModel( + spaceModelUuid: + newModel.uuid ?? + '')); + } + Navigator.of(context) + .pop(); + })); + } + } + } } } : null, diff --git a/lib/pages/spaces_management/space_model/widgets/subspace_chip_widget.dart b/lib/pages/spaces_management/space_model/widgets/subspace_chip_widget.dart index 8f987c51..70ac6e24 100644 --- a/lib/pages/spaces_management/space_model/widgets/subspace_chip_widget.dart +++ b/lib/pages/spaces_management/space_model/widgets/subspace_chip_widget.dart @@ -1,9 +1,6 @@ import 'package:flutter/material.dart'; import 'package:syncrow_web/utils/color_manager.dart'; -import 'package:flutter/material.dart'; -import 'package:syncrow_web/utils/color_manager.dart'; - class SubspaceChipWidget extends StatelessWidget { final String subspace; diff --git a/lib/pages/spaces_management/space_model/widgets/subspace_model_create_widget.dart b/lib/pages/spaces_management/space_model/widgets/subspace_model_create_widget.dart index 7781bb5e..0dda53a6 100644 --- a/lib/pages/spaces_management/space_model/widgets/subspace_model_create_widget.dart +++ b/lib/pages/spaces_management/space_model/widgets/subspace_model_create_widget.dart @@ -46,23 +46,23 @@ class SubspaceModelCreate extends StatelessWidget { spacing: 8.0, runSpacing: 8.0, children: [ - ...subspaces.map( - (subspace) => Chip( - label: Text( - subspace.subspaceName, - style: const TextStyle( - color: ColorsManager.spaceColor), // Text color - ), - backgroundColor: - ColorsManager.whiteColors, // Chip background color - shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.circular(16), // Rounded chip - side: const BorderSide( - color: ColorsManager.spaceColor), // Border color - ), - ), - ), + ...subspaces.map((subspace) => Container( + padding: const EdgeInsets.symmetric( + horizontal: 8.0, vertical: 4.0), + decoration: BoxDecoration( + color: ColorsManager.whiteColors, + borderRadius: BorderRadius.circular(10), + border: Border.all( + color: ColorsManager.transparentColor), + ), + child: Text( + subspace.subspaceName, + style: Theme.of(context) + .textTheme + .bodySmall + ?.copyWith(color: ColorsManager.spaceColor), + ), + )), GestureDetector( onTap: () async { await _openDialog(context, 'Edit Sub-space'); diff --git a/lib/pages/spaces_management/space_model/widgets/tag_chips_display_widget.dart b/lib/pages/spaces_management/space_model/widgets/tag_chips_display_widget.dart index 0c46076f..d4111031 100644 --- a/lib/pages/spaces_management/space_model/widgets/tag_chips_display_widget.dart +++ b/lib/pages/spaces_management/space_model/widgets/tag_chips_display_widget.dart @@ -98,6 +98,7 @@ class TagChipDisplay extends StatelessWidget { subspaces: subspaces, pageContext: pageContext, allTags: allTags, + spaceModel: spaceModel, initialTags: TagHelper.generateInitialTags( subspaces: subspaces, spaceTagModels: spaceModel?.tags ?? []), @@ -139,6 +140,7 @@ class TagChipDisplay extends StatelessWidget { spaceName: spaceNameController.text, pageContext: pageContext, isCreate: true, + spaceModel: spaceModel, ), ); }, diff --git a/lib/pages/spaces_management/tag_model/views/add_device_type_model_widget.dart b/lib/pages/spaces_management/tag_model/views/add_device_type_model_widget.dart index ddb9b5a3..a9d40147 100644 --- a/lib/pages/spaces_management/tag_model/views/add_device_type_model_widget.dart +++ b/lib/pages/spaces_management/tag_model/views/add_device_type_model_widget.dart @@ -5,9 +5,10 @@ import 'package:syncrow_web/pages/common/buttons/default_button.dart'; import 'package:syncrow_web/pages/spaces_management/assign_tag_models/views/assign_tag_models_dialog.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/selected_product_model.dart'; -import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_bloc.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/subspace_template_model.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_model.dart'; +import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/create_space_model_dialog.dart'; import 'package:syncrow_web/pages/spaces_management/tag_model/bloc/add_device_model_bloc.dart'; import 'package:syncrow_web/pages/spaces_management/tag_model/bloc/add_device_model_state.dart'; import 'package:syncrow_web/pages/spaces_management/tag_model/bloc/add_device_type_model_event.dart'; @@ -24,6 +25,7 @@ class AddDeviceTypeModelWidget extends StatelessWidget { final bool isCreate; final List? otherSpaceModels; final BuildContext? pageContext; + final SpaceTemplateModel? spaceModel; const AddDeviceTypeModelWidget( {super.key, @@ -35,7 +37,8 @@ class AddDeviceTypeModelWidget extends StatelessWidget { required this.spaceName, required this.isCreate, this.pageContext, - this.otherSpaceModels}); + this.otherSpaceModels, + this.spaceModel}); @override Widget build(BuildContext context) { @@ -75,6 +78,7 @@ class AddDeviceTypeModelWidget extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 20.0), child: ScrollableGridViewWidget( + isCreate: isCreate, products: products, crossAxisCount: crossAxisCount, initialProductCounts: state.selectedProducts, @@ -98,6 +102,44 @@ class AddDeviceTypeModelWidget extends StatelessWidget { onPressed: () async { if (isCreate) { Navigator.of(context).pop(); + await showDialog( + context: context, + builder: (BuildContext dialogContext) { + return CreateSpaceModelDialog( + products: products, + allTags: allTags, + pageContext: pageContext, + otherSpaceModels: otherSpaceModels, + spaceModel: SpaceTemplateModel( + modelName: spaceName, + tags: spaceModel?.tags ?? [], + uuid: spaceModel?.uuid, + internalId: spaceModel?.internalId, + subspaceModels: subspaces), + ); + }, + ); + } else { + final initialTags = generateInitialTags( + spaceTagModels: spaceTagModels, + subspaces: subspaces, + ); + + Navigator.of(context).pop(); + await showDialog( + context: context, + builder: (context) => AssignTagModelsDialog( + products: products, + subspaces: subspaces, + addedProducts: initialSelectedProducts ?? [], + allTags: allTags, + spaceName: spaceName, + initialTags: initialTags, + otherSpaceModels: otherSpaceModels, + title: 'Edit Device', + spaceModel: spaceModel, + pageContext: pageContext, + )); } }, ), @@ -140,6 +182,7 @@ class AddDeviceTypeModelWidget extends StatelessWidget { initialTags: state.initialTag, otherSpaceModels: otherSpaceModels, title: dialogTitle, + spaceModel: spaceModel, pageContext: pageContext, ), ); diff --git a/lib/pages/spaces_management/tag_model/widgets/device_type_tile_widget.dart b/lib/pages/spaces_management/tag_model/widgets/device_type_tile_widget.dart index c2d38d0b..7d103cdb 100644 --- a/lib/pages/spaces_management/tag_model/widgets/device_type_tile_widget.dart +++ b/lib/pages/spaces_management/tag_model/widgets/device_type_tile_widget.dart @@ -13,12 +13,13 @@ import 'package:syncrow_web/utils/constants/assets.dart'; class DeviceTypeTileWidget extends StatelessWidget { final ProductModel product; final List productCounts; + final bool isCreate; - const DeviceTypeTileWidget({ - super.key, - required this.product, - required this.productCounts, - }); + const DeviceTypeTileWidget( + {super.key, + required this.product, + required this.productCounts, + required this.isCreate}); @override Widget build(BuildContext context) { @@ -48,6 +49,7 @@ class DeviceTypeTileWidget extends StatelessWidget { DeviceNameWidget(name: product.name), const SizedBox(height: 4), CounterWidget( + isCreate: isCreate, initialCount: selectedProduct.count, onCountChanged: (newCount) { context.read().add( diff --git a/lib/pages/spaces_management/tag_model/widgets/scrollable_grid_view_widget.dart b/lib/pages/spaces_management/tag_model/widgets/scrollable_grid_view_widget.dart index 3e32ccd8..d1775c66 100644 --- a/lib/pages/spaces_management/tag_model/widgets/scrollable_grid_view_widget.dart +++ b/lib/pages/spaces_management/tag_model/widgets/scrollable_grid_view_widget.dart @@ -10,12 +10,14 @@ class ScrollableGridViewWidget extends StatelessWidget { final List? products; final int crossAxisCount; final List? initialProductCounts; + final bool isCreate; const ScrollableGridViewWidget({ super.key, required this.products, required this.crossAxisCount, this.initialProductCounts, + required this.isCreate }); @override @@ -30,7 +32,7 @@ class ScrollableGridViewWidget extends StatelessWidget { final productCounts = state is AddDeviceModelLoaded ? state.selectedProducts : []; - + return GridView.builder( controller: scrollController, shrinkWrap: true, @@ -47,6 +49,7 @@ class ScrollableGridViewWidget extends StatelessWidget { return DeviceTypeTileWidget( product: product, + isCreate: isCreate, productCounts: initialProductCount != null ? [...productCounts, initialProductCount] : productCounts, diff --git a/lib/services/space_model_mang_api.dart b/lib/services/space_model_mang_api.dart index ee241189..eb896432 100644 --- a/lib/services/space_model_mang_api.dart +++ b/lib/services/space_model_mang_api.dart @@ -34,6 +34,20 @@ class SpaceModelManagementApi { return response; } + + Future updateSpaceModel( + CreateSpaceTemplateBodyModel spaceModel, String spaceModelUuid) async { + final response = await HTTPService().put( + path: ApiEndpoints.updateSpaceModel + .replaceAll('{projectId}', TempConst.projectId).replaceAll('{spaceModelUuid}', spaceModelUuid), + body: spaceModel.toJson(), + expectedResponseModel: (json) { + return json['message']; + }, + ); + return response; + } + Future getSpaceModel(String spaceModelUuid) async { final response = await HTTPService().get( path: ApiEndpoints.getSpaceModel diff --git a/lib/utils/constants/api_const.dart b/lib/utils/constants/api_const.dart index 92a2581c..35020151 100644 --- a/lib/utils/constants/api_const.dart +++ b/lib/utils/constants/api_const.dart @@ -101,8 +101,11 @@ abstract class ApiEndpoints { //space model static const String listSpaceModels = '/projects/{projectId}/space-models'; static const String createSpaceModel = '/projects/{projectId}/space-models'; - static const String getSpaceModel = '/projects/{projectId}/space-models/{spaceModelUuid}'; - + static const String getSpaceModel = + '/projects/{projectId}/space-models/{spaceModelUuid}'; + static const String updateSpaceModel = + '/projects/{projectId}/space-models/{spaceModelUuid}'; + static const String roleTypes = '/role/types'; static const String permission = '/permission/{roleUuid}'; static const String inviteUser = '/invite-user';