diff --git a/lib/pages/device_managment/sos/view/sos_batch_control_view.dart b/lib/pages/device_managment/sos/view/sos_batch_control_view.dart index bc66d69f..9082c8bd 100644 --- a/lib/pages/device_managment/sos/view/sos_batch_control_view.dart +++ b/lib/pages/device_managment/sos/view/sos_batch_control_view.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart'; import 'package:syncrow_web/pages/device_managment/shared/batch_control/factory_reset.dart'; -import 'package:syncrow_web/pages/device_managment/shared/batch_control/firmware_update.dart'; import 'package:syncrow_web/pages/device_managment/sos/bloc/sos_device_bloc.dart'; class SOSBatchControlView extends StatelessWidget { diff --git a/lib/pages/spaces_management/assign_tag_models/bloc/assign_tag_model_bloc.dart b/lib/pages/spaces_management/assign_tag_models/bloc/assign_tag_model_bloc.dart index 42184278..3dd5e27d 100644 --- a/lib/pages/spaces_management/assign_tag_models/bloc/assign_tag_model_bloc.dart +++ b/lib/pages/spaces_management/assign_tag_models/bloc/assign_tag_model_bloc.dart @@ -7,21 +7,49 @@ class AssignTagModelBloc extends Bloc { AssignTagModelBloc() : super(AssignTagModelInitial()) { on((event, emit) { - final tags = event.initialTags?.isNotEmpty == true - ? event.initialTags! - : event.addedProducts - .expand((selectedProduct) => List.generate( - selectedProduct.count, - (index) => TagModel( - tag: '', - product: selectedProduct.product, - location: 'None', - ), - )) - .toList(); + final initialTags = event.initialTags ?? []; - emit( - AssignTagModelLoaded(tags: tags, isSaveEnabled: _validateTags(tags))); + final existingTagCounts = {}; + for (var tag in initialTags) { + if (tag.product != null) { + existingTagCounts[tag.product!.uuid] = + (existingTagCounts[tag.product!.uuid] ?? 0) + 1; + } + } + + final allTags = []; + + for (var selectedProduct in event.addedProducts) { + final existingCount = existingTagCounts[selectedProduct.productId] ?? 0; + + if (selectedProduct.count == 0 || + selectedProduct.count <= existingCount) { + allTags.addAll(initialTags + .where((tag) => tag.product?.uuid == selectedProduct.productId)); + continue; + } + + final missingCount = selectedProduct.count - existingCount; + + allTags.addAll(initialTags + .where((tag) => tag.product?.uuid == selectedProduct.productId)); + + if (missingCount > 0) { + allTags.addAll(List.generate( + missingCount, + (index) => TagModel( + tag: '', + product: selectedProduct.product, + location: 'None', + ), + )); + } + } + + emit(AssignTagModelLoaded( + tags: allTags, + isSaveEnabled: _validateTags(allTags), + )); }); on((event, emit) { 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 1ce8f651..d93f68c5 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,13 +1,51 @@ 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/services/space_model_mang_api.dart'; class CreateSpaceModelBloc extends Bloc { SpaceTemplateModel? _space; - CreateSpaceModelBloc() : super(CreateSpaceModelInitial()) { + final SpaceModelManagementApi _api; + + CreateSpaceModelBloc(this._api) : super(CreateSpaceModelInitial()) { + on((event, emit) async { + try { + final spaceTemplate = event.spaceTemplate; + + + final tagBodyModels = + spaceTemplate.tags?.map((tag) => tag.toTagBodyModel()).toList() ?? + []; + + final subspaceTemplateBodyModels = + spaceTemplate.subspaceModels?.map((subspaceModel) { + final tagsubspaceBodyModels = subspaceModel.tags + ?.map((tag) => tag.toTagBodyModel()) + .toList() ?? + []; + return CreateSubspaceTemplateModel() + ..subspaceName = subspaceModel.subspaceName + ..tags = tagsubspaceBodyModels; + }).toList() ?? + []; + + final spaceModelBody = CreateSpaceTemplateBodyModel( + modelName: spaceTemplate.modelName, + tags: tagBodyModels, + subspaceModels: subspaceTemplateBodyModels); + + print(spaceModelBody); + final success = await _api.createSpaceModel(spaceModelBody); + } catch (e) { + print(e); + } + }); + on((event, emit) { emit(CreateSpaceModelLoading()); Future.delayed(const Duration(seconds: 1), () { @@ -25,24 +63,27 @@ class CreateSpaceModelBloc }); on((event, emit) { - if (_space != null) { - _space = _space!.copyWith(modelName: event.name); // Use copyWith for immutability - emit(CreateSpaceModelLoaded(_space!)); + final currentState = state; + + if (currentState is CreateSpaceModelLoaded) { + final updatedSpaceModel = + currentState.space.copyWith(modelName: event.name); + emit(CreateSpaceModelLoaded(updatedSpaceModel)); } else { emit(CreateSpaceModelError("Space template not initialized")); } }); - on((event, emit) { - if (_space != null) { - final updatedSpace = _space!.copyWith( + final currentState = state; + + if (currentState is CreateSpaceModelLoaded) { + final updatedSpace = currentState.space.copyWith( subspaceModels: [ ...(_space!.subspaceModels ?? []), ...event.subspaces, ], ); - _space = updatedSpace; emit(CreateSpaceModelLoaded(updatedSpace)); } else { emit(CreateSpaceModelError("Space template not initialized")); 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 ccf0e3fb..7944a8a8 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 @@ -1,7 +1,13 @@ +import 'package:equatable/equatable.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'; -abstract class CreateSpaceModelEvent {} +abstract class CreateSpaceModelEvent extends Equatable { + const CreateSpaceModelEvent(); + + @override + List get props => []; +} class LoadSpaceTemplate extends CreateSpaceModelEvent {} @@ -11,6 +17,17 @@ class UpdateSpaceTemplate extends CreateSpaceModelEvent { UpdateSpaceTemplate(this.spaceTemplate); } +class CreateSpaceTemplate extends CreateSpaceModelEvent { + final SpaceTemplateModel spaceTemplate; + + const CreateSpaceTemplate({ + required this.spaceTemplate, + }); + + @override + List get props => [spaceTemplate]; +} + class UpdateSpaceTemplateName extends CreateSpaceModelEvent { final String name; diff --git a/lib/pages/spaces_management/space_model/bloc/create_space_model_state.dart b/lib/pages/spaces_management/space_model/bloc/create_space_model_state.dart index 1a9f52bb..c05e8744 100644 --- a/lib/pages/spaces_management/space_model/bloc/create_space_model_state.dart +++ b/lib/pages/spaces_management/space_model/bloc/create_space_model_state.dart @@ -1,6 +1,12 @@ +import 'package:equatable/equatable.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart'; -abstract class CreateSpaceModelState {} +abstract class CreateSpaceModelState extends Equatable { + const CreateSpaceModelState(); + + @override + List get props => []; +} class CreateSpaceModelInitial extends CreateSpaceModelState {} 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 new file mode 100644 index 00000000..896fe000 --- /dev/null +++ b/lib/pages/spaces_management/space_model/models/create_space_template_body_model.dart @@ -0,0 +1,47 @@ +import 'dart:convert'; + +class TagBodyModel { + late String uuid; + late String tag; + late final String? productUuid; + + Map toJson() { + return { + 'uuid': uuid, + 'tag': tag, + 'productUuid': productUuid, + }; + } + + @override + String toString() { + return toJson().toString(); + } +} + +class CreateSubspaceTemplateModel { + late String subspaceName; + late List? tags; +} + +class CreateSpaceTemplateBodyModel { + final String modelName; + final List? tags; + final List? subspaceModels; + + CreateSpaceTemplateBodyModel({ + required this.modelName, + this.tags, + this.subspaceModels, + }); + + Map toJson() { + return { + 'modelName': modelName, + 'tags': tags, + 'subspaceModels': 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 ec2f466f..f62bbcf6 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 @@ -1,16 +1,20 @@ +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/utils/constants/action_enum.dart'; import 'package:uuid/uuid.dart'; -class SpaceTemplateModel { +class SpaceTemplateModel extends Equatable { final String? uuid; String modelName; List? subspaceModels; final List? tags; String internalId; + @override + List get props => [modelName, subspaceModels]; + SpaceTemplateModel({ this.uuid, String? internalId, @@ -26,9 +30,10 @@ class SpaceTemplateModel { uuid: json['uuid'] ?? '', internalId: internalId, modelName: json['modelName'] ?? '', - subspaceModels: (json['subspaceModels'] as List) - .map((item) => SubspaceTemplateModel.fromJson(item)) - .toList(), + subspaceModels: (json['subspaceModels'] as List?) + ?.map((e) => SubspaceTemplateModel.fromJson(e)) + .toList() ?? + [], tags: (json['tags'] as List) .map((item) => TagModel.fromJson(item)) .toList(), diff --git a/lib/pages/spaces_management/space_model/models/tag_model.dart b/lib/pages/spaces_management/space_model/models/tag_model.dart index 1bd2dd02..99008e76 100644 --- a/lib/pages/spaces_management/space_model/models/tag_model.dart +++ b/lib/pages/spaces_management/space_model/models/tag_model.dart @@ -1,5 +1,5 @@ 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/create_space_template_body_model.dart'; import 'package:uuid/uuid.dart'; class TagModel { @@ -50,3 +50,12 @@ class TagModel { }; } } + +extension TagModelExtensions on TagModel { + TagBodyModel toTagBodyModel() { + return TagBodyModel() + ..uuid = uuid ?? '' + ..tag = tag ?? '' + ..productUuid = product?.uuid; + } +} \ No newline at end of file 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 553f3be2..6fecd125 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 @@ -19,73 +19,83 @@ class SpaceModelPage extends StatelessWidget { backgroundColor: ColorsManager.whiteColors, body: Padding( padding: const EdgeInsets.fromLTRB(20.0, 16.0, 16.0, 16.0), - child: GridView.builder( - //clipBehavior: Clip.none, - shrinkWrap: false, - physics: const AlwaysScrollableScrollPhysics(), - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 3, - crossAxisSpacing: 13.0, - mainAxisSpacing: 13.0, - childAspectRatio: calculateChildAspectRatio(context), - ), - itemCount: spaceModels.length + 1, - itemBuilder: (context, index) { - if (index == spaceModels.length) { - return GestureDetector( - onTap: () { - showDialog( - context: context, - builder: (BuildContext context) { - return CreateSpaceModelDialog(products: products,allTags: allTagValues,); - }, - ); - }, - child: Container( - decoration: BoxDecoration( - color: ColorsManager.whiteColors, - borderRadius: BorderRadius.circular(20), - boxShadow: const [ - BoxShadow( - color: ColorsManager.semiTransparentBlackColor, - blurRadius: 15, - offset: Offset(0, 4), - spreadRadius: 0, - ), - BoxShadow( - color: ColorsManager.semiTransparentBlackColor, - blurRadius: 25, - offset: Offset(0, 15), - spreadRadius: -5, - ), - ], - ), - child: Center( - child: Container( - width: 60, - height: 60, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: ColorsManager.neutralGray, - border: Border.all( - color: ColorsManager.textFieldGreyColor, - width: 2.0, - ), - ), - child: const Icon( - Icons.add, - size: 40, - color: ColorsManager.spaceColor, // Icon color - ), - ), - ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Expanded( + child: GridView.builder( + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3, + crossAxisSpacing: 10.0, + mainAxisSpacing: 10.0, + childAspectRatio: calculateChildAspectRatio(context), ), - ); - } + itemCount: spaceModels.length + 1, + itemBuilder: (context, index) { + if (index == spaceModels.length) { + return GestureDetector( + onTap: () { + showDialog( + context: context, + builder: (BuildContext context) { + return CreateSpaceModelDialog( + products: products, + allTags: allTagValues, + ); + }, + ); + }, + child: _buildAddContainer(), + ); + } + final model = spaceModels[index]; + return SpaceModelCardWidget(model: model); + }, + ), + ), + ], + ), + ), + ); + } - final model = spaceModels[index]; - return SpaceModelCardWidget(model: model); - }, + Widget _buildAddContainer() { + return Container( + decoration: BoxDecoration( + color: ColorsManager.whiteColors, + borderRadius: BorderRadius.circular(20), + boxShadow: const [ + BoxShadow( + color: ColorsManager.semiTransparentBlackColor, + blurRadius: 15, + offset: Offset(0, 4), + spreadRadius: 0, + ), + BoxShadow( + color: ColorsManager.semiTransparentBlackColor, + blurRadius: 25, + offset: Offset(0, 15), + spreadRadius: -5, + ), + ], + ), + child: Center( + child: Container( + width: 60, + height: 60, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: ColorsManager.neutralGray, + border: Border.all( + color: ColorsManager.textFieldGreyColor, + width: 2.0, + ), + ), + child: const Icon( + Icons.add, + size: 40, + color: ColorsManager.spaceColor, + ), ), ), ); @@ -93,17 +103,15 @@ class SpaceModelPage extends StatelessWidget { double calculateChildAspectRatio(BuildContext context) { double screenWidth = MediaQuery.of(context).size.width; - - // Adjust the aspect ratio based on the screen width if (screenWidth > 1600) { - return 4.0; // For large screens + return 3; } if (screenWidth > 1200) { - return 3.2; // For large screens + return 5; } else if (screenWidth > 800) { - return 3.0; // For medium screens + return 5; } else { - return 2.0; // For small screens + return 6.0; } } 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 93e5a3dc..bd988782 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 @@ -7,10 +7,10 @@ import 'package:syncrow_web/pages/spaces_management/space_model/bloc/create_spac 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/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/widgets/tag_chips_display_widget.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/widgets/subspace_model_create_widget.dart'; +import 'package:syncrow_web/services/space_model_mang_api.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import '../../models/subspace_template_model.dart'; @@ -26,31 +26,45 @@ class CreateSpaceModelDialog extends StatelessWidget { @override Widget build(BuildContext context) { + final SpaceModelManagementApi _spaceModelApi = SpaceModelManagementApi(); + final screenWidth = MediaQuery.of(context).size.width; List? subspaces = spaceModel?.subspaceModels ?? []; final TextEditingController spaceNameController = TextEditingController( text: spaceModel?.modelName ?? '', ); + return AlertDialog( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), backgroundColor: ColorsManager.whiteColors, content: SizedBox( - width: screenWidth * 0.3, - child: BlocProvider( - create: (_) { - final bloc = CreateSpaceModelBloc(); - if (spaceModel != null) { - bloc.add(UpdateSpaceTemplate(spaceModel!)); - } else { - bloc.add(UpdateSpaceTemplate(SpaceTemplateModel( - modelName: '', - subspaceModels: [], - ))); - } - return bloc; - }, - child: BlocBuilder( - builder: (context, state) { + width: screenWidth * 0.3, + child: BlocProvider( + create: (_) { + final bloc = CreateSpaceModelBloc(_spaceModelApi); + if (spaceModel != null) { + bloc.add(UpdateSpaceTemplate(spaceModel!)); + } else { + bloc.add(UpdateSpaceTemplate(SpaceTemplateModel( + modelName: '', + subspaceModels: [], + ))); + } + + spaceNameController.addListener(() { + bloc.add(UpdateSpaceTemplateName(name: spaceNameController.text)); + }); + + return bloc; + }, + child: BlocBuilder( + builder: (context, state) { + if (state is CreateSpaceModelLoading) { + return const Center(child: CircularProgressIndicator()); + } else if (state is CreateSpaceModelLoaded) { + final updatedSpaceModel = state.space; + final subspaces = updatedSpaceModel.subspaceModels ?? []; + return Column( mainAxisSize: MainAxisSize.min, children: [ @@ -66,6 +80,11 @@ class CreateSpaceModelDialog extends StatelessWidget { width: screenWidth * 0.25, child: TextField( controller: spaceNameController, + onChanged: (value) { + context + .read() + .add(UpdateSpaceTemplateName(name: value)); + }, style: const TextStyle(color: ColorsManager.blackColor), decoration: InputDecoration( filled: true, @@ -85,11 +104,12 @@ class CreateSpaceModelDialog extends StatelessWidget { ), ), const SizedBox(height: 16), - SubspaceModelCreate(context, subspaces: subspaces), + SubspaceModelCreate(context, + subspaces: state.space.subspaceModels ?? []), const SizedBox(height: 10), TagChipDisplay(context, screenWidth: screenWidth, - spaceModel: spaceModel, + spaceModel: updatedSpaceModel, products: products, subspaces: subspaces, allTags: allTags, @@ -109,8 +129,14 @@ class CreateSpaceModelDialog extends StatelessWidget { Expanded( child: DefaultButton( onPressed: () { - // Return data when OK is pressed - Navigator.of(context).pop(subspaces); + final updatedSpaceTemplate = + updatedSpaceModel.copyWith( + modelName: spaceNameController.text.trim(), + ); + context.read().add( + CreateSpaceTemplate( + spaceTemplate: updatedSpaceTemplate), + ); }, backgroundColor: ColorsManager.secondaryColor, borderRadius: 10, @@ -123,9 +149,19 @@ class CreateSpaceModelDialog extends StatelessWidget { ), ], ); - }, - ), - )), + } else if (state is CreateSpaceModelError) { + return Text( + 'Error: ${state.message}', + style: const TextStyle(color: Colors.red), + ); + } + + // Default case (e.g., CreateSpaceModelInitial) + return const Center(child: Text('Initializing...')); + }, + ), + ), + ), ); } } 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 30b84a4b..35b680a0 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 @@ -10,7 +10,8 @@ import 'package:syncrow_web/pages/spaces_management/space_model/bloc/create_spac class SubspaceModelCreate extends StatelessWidget { final List subspaces; - const SubspaceModelCreate(BuildContext context, { + const SubspaceModelCreate( + BuildContext context, { Key? key, required this.subspaces, }) : super(key: key); @@ -26,6 +27,8 @@ class SubspaceModelCreate extends StatelessWidget { overlayColor: ColorsManager.transparentColor, ), onPressed: () async { + Navigator.of(context).pop(); + final result = await showDialog>( barrierDismissible: false, context: context, @@ -58,16 +61,16 @@ class SubspaceModelCreate extends StatelessWidget { child: Container( padding: const EdgeInsets.all(8.0), decoration: BoxDecoration( - color: ColorsManager.textFieldGreyColor, - borderRadius: BorderRadius.circular(15), + color: ColorsManager.textFieldGreyColor, + borderRadius: BorderRadius.circular(15), border: Border.all( - color: ColorsManager.textFieldGreyColor, + color: ColorsManager.textFieldGreyColor, width: 3.0, // Border width ), ), child: Wrap( - spacing: 8.0, - runSpacing: 8.0, + spacing: 8.0, + runSpacing: 8.0, children: [ ...subspaces.map( (subspace) => Chip( 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 00b2d493..f60e1cf3 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 @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.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/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'; @@ -29,7 +30,8 @@ class TagChipDisplay extends StatelessWidget { @override Widget build(BuildContext context) { - return (spaceModel?.subspaceModels?.isNotEmpty == true || spaceModel?.tags?.isNotEmpty == true || + return (spaceModel?.subspaceModels?.isNotEmpty == true || + spaceModel?.tags?.isNotEmpty == true || spaceModel?.subspaceModels ?.any((subspace) => subspace.tags?.isNotEmpty == true) == true) @@ -60,8 +62,7 @@ class TagChipDisplay extends StatelessWidget { width: 24, height: 24, child: SvgPicture.asset( - entry.key.icon ?? - 'assets/default_icon.svg', // Provide a default asset path if null + entry.key.icon ?? 'assets/icons/gateway.svg', fit: BoxFit.contain, ), ), @@ -71,19 +72,19 @@ class TagChipDisplay extends StatelessWidget { color: ColorsManager.spaceColor, ), ), - backgroundColor: - Colors.white, // Chip background color + backgroundColor: Colors.white, shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.circular(16), // Rounded chip + borderRadius: BorderRadius.circular(16), side: const BorderSide( - color: ColorsManager.spaceColor, // Border color + color: ColorsManager.spaceColor, ), ), ), ), GestureDetector( onTap: () async { + Navigator.of(context).pop(); + await showDialog( barrierDismissible: false, context: context, @@ -92,6 +93,10 @@ class TagChipDisplay extends StatelessWidget { subspaces: subspaces, allTags: allTags, spaceName: spaceNameController.text, + spaceTagModels: spaceModel?.tags, + initialSelectedProducts: + _createInitialSelectedProducts( + spaceModel?.tags, spaceModel?.subspaceModels), ), ); // Edit action @@ -117,6 +122,8 @@ class TagChipDisplay extends StatelessWidget { ) : TextButton( onPressed: () async { + Navigator.of(context).pop(); + final result = await showDialog( barrierDismissible: false, context: context, @@ -148,4 +155,42 @@ class TagChipDisplay extends StatelessWidget { } return groupedTags; } + + List _createInitialSelectedProducts( + List? tags, List? subspaces) { + final Map productCounts = {}; + + // Count products in spaceModel tags + if (tags != null) { + for (var tag in tags) { + if (tag.product != null) { + productCounts[tag.product!] = (productCounts[tag.product!] ?? 0) + 1; + } + } + } + + // Count products in subspaces + if (subspaces != null) { + for (var subspace in subspaces) { + if (subspace.tags != null) { + for (var tag in subspace.tags!) { + if (tag.product != null) { + productCounts[tag.product!] = + (productCounts[tag.product!] ?? 0) + 1; + } + } + } + } + } + + // Create SelectedProduct instances + return productCounts.entries + .map((entry) => SelectedProduct( + productId: entry.key.uuid, + count: entry.value, + productName: entry.key.name ?? 'Unnamed', + product: entry.key, + )) + .toList(); + } } 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 021e5ac9..74f11194 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,6 +5,7 @@ import 'package:syncrow_web/pages/spaces_management/assign_tag_models/views/assi 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/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/tag_model/bloc/add_device_model_bloc.dart'; import 'package:syncrow_web/pages/spaces_management/tag_model/widgets/action_button_widget.dart'; import 'package:syncrow_web/pages/spaces_management/tag_model/widgets/scrollable_grid_view_widget.dart'; @@ -15,6 +16,7 @@ class AddDeviceTypeModelWidget extends StatelessWidget { final ValueChanged>? onProductsSelected; final List? initialSelectedProducts; final List? subspaces; + final List? spaceTagModels; final List? allTags; final String spaceName; @@ -25,8 +27,8 @@ class AddDeviceTypeModelWidget extends StatelessWidget { this.onProductsSelected, this.subspaces, this.allTags, - required this.spaceName - }); + this.spaceTagModels, + required this.spaceName}); @override Widget build(BuildContext context) { @@ -89,6 +91,9 @@ class AddDeviceTypeModelWidget extends StatelessWidget { addedProducts: currentState, allTags: allTags, spaceName: spaceName, + initialTags: generateInitialTags( + spaceTagModels: spaceTagModels, + subspaces: subspaces), ), ); } @@ -100,4 +105,29 @@ class AddDeviceTypeModelWidget extends StatelessWidget { ), )); } + + List generateInitialTags({ + List? spaceTagModels, + List? subspaces, + }) { + final List initialTags = []; + + if (spaceTagModels != null) { + initialTags.addAll(spaceTagModels); + } + + if (subspaces != null) { + for (var subspace in subspaces) { + if (subspace.tags != null) { + initialTags.addAll( + subspace.tags!.map( + (tag) => tag.copyWith(location: subspace.subspaceName), + ), + ); + } + } + } + + return initialTags; + } } 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 e05c6711..2a653dde 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 @@ -8,11 +8,13 @@ import 'package:syncrow_web/pages/spaces_management/tag_model/widgets/device_typ class ScrollableGridViewWidget extends StatelessWidget { final List? products; final int crossAxisCount; + final List? initialProductCounts; const ScrollableGridViewWidget({ super.key, required this.products, required this.crossAxisCount, + this.initialProductCounts, }); @override @@ -36,9 +38,13 @@ class ScrollableGridViewWidget extends StatelessWidget { itemCount: products?.length ?? 0, itemBuilder: (context, index) { final product = products![index]; + final initialProductCount = _findInitialProductCount(product); + return DeviceTypeTileWidget( product: product, - productCounts: productCounts, + productCounts: initialProductCount != null + ? [...productCounts, initialProductCount] + : productCounts, ); }, ); @@ -46,4 +52,21 @@ class ScrollableGridViewWidget extends StatelessWidget { ), ); } + + SelectedProduct? _findInitialProductCount(ProductModel product) { + // Check if the product exists in initialProductCounts + if (initialProductCounts == null) return null; + final matchingProduct = initialProductCounts!.firstWhere( + (selectedProduct) => selectedProduct.productId == product.uuid, + orElse: () => SelectedProduct( + productId: '', + count: 0, + productName: '', + product: null, + ), + ); + + // Check if the product was actually found + return matchingProduct.productId.isNotEmpty ? matchingProduct : null; + } } diff --git a/lib/services/api/http_service.dart b/lib/services/api/http_service.dart index b75f05cf..2ed3da42 100644 --- a/lib/services/api/http_service.dart +++ b/lib/services/api/http_service.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:dio/dio.dart'; import 'package:syncrow_web/services/api/http_interceptor.dart'; import 'package:syncrow_web/services/locator.dart'; @@ -42,22 +44,30 @@ class HTTPService { } } - Future post( - {required String path, - Map? queryParameters, - Options? options, - dynamic body, - bool showServerMessage = true, - required T Function(dynamic) expectedResponseModel}) async { + Future post({ + required String path, + Map? queryParameters, + Options? options, + dynamic body, + bool showServerMessage = true, + required T Function(dynamic) expectedResponseModel, + }) async { try { + final bodyString = body is Map || body is List + ? jsonEncode(body) + : body?.toString() ?? 'null'; + + print("POST Request: $path, Body: $bodyString, Query: $queryParameters"); final response = await client.post( path, data: body, queryParameters: queryParameters, options: options, ); + print("POST Response: ${response.data.toString()}"); return expectedResponseModel(response.data); } catch (error) { + print("POST Error: $error"); rethrow; } } diff --git a/lib/services/space_mana_api.dart b/lib/services/space_mana_api.dart index 333b715e..da70d46f 100644 --- a/lib/services/space_mana_api.dart +++ b/lib/services/space_mana_api.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart'; -import 'package:syncrow_web/pages/spaces_management/all_spaces/model/selected_product_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/services/api/http_service.dart'; diff --git a/lib/services/space_model_mang_api.dart b/lib/services/space_model_mang_api.dart index 762f9178..82ed097f 100644 --- a/lib/services/space_model_mang_api.dart +++ b/lib/services/space_model_mang_api.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.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/services/api/http_service.dart'; import 'package:syncrow_web/utils/constants/api_const.dart'; @@ -34,4 +35,23 @@ class SpaceModelManagementApi { return []; } } + + Future createSpaceModel( + CreateSpaceTemplateBodyModel spaceModel) async { + try { + final response = await HTTPService().post( + path: ApiEndpoints.createSpaceModel + .replaceAll('{projectId}', TempConst.projectId), + showServerMessage: true, + body: spaceModel.toJson(), + expectedResponseModel: (json) { + return SpaceTemplateModel.fromJson(json['data']); + }, + ); + return response; + } catch (e) { + debugPrint('Error creating community: $e'); + return null; + } + } } diff --git a/lib/utils/constants/api_const.dart b/lib/utils/constants/api_const.dart index 2fdca23a..ca4527fb 100644 --- a/lib/utils/constants/api_const.dart +++ b/lib/utils/constants/api_const.dart @@ -99,4 +99,5 @@ abstract class ApiEndpoints { //space model static const String listSpaceModels = '/projects/{projectId}/space-models'; + static const String createSpaceModel = '/projects/{projectId}/space-models'; }